--- - name: Calico | Install Wireguard packages package: name: "{{ item }}" state: present with_items: "{{ calico_wireguard_packages }}" register: calico_package_install until: calico_package_install is succeeded retries: 4 when: calico_wireguard_enabled - name: Calico | Copy calicoctl binary from download dir copy: src: "{{ downloads.calicoctl.dest }}" dest: "{{ bin_dir }}/calicoctl" mode: "0755" remote_src: yes - name: Calico | Create calico certs directory file: dest: "{{ calico_cert_dir }}" state: directory mode: "0750" owner: root group: root when: calico_datastore == "etcd" - name: Calico | Link etcd certificates for calico-node file: src: "{{ etcd_cert_dir }}/{{ item.s }}" dest: "{{ calico_cert_dir }}/{{ item.d }}" state: hard mode: "0640" force: yes with_items: - {s: "{{ kube_etcd_cacert_file }}", d: "ca_cert.crt"} - {s: "{{ kube_etcd_cert_file }}", d: "cert.crt"} - {s: "{{ kube_etcd_key_file }}", d: "key.pem"} when: calico_datastore == "etcd" - name: Calico | Generate typha certs include_tasks: typha_certs.yml when: - typha_secure - inventory_hostname == groups['kube_control_plane'][0] - name: Calico | Generate apiserver certs include_tasks: calico_apiserver_certs.yml when: - calico_apiserver_enabled - inventory_hostname == groups['kube_control_plane'][0] - name: Calico | Install calicoctl wrapper script template: src: "calicoctl.{{ calico_datastore }}.sh.j2" dest: "{{ bin_dir }}/calicoctl.sh" mode: "0755" owner: root group: root - name: Calico | wait for etcd uri: url: "{{ etcd_access_addresses.split(',') | first }}/health" validate_certs: no client_cert: "{{ calico_cert_dir }}/cert.crt" client_key: "{{ calico_cert_dir }}/key.pem" register: result until: result.status == 200 or result.status == 401 retries: 10 delay: 5 run_once: true when: calico_datastore == "etcd" - name: Calico | Check if calico network pool has already been configured # noqa risky-shell-pipe - grep will exit 1 if no match found shell: > {{ bin_dir }}/calicoctl.sh get ippool | grep -w "{{ calico_pool_cidr | default(kube_pods_subnet) }}" | wc -l args: executable: /bin/bash register: calico_conf retries: 4 until: calico_conf.rc == 0 delay: "{{ retry_stagger | random + 3 }}" changed_when: false when: - inventory_hostname == groups['kube_control_plane'][0] - name: Calico | Ensure that calico_pool_cidr is within kube_pods_subnet when defined assert: that: "[calico_pool_cidr] | ansible.utils.ipaddr(kube_pods_subnet) | length == 1" msg: "{{ calico_pool_cidr }} is not within or equal to {{ kube_pods_subnet }}" when: - inventory_hostname == groups['kube_control_plane'][0] - 'calico_conf.stdout == "0"' - calico_pool_cidr is defined - name: Calico | Check if calico IPv6 network pool has already been configured # noqa risky-shell-pipe - grep will exit 1 if no match found shell: > {{ bin_dir }}/calicoctl.sh get ippool | grep -w "{{ calico_pool_cidr_ipv6 | default(kube_pods_subnet_ipv6) }}" | wc -l args: executable: /bin/bash register: calico_conf_ipv6 retries: 4 until: calico_conf_ipv6.rc == 0 delay: "{{ retry_stagger | random + 3 }}" changed_when: false when: - inventory_hostname == groups['kube_control_plane'][0] - enable_dual_stack_networks - name: Calico | Ensure that calico_pool_cidr_ipv6 is within kube_pods_subnet_ipv6 when defined assert: that: "[calico_pool_cidr_ipv6] | ansible.utils.ipaddr(kube_pods_subnet_ipv6) | length == 1" msg: "{{ calico_pool_cidr_ipv6 }} is not within or equal to {{ kube_pods_subnet_ipv6 }}" when: - inventory_hostname == groups['kube_control_plane'][0] - calico_conf_ipv6.stdout is defined and calico_conf_ipv6.stdout == "0" - calico_pool_cidr_ipv6 is defined - enable_dual_stack_networks - name: Calico | kdd specific configuration when: - inventory_hostname in groups['kube_control_plane'] - calico_datastore == "kdd" block: - name: Calico | Check if extra directory is needed stat: path: "{{ local_release_dir }}/calico-{{ calico_version }}-kdd-crds/{{ 'kdd' if (calico_version is version('v3.22.3', '<')) else 'crd' }}" register: kdd_path - name: Calico | Set kdd path when calico < v3.22.3 set_fact: calico_kdd_path: "{{ local_release_dir }}/calico-{{ calico_version }}-kdd-crds{{ '/kdd' if kdd_path.stat.exists is defined and kdd_path.stat.exists }}" when: - calico_version is version('v3.22.3', '<') - name: Calico | Set kdd path when calico > v3.22.2 set_fact: calico_kdd_path: "{{ local_release_dir }}/calico-{{ calico_version }}-kdd-crds{{ '/crd' if kdd_path.stat.exists is defined and kdd_path.stat.exists }}" when: - calico_version is version('v3.22.2', '>') - name: Calico | Create calico manifests for kdd assemble: src: "{{ calico_kdd_path }}" dest: "{{ kube_config_dir }}/kdd-crds.yml" mode: "0644" delimiter: "---\n" regexp: ".*\\.yaml" remote_src: true - name: Calico | Create Calico Kubernetes datastore resources kube: kubectl: "{{ bin_dir }}/kubectl" filename: "{{ kube_config_dir }}/kdd-crds.yml" state: "latest" register: kubectl_result until: kubectl_result is succeeded retries: 5 when: - inventory_hostname == groups['kube_control_plane'][0] - name: Calico | Configure Felix when: - inventory_hostname == groups['kube_control_plane'][0] block: - name: Calico | Get existing FelixConfiguration command: "{{ bin_dir }}/calicoctl.sh get felixconfig default -o json" register: _felix_cmd ignore_errors: True changed_when: False - name: Calico | Set kubespray FelixConfiguration set_fact: _felix_config: > { "kind": "FelixConfiguration", "apiVersion": "projectcalico.org/v3", "metadata": { "name": "default", }, "spec": { "ipipEnabled": {{ calico_ipip_mode != 'Never' }}, "reportingInterval": "{{ calico_felix_reporting_interval }}", "bpfLogLevel": "{{ calico_bpf_log_level }}", "bpfEnabled": {{ calico_bpf_enabled | bool }}, "bpfExternalServiceMode": "{{ calico_bpf_service_mode }}", "wireguardEnabled": {{ calico_wireguard_enabled | bool }}, "logSeverityScreen": "{{ calico_felix_log_severity_screen }}", "vxlanEnabled": {{ calico_vxlan_mode != 'Never' }}, "featureDetectOverride": "{{ calico_feature_detect_override }}", "floatingIPs": "{{ calico_felix_floating_ips }}" } } - name: Calico | Process FelixConfiguration set_fact: _felix_config: "{{ _felix_cmd.stdout | from_json | combine(_felix_config, recursive=True) }}" when: - _felix_cmd is success - name: Calico | Configure calico FelixConfiguration command: cmd: "{{ bin_dir }}/calicoctl.sh apply -f -" stdin: "{{ _felix_config is string | ternary(_felix_config, _felix_config | to_json) }}" changed_when: False - name: Calico | Configure Calico IP Pool when: - inventory_hostname == groups['kube_control_plane'][0] block: - name: Calico | Get existing calico network pool command: "{{ bin_dir }}/calicoctl.sh get ippool {{ calico_pool_name }} -o json" register: _calico_pool_cmd ignore_errors: True changed_when: False - name: Calico | Set kubespray calico network pool set_fact: _calico_pool: > { "kind": "IPPool", "apiVersion": "projectcalico.org/v3", "metadata": { "name": "{{ calico_pool_name }}", }, "spec": { "blockSize": {{ calico_pool_blocksize }}, "cidr": "{{ calico_pool_cidr | default(kube_pods_subnet) }}", "ipipMode": "{{ calico_ipip_mode }}", "vxlanMode": "{{ calico_vxlan_mode }}", "natOutgoing": {{ nat_outgoing | default(false) }} } } - name: Calico | Process calico network pool when: - _calico_pool_cmd is success block: - name: Calico | Get current calico network pool blocksize set_fact: _calico_blocksize: > { "spec": { "blockSize": {{ (_calico_pool_cmd.stdout | from_json).spec.blockSize }} } } - name: Calico | Merge calico network pool set_fact: _calico_pool: "{{ _calico_pool_cmd.stdout | from_json | combine(_calico_pool, _calico_blocksize, recursive=True) }}" - name: Calico | Configure calico network pool command: cmd: "{{ bin_dir }}/calicoctl.sh apply -f -" stdin: "{{ _calico_pool is string | ternary(_calico_pool, _calico_pool | to_json) }}" changed_when: False - name: Calico | Configure Calico IPv6 Pool when: - inventory_hostname == groups['kube_control_plane'][0] - enable_dual_stack_networks | bool block: - name: Calico | Get existing calico ipv6 network pool command: "{{ bin_dir }}/calicoctl.sh get ippool {{ calico_pool_name }}-ipv6 -o json" register: _calico_pool_ipv6_cmd ignore_errors: True changed_when: False - name: Calico | Set kubespray calico network pool set_fact: _calico_pool_ipv6: > { "kind": "IPPool", "apiVersion": "projectcalico.org/v3", "metadata": { "name": "{{ calico_pool_name }}-ipv6", }, "spec": { "blockSize": {{ calico_pool_blocksize_ipv6 }}, "cidr": "{{ calico_pool_cidr_ipv6 | default(kube_pods_subnet_ipv6) }}", "ipipMode": "{{ calico_ipip_mode_ipv6 }}", "vxlanMode": "{{ calico_vxlan_mode_ipv6 }}", "natOutgoing": {{ nat_outgoing_ipv6 | default(false) }} } } - name: Calico | Process calico ipv6 network pool when: - _calico_pool_ipv6_cmd is success block: - name: Calico | Get current calico ipv6 network pool blocksize set_fact: _calico_blocksize_ipv6: > { "spec": { "blockSize": {{ (_calico_pool_ipv6_cmd.stdout | from_json).spec.blockSize }} } } - name: Calico | Merge calico ipv6 network pool set_fact: _calico_pool_ipv6: "{{ _calico_pool_ipv6_cmd.stdout | from_json | combine(_calico_pool_ipv6, _calico_blocksize_ipv6, recursive=True) }}" - name: Calico | Configure calico ipv6 network pool command: cmd: "{{ bin_dir }}/calicoctl.sh apply -f -" stdin: "{{ _calico_pool_ipv6 is string | ternary(_calico_pool_ipv6, _calico_pool_ipv6 | to_json) }}" changed_when: False - name: Populate Service External IPs set_fact: _service_external_ips: "{{ _service_external_ips | default([]) + [{'cidr': item}] }}" with_items: "{{ calico_advertise_service_external_ips }}" run_once: yes - name: Populate Service LoadBalancer IPs set_fact: _service_loadbalancer_ips: "{{ _service_loadbalancer_ips | default([]) + [{'cidr': item}] }}" with_items: "{{ calico_advertise_service_loadbalancer_ips }}" run_once: yes - name: "Determine nodeToNodeMesh needed state" set_fact: nodeToNodeMeshEnabled: "false" when: - peer_with_router | default(false) or peer_with_calico_rr | default(false) - inventory_hostname in groups['k8s_cluster'] run_once: yes - name: Calico | Configure Calico BGP when: - inventory_hostname == groups['kube_control_plane'][0] block: - name: Calico | Get existing BGP Configuration command: "{{ bin_dir }}/calicoctl.sh get bgpconfig default -o json" register: _bgp_config_cmd ignore_errors: True changed_when: False - name: Calico | Set kubespray BGP Configuration set_fact: # noqa: jinja[spacing] _bgp_config: > { "kind": "BGPConfiguration", "apiVersion": "projectcalico.org/v3", "metadata": { "name": "default", }, "spec": { "listenPort": {{ calico_bgp_listen_port }}, "logSeverityScreen": "Info", {% if not calico_no_global_as_num | default(false) %}"asNumber": {{ global_as_num }},{% endif %} "nodeToNodeMeshEnabled": {{ nodeToNodeMeshEnabled | default('true') }} , {% if calico_advertise_cluster_ips | default(false) %} "serviceClusterIPs": [{"cidr": "{{ kube_service_addresses }}" } {{ ',{"cidr":"' + kube_service_addresses_ipv6 + '"}' if enable_dual_stack_networks else '' }}],{% endif %} {% if calico_advertise_service_loadbalancer_ips | length > 0 %}"serviceLoadBalancerIPs": {{ _service_loadbalancer_ips }},{% endif %} "serviceExternalIPs": {{ _service_external_ips | default([]) }} } } - name: Calico | Process BGP Configuration set_fact: _bgp_config: "{{ _bgp_config_cmd.stdout | from_json | combine(_bgp_config, recursive=True) }}" when: - _bgp_config_cmd is success - name: Calico | Set up BGP Configuration command: cmd: "{{ bin_dir }}/calicoctl.sh apply -f -" stdin: "{{ _bgp_config is string | ternary(_bgp_config, _bgp_config | to_json) }}" changed_when: False - name: Calico | Create calico manifests template: src: "{{ item.file }}.j2" dest: "{{ kube_config_dir }}/{{ item.file }}" mode: "0644" with_items: - {name: calico-config, file: calico-config.yml, type: cm} - {name: calico-node, file: calico-node.yml, type: ds} - {name: calico, file: calico-node-sa.yml, type: sa} - {name: calico, file: calico-cr.yml, type: clusterrole} - {name: calico, file: calico-crb.yml, type: clusterrolebinding} - {name: kubernetes-services-endpoint, file: kubernetes-services-endpoint.yml, type: cm } register: calico_node_manifests when: - inventory_hostname in groups['kube_control_plane'] - rbac_enabled or item.type not in rbac_resources - name: Calico | Create calico manifests for typha template: src: "{{ item.file }}.j2" dest: "{{ kube_config_dir }}/{{ item.file }}" mode: "0644" with_items: - {name: calico, file: calico-typha.yml, type: typha} register: calico_node_typha_manifest when: - inventory_hostname in groups['kube_control_plane'] - typha_enabled - name: Calico | get calico apiserver caBundle command: "{{ bin_dir }}/kubectl get secret -n calico-apiserver calico-apiserver-certs -o jsonpath='{.data.apiserver\\.crt}'" changed_when: false register: calico_apiserver_cabundle when: - inventory_hostname == groups['kube_control_plane'][0] - calico_apiserver_enabled - name: Calico | set calico apiserver caBundle fact set_fact: calico_apiserver_cabundle: "{{ calico_apiserver_cabundle.stdout }}" when: - inventory_hostname == groups['kube_control_plane'][0] - calico_apiserver_enabled - name: Calico | Create calico manifests for apiserver template: src: "{{ item.file }}.j2" dest: "{{ kube_config_dir }}/{{ item.file }}" mode: "0644" with_items: - {name: calico, file: calico-apiserver.yml, type: calico-apiserver} register: calico_apiserver_manifest when: - inventory_hostname in groups['kube_control_plane'] - calico_apiserver_enabled - name: Start Calico resources kube: name: "{{ item.item.name }}" namespace: "kube-system" kubectl: "{{ bin_dir }}/kubectl" resource: "{{ item.item.type }}" filename: "{{ kube_config_dir }}/{{ item.item.file }}" state: "latest" with_items: - "{{ calico_node_manifests.results }}" - "{{ calico_node_typha_manifest.results }}" when: - inventory_hostname == groups['kube_control_plane'][0] - not item is skipped loop_control: label: "{{ item.item.file }}" - name: Start Calico apiserver resources kube: name: "{{ item.item.name }}" namespace: "calico-apiserver" kubectl: "{{ bin_dir }}/kubectl" resource: "{{ item.item.type }}" filename: "{{ kube_config_dir }}/{{ item.item.file }}" state: "latest" with_items: - "{{ calico_apiserver_manifest.results }}" when: - inventory_hostname == groups['kube_control_plane'][0] - not item is skipped loop_control: label: "{{ item.item.file }}" - name: Wait for calico kubeconfig to be created wait_for: path: /etc/cni/net.d/calico-kubeconfig timeout: "{{ calico_kubeconfig_wait_timeout }}" when: - inventory_hostname not in groups['kube_control_plane'] - calico_datastore == "kdd" - name: Calico | Create Calico ipam manifests template: src: "{{ item.file }}.j2" dest: "{{ kube_config_dir }}/{{ item.file }}" mode: "0644" with_items: - {name: calico, file: calico-ipamconfig.yml, type: ipam} when: - inventory_hostname in groups['kube_control_plane'] - calico_datastore == "kdd" - name: Calico | Create ipamconfig resources kube: kubectl: "{{ bin_dir }}/kubectl" filename: "{{ kube_config_dir }}/calico-ipamconfig.yml" state: "latest" register: resource_result until: resource_result is succeeded retries: 4 when: - inventory_hostname == groups['kube_control_plane'][0] - calico_datastore == "kdd" - name: Calico | Peer with Calico Route Reflector include_tasks: peer_with_calico_rr.yml when: - peer_with_calico_rr | default(false) - name: Calico | Peer with the router include_tasks: peer_with_router.yml when: - peer_with_router | default(false)