You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
15 KiB

  1. ---
  2. - name: Calico | Install Wireguard packages
  3. package:
  4. name: "{{ item }}"
  5. state: present
  6. with_items: "{{ calico_wireguard_packages }}"
  7. register: calico_package_install
  8. until: calico_package_install is succeeded
  9. retries: 4
  10. when: calico_wireguard_enabled
  11. - name: Calico | Copy calicoctl binary from download dir
  12. copy:
  13. src: "{{ local_release_dir }}/calicoctl"
  14. dest: "{{ bin_dir }}/calicoctl"
  15. mode: 0755
  16. remote_src: yes
  17. - name: Calico | Write Calico cni config
  18. template:
  19. src: "cni-calico.conflist.j2"
  20. dest: "/etc/cni/net.d/calico.conflist.template"
  21. owner: kube
  22. register: calico_conflist
  23. notify: reset_calico_cni
  24. - name: Calico | Create calico certs directory
  25. file:
  26. dest: "{{ calico_cert_dir }}"
  27. state: directory
  28. mode: 0750
  29. owner: root
  30. group: root
  31. when: calico_datastore == "etcd"
  32. - name: Calico | Link etcd certificates for calico-node
  33. file:
  34. src: "{{ etcd_cert_dir }}/{{ item.s }}"
  35. dest: "{{ calico_cert_dir }}/{{ item.d }}"
  36. state: hard
  37. mode: 0640
  38. force: yes
  39. with_items:
  40. - {s: "{{ kube_etcd_cacert_file }}", d: "ca_cert.crt"}
  41. - {s: "{{ kube_etcd_cert_file }}", d: "cert.crt"}
  42. - {s: "{{ kube_etcd_key_file }}", d: "key.pem"}
  43. when: calico_datastore == "etcd"
  44. - name: Calico | Generate typha certs
  45. include_tasks: typha_certs.yml
  46. when:
  47. - typha_secure
  48. - inventory_hostname == groups['kube_control_plane'][0]
  49. - name: Calico | Install calicoctl wrapper script
  50. template:
  51. src: "calicoctl.{{ calico_datastore }}.sh.j2"
  52. dest: "{{ bin_dir }}/calicoctl.sh"
  53. mode: 0755
  54. owner: root
  55. group: root
  56. - name: Calico | wait for etcd
  57. uri:
  58. url: "{{ etcd_access_addresses.split(',') | first }}/health"
  59. validate_certs: no
  60. client_cert: "{{ calico_cert_dir }}/cert.crt"
  61. client_key: "{{ calico_cert_dir }}/key.pem"
  62. register: result
  63. until: result.status == 200 or result.status == 401
  64. retries: 10
  65. delay: 5
  66. run_once: true
  67. when: calico_datastore == "etcd"
  68. - name: Calico | Check if calico network pool has already been configured
  69. # noqa 306 - grep will exit 1 if no match found
  70. shell: >
  71. {{ bin_dir }}/calicoctl.sh get ippool | grep -w "{{ calico_pool_cidr | default(kube_pods_subnet) }}" | wc -l
  72. args:
  73. executable: /bin/bash
  74. register: calico_conf
  75. retries: 4
  76. until: calico_conf.rc == 0
  77. delay: "{{ retry_stagger | random + 3 }}"
  78. changed_when: false
  79. when:
  80. - inventory_hostname == groups['kube_control_plane'][0]
  81. - name: Calico | Ensure that calico_pool_cidr is within kube_pods_subnet when defined
  82. assert:
  83. that: "[calico_pool_cidr] | ipaddr(kube_pods_subnet) | length == 1"
  84. msg: "{{ calico_pool_cidr }} is not within or equal to {{ kube_pods_subnet }}"
  85. when:
  86. - inventory_hostname == groups['kube_control_plane'][0]
  87. - 'calico_conf.stdout == "0"'
  88. - calico_pool_cidr is defined
  89. - name: Calico | Check if calico IPv6 network pool has already been configured
  90. # noqa 306 - grep will exit 1 if no match found
  91. shell: >
  92. {{ bin_dir }}/calicoctl.sh get ippool | grep -w "{{ calico_pool_cidr_ipv6 | default(kube_pods_subnet_ipv6) }}" | wc -l
  93. args:
  94. executable: /bin/bash
  95. register: calico_conf_ipv6
  96. retries: 4
  97. until: calico_conf_ipv6.rc == 0
  98. delay: "{{ retry_stagger | random + 3 }}"
  99. changed_when: false
  100. when:
  101. - inventory_hostname == groups['kube_control_plane'][0]
  102. - enable_dual_stack_networks
  103. - name: Calico | Ensure that calico_pool_cidr_ipv6 is within kube_pods_subnet_ipv6 when defined
  104. assert:
  105. that: "[calico_pool_cidr_ipv6] | ipaddr(kube_pods_subnet_ipv6) | length == 1"
  106. msg: "{{ calico_pool_cidr_ipv6 }} is not within or equal to {{ kube_pods_subnet_ipv6 }}"
  107. when:
  108. - inventory_hostname == groups['kube_control_plane'][0]
  109. - calico_conf_ipv6.stdout is defined and calico_conf_ipv6.stdout == "0"
  110. - calico_pool_cidr_ipv6 is defined
  111. - enable_dual_stack_networks
  112. - block:
  113. - name: Calico | Create calico manifests for kdd
  114. assemble:
  115. src: "{{ local_release_dir }}/calico-{{ calico_version }}-kdd-crds"
  116. dest: "{{ kube_config_dir }}/kdd-crds.yml"
  117. delimiter: "---\n"
  118. regexp: ".*\\.yaml"
  119. remote_src: true
  120. - name: Calico | Create Calico Kubernetes datastore resources
  121. kube:
  122. kubectl: "{{ bin_dir }}/kubectl"
  123. filename: "{{ kube_config_dir }}/kdd-crds.yml"
  124. state: "latest"
  125. when:
  126. - inventory_hostname == groups['kube_control_plane'][0]
  127. when:
  128. - inventory_hostname in groups['kube_control_plane']
  129. - calico_datastore == "kdd"
  130. - name: Calico | Configure calico FelixConfiguration
  131. command:
  132. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  133. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  134. vars:
  135. stdin: >
  136. { "kind": "FelixConfiguration",
  137. "apiVersion": "projectcalico.org/v3",
  138. "metadata": {
  139. "name": "default",
  140. },
  141. "spec": {
  142. "ipipEnabled": {{ calico_ipip_mode != 'Never' | bool }},
  143. "reportingInterval": "{{ calico_felix_reporting_interval }}",
  144. "bpfLogLevel": "{{ calico_bpf_log_level }}",
  145. "bpfEnabled": {{ calico_bpf_enabled | bool }},
  146. "bpfExternalServiceMode": "{{ calico_bpf_service_mode }}",
  147. "wireguardEnabled": {{ calico_wireguard_enabled | bool }},
  148. "logSeverityScreen": "{{ calico_felix_log_severity_screen }}" }}
  149. when:
  150. - inventory_hostname == groups['kube_control_plane'][0]
  151. - name: Calico | Configure calico network pool
  152. command:
  153. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  154. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  155. vars:
  156. stdin: >
  157. { "kind": "IPPool",
  158. "apiVersion": "projectcalico.org/v3",
  159. "metadata": {
  160. "name": "{{ calico_pool_name }}",
  161. },
  162. "spec": {
  163. "blockSize": {{ calico_pool_blocksize | default(kube_network_node_prefix) }},
  164. "cidr": "{{ calico_pool_cidr | default(kube_pods_subnet) }}",
  165. "ipipMode": "{{ calico_ipip_mode }}",
  166. "vxlanMode": "{{ calico_vxlan_mode }}",
  167. "natOutgoing": {{ nat_outgoing|default(false) and not peer_with_router|default(false) }} }}
  168. when:
  169. - inventory_hostname == groups['kube_control_plane'][0]
  170. - 'calico_conf.stdout == "0"'
  171. - name: Calico | Configure calico ipv6 network pool (version >= v3.3.0)
  172. command:
  173. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  174. stdin: >
  175. { "kind": "IPPool",
  176. "apiVersion": "projectcalico.org/v3",
  177. "metadata": {
  178. "name": "{{ calico_pool_name }}-ipv6",
  179. },
  180. "spec": {
  181. "blockSize": {{ calico_pool_blocksize_ipv6 | default(kube_network_node_prefix_ipv6) }},
  182. "cidr": "{{ calico_pool_cidr_ipv6 | default(kube_pods_subnet_ipv6) }}",
  183. "ipipMode": "{{ calico_ipip_mode_ipv6 }}",
  184. "vxlanMode": "{{ calico_vxlan_mode_ipv6 }}",
  185. "natOutgoing": {{ nat_outgoing_ipv6|default(false) and not peer_with_router_ipv6|default(false) }} }}
  186. when:
  187. - inventory_hostname == groups['kube_control_plane'][0]
  188. - calico_conf_ipv6.stdout is defined and calico_conf_ipv6.stdout == "0"
  189. - enable_dual_stack_networks | bool
  190. - name: Populate Service External IPs
  191. set_fact:
  192. _service_external_ips: "{{ _service_external_ips|default([]) + [ {'cidr': item} ] }}"
  193. with_items: "{{ calico_advertise_service_external_ips }}"
  194. run_once: yes
  195. - name: Populate Service LoadBalancer IPs
  196. set_fact:
  197. _service_loadbalancer_ips: "{{ _service_loadbalancer_ips|default([]) + [ {'cidr': item} ] }}"
  198. with_items: "{{ calico_advertise_service_loadbalancer_ips }}"
  199. run_once: yes
  200. - name: "Determine nodeToNodeMesh needed state"
  201. set_fact:
  202. nodeToNodeMeshEnabled: "false"
  203. when:
  204. - peer_with_router|default(false) or peer_with_calico_rr|default(false)
  205. - inventory_hostname in groups['k8s_cluster']
  206. run_once: yes
  207. - name: Calico | Set up BGP Configuration
  208. command:
  209. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  210. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  211. vars:
  212. stdin: >
  213. { "kind": "BGPConfiguration",
  214. "apiVersion": "projectcalico.org/v3",
  215. "metadata": {
  216. "name": "default",
  217. },
  218. "spec": {
  219. "listenPort": {{ calico_bgp_listen_port }},
  220. "logSeverityScreen": "Info",
  221. {% if not calico_no_global_as_num|default(false) %}"asNumber": {{ global_as_num }},{% endif %}
  222. "nodeToNodeMeshEnabled": {{ nodeToNodeMeshEnabled|default('true') }} ,
  223. {% if calico_advertise_cluster_ips|default(false) %}"serviceClusterIPs": [{"cidr": "{{ kube_service_addresses }}" }],{% endif %}
  224. {% if calico_version is version('v3.18.0', '>') and calico_advertise_service_loadbalancer_ips|length > 0 %}"serviceLoadBalancerIPs": {{ _service_loadbalancer_ips }},{% endif %}
  225. "serviceExternalIPs": {{ _service_external_ips|default([]) }} }}
  226. changed_when: false
  227. when:
  228. - inventory_hostname == groups['kube_control_plane'][0]
  229. - name: Calico | Configure peering with router(s) at global scope
  230. command:
  231. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  232. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  233. vars:
  234. stdin: >
  235. {"apiVersion": "projectcalico.org/v3",
  236. "kind": "BGPPeer",
  237. "metadata": {
  238. "name": "global-{{ item.name | default(item.router_id|replace(':','-')) }}"
  239. },
  240. "spec": {
  241. "asNumber": "{{ item.as }}",
  242. "peerIP": "{{ item.router_id }}"
  243. }}
  244. register: output
  245. retries: 4
  246. until: output.rc == 0
  247. delay: "{{ retry_stagger | random + 3 }}"
  248. with_items:
  249. - "{{ peers|selectattr('scope','defined')|selectattr('scope','equalto', 'global')|list|default([]) }}"
  250. when:
  251. - inventory_hostname == groups['kube_control_plane'][0]
  252. - peer_with_router|default(false)
  253. - name: Calico | Configure peering with route reflectors at global scope
  254. command:
  255. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  256. # revert when it's already a string
  257. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  258. vars:
  259. stdin: >
  260. {"apiVersion": "projectcalico.org/v3",
  261. "kind": "BGPPeer",
  262. "metadata": {
  263. "name": "peer-to-rrs"
  264. },
  265. "spec": {
  266. "nodeSelector": "!has(i-am-a-route-reflector)",
  267. "peerSelector": "has(i-am-a-route-reflector)"
  268. }}
  269. register: output
  270. retries: 4
  271. until: output.rc == 0
  272. delay: "{{ retry_stagger | random + 3 }}"
  273. with_items:
  274. - "{{ groups['calico_rr'] | default([]) }}"
  275. when:
  276. - inventory_hostname == groups['kube_control_plane'][0]
  277. - peer_with_calico_rr|default(false)
  278. - name: Calico | Configure route reflectors to peer with each other
  279. command:
  280. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  281. # revert when it's already a string
  282. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  283. vars:
  284. stdin: >
  285. {"apiVersion": "projectcalico.org/v3",
  286. "kind": "BGPPeer",
  287. "metadata": {
  288. "name": "rr-mesh"
  289. },
  290. "spec": {
  291. "nodeSelector": "has(i-am-a-route-reflector)",
  292. "peerSelector": "has(i-am-a-route-reflector)"
  293. }}
  294. register: output
  295. retries: 4
  296. until: output.rc == 0
  297. delay: "{{ retry_stagger | random + 3 }}"
  298. with_items:
  299. - "{{ groups['calico_rr'] | default([]) }}"
  300. when:
  301. - inventory_hostname == groups['kube_control_plane'][0]
  302. - peer_with_calico_rr|default(false)
  303. - name: Calico | Create calico manifests
  304. template:
  305. src: "{{ item.file }}.j2"
  306. dest: "{{ kube_config_dir }}/{{ item.file }}"
  307. with_items:
  308. - {name: calico-config, file: calico-config.yml, type: cm}
  309. - {name: calico-node, file: calico-node.yml, type: ds}
  310. - {name: calico, file: calico-node-sa.yml, type: sa}
  311. - {name: calico, file: calico-cr.yml, type: clusterrole}
  312. - {name: calico, file: calico-crb.yml, type: clusterrolebinding}
  313. - {name: kubernetes-services-endpoint, file: kubernetes-services-endpoint.yml, type: cm }
  314. register: calico_node_manifests
  315. when:
  316. - inventory_hostname in groups['kube_control_plane']
  317. - rbac_enabled or item.type not in rbac_resources
  318. - name: Calico | Create calico manifests for typha
  319. template:
  320. src: "{{ item.file }}.j2"
  321. dest: "{{ kube_config_dir }}/{{ item.file }}"
  322. with_items:
  323. - {name: calico, file: calico-typha.yml, type: typha}
  324. register: calico_node_typha_manifest
  325. when:
  326. - inventory_hostname in groups['kube_control_plane']
  327. - typha_enabled and calico_datastore == "kdd"
  328. - name: Start Calico resources
  329. kube:
  330. name: "{{ item.item.name }}"
  331. namespace: "kube-system"
  332. kubectl: "{{ bin_dir }}/kubectl"
  333. resource: "{{ item.item.type }}"
  334. filename: "{{ kube_config_dir }}/{{ item.item.file }}"
  335. state: "latest"
  336. with_items:
  337. - "{{ calico_node_manifests.results }}"
  338. - "{{ calico_node_typha_manifest.results }}"
  339. when:
  340. - inventory_hostname == groups['kube_control_plane'][0]
  341. - not item is skipped
  342. loop_control:
  343. label: "{{ item.item.file }}"
  344. - name: Wait for calico kubeconfig to be created
  345. wait_for:
  346. path: /etc/cni/net.d/calico-kubeconfig
  347. when:
  348. - inventory_hostname not in groups['kube_control_plane']
  349. - calico_datastore == "kdd"
  350. - name: Calico | Configure node asNumber for per node peering
  351. command:
  352. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  353. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  354. vars:
  355. stdin: >
  356. {"apiVersion": "projectcalico.org/v3",
  357. "kind": "Node",
  358. "metadata": {
  359. "name": "{{ inventory_hostname }}"
  360. },
  361. "spec": {
  362. "bgp": {
  363. "asNumber": "{{ local_as }}"
  364. },
  365. "orchRefs":[{"nodeName":"{{ inventory_hostname }}","orchestrator":"k8s"}]
  366. }}
  367. register: output
  368. retries: 4
  369. until: output.rc == 0
  370. delay: "{{ retry_stagger | random + 3 }}"
  371. when:
  372. - peer_with_router|default(false)
  373. - inventory_hostname in groups['k8s_cluster']
  374. - local_as is defined
  375. - groups['calico_rr'] | default([]) | length == 0
  376. - name: Calico | Configure peering with router(s) at node scope
  377. command:
  378. cmd: "{{ bin_dir }}/calicoctl.sh apply -f -"
  379. stdin: "{{ stdin is string | ternary(stdin, stdin|to_json) }}"
  380. vars:
  381. stdin: >
  382. {"apiVersion": "projectcalico.org/v3",
  383. "kind": "BGPPeer",
  384. "metadata": {
  385. "name": "{{ inventory_hostname }}-{{ item.name | default(item.router_id|replace(':','-')) }}"
  386. },
  387. "spec": {
  388. "asNumber": "{{ item.as }}",
  389. "node": "{{ inventory_hostname }}",
  390. "peerIP": "{{ item.router_id }}"
  391. }}
  392. register: output
  393. retries: 4
  394. until: output.rc == 0
  395. delay: "{{ retry_stagger | random + 3 }}"
  396. with_items:
  397. - "{{ peers|selectattr('scope','undefined')|list|default([]) | union(peers|selectattr('scope','defined')|selectattr('scope','equalto', 'node')|list|default([])) }}"
  398. when:
  399. - peer_with_router|default(false)
  400. - inventory_hostname in groups['k8s_cluster']