--- - name: Require Flatcar Linux ansible.builtin.assert: that: - flatcar_os_release.stdout is search('ID=flatcar') fail_msg: This role is for Flatcar Linux. Use bootstrap-k3s.yml for K3s hosts. - name: Read host architecture ansible.builtin.raw: uname -m register: host_architecture changed_when: false - name: Validate x86-64 host architecture ansible.builtin.assert: that: - host_architecture.stdout | trim in ['x86_64', 'amd64'] - tool_architecture == 'amd64' fail_msg: This profile currently pins x86-64 binaries. - name: Ensure Docker is enabled and running ansible.builtin.raw: systemctl enable --now docker changed_when: false - name: Create Flatcar k3d directories ansible.builtin.raw: >- install -d -m 0755 -o {{ k3d_user }} -g {{ k3d_group }} {{ k3d_tool_dir }} {{ k3d_workspace }} /home/core/.kube - name: Install pinned k3d ansible.builtin.raw: >- if [ ! -x {{ k3d_tool_dir }}/k3d ] || [ ! -f {{ k3d_tool_dir }}/.k3d-{{ k3d_version }} ]; then curl --fail --location --silent --show-error https://github.com/k3d-io/k3d/releases/download/v{{ k3d_version }}/k3d-linux-{{ tool_architecture }} --output {{ k3d_tool_dir }}/k3d && chmod 0755 {{ k3d_tool_dir }}/k3d && touch {{ k3d_tool_dir }}/.k3d-{{ k3d_version }}; fi - name: Install pinned kubectl ansible.builtin.raw: >- if [ ! -x {{ k3d_tool_dir }}/kubectl ] || [ ! -f {{ k3d_tool_dir }}/.kubectl-{{ kubectl_version }} ]; then curl --fail --location --silent --show-error https://dl.k8s.io/release/{{ kubectl_version }}/bin/linux/{{ tool_architecture }}/kubectl --output {{ k3d_tool_dir }}/kubectl && chmod 0755 {{ k3d_tool_dir }}/kubectl && touch {{ k3d_tool_dir }}/.kubectl-{{ kubectl_version }}; fi - name: Download and install pinned Helm ansible.builtin.raw: >- if [ ! -x {{ k3d_tool_dir }}/helm ] || [ ! -f {{ k3d_tool_dir }}/.helm-{{ helm_version }} ]; then curl --fail --location --silent --show-error https://get.helm.sh/helm-{{ helm_version }}-linux-{{ tool_architecture }}.tar.gz --output /tmp/flatcar-k3d-helm.tar.gz && tar -xzf /tmp/flatcar-k3d-helm.tar.gz -C /tmp && install -m 0755 /tmp/linux-amd64/helm {{ k3d_tool_dir }}/helm && touch {{ k3d_tool_dir }}/.helm-{{ helm_version }}; fi - name: Configure core shell PATH ansible.builtin.raw: >- grep -Fxq 'export PATH="{{ k3d_tool_dir }}:$HOME/bin:$PATH"' /home/core/.profile || printf '%s\n' 'export PATH="{{ k3d_tool_dir }}:$HOME/bin:$PATH"' 'export KUBECONFIG="$HOME/.kube/config"' >> /home/core/.profile && chown core:core /home/core/.profile && chmod 0644 /home/core/.profile - name: Copy repository from the Ansible controller ansible.posix.synchronize: src: "{{ bootstrap_repo_source }}/" dest: "{{ k3d_workspace }}/" archive: true delete: false rsync_opts: - "--exclude=.git" - "--exclude=artifacts" delegate_to: localhost become: false when: bootstrap_repo_url | length == 0 - name: Install temporary repository deploy key ansible.builtin.raw: >- printf '%s' '{{ bootstrap_repo_ssh_private_key | b64encode }}' | base64 -d > {{ bootstrap_repo_ssh_private_key_path }} && chmod 0600 {{ bootstrap_repo_ssh_private_key_path }} no_log: true when: - bootstrap_repo_url | length > 0 - bootstrap_repo_ssh_private_key | length > 0 - name: Clone or update the repository on the host ansible.builtin.raw: >- if [ -d {{ k3d_workspace }}/.git ]; then git -C {{ k3d_workspace }} fetch --prune origin {{ bootstrap_repo_ref }} && git -C {{ k3d_workspace }} checkout {{ bootstrap_repo_ref }} && git -C {{ k3d_workspace }} reset --hard origin/{{ bootstrap_repo_ref }}; else GIT_SSH_COMMAND="ssh -i {{ bootstrap_repo_ssh_private_key_path }} -o StrictHostKeyChecking=accept-new" git clone --branch {{ bootstrap_repo_ref }} {{ bootstrap_repo_url }} {{ k3d_workspace }}; fi no_log: "{{ bootstrap_repo_ssh_private_key | length > 0 }}" when: bootstrap_repo_url | length > 0 - name: Remove temporary repository deploy key ansible.builtin.raw: rm -f {{ bootstrap_repo_ssh_private_key_path }} when: - bootstrap_repo_url | length > 0 - bootstrap_repo_ssh_private_key | length > 0 - name: Check whether the k3d cluster already exists ansible.builtin.raw: "{{ k3d_tool_dir }}/k3d cluster list" register: k3d_cluster_list changed_when: false - name: Configure the Cilium profile API certificate SAN ansible.builtin.raw: >- sed -i -e 's/K3D_EXTERNAL_API_SERVER_IP/{{ kubeconfig_server_host }}/g' -e 's/K3D_INTERNAL_API_SERVER_IP/{{ cilium_k8s_service_host }}/g' {{ k3d_workspace }}/local-quickstart/{{ k3d_config_source | basename }} when: - cilium_enabled | bool - cilium_k8s_service_host | default('') | length > 0 - k3d_cluster_name not in k3d_cluster_list.stdout - name: Create the k3d cluster ansible.builtin.raw: >- {{ k3d_tool_dir }}/k3d cluster create --config {{ k3d_workspace }}/local-quickstart/{{ k3d_config_source | basename }} --wait --timeout 180s become_user: "{{ k3d_user }}" when: k3d_cluster_name not in k3d_cluster_list.stdout - name: Write the cluster kubeconfig for the core user ansible.builtin.raw: >- {{ k3d_tool_dir }}/k3d kubeconfig get {{ k3d_cluster_name }} > /home/core/.kube/config && chmod 0600 /home/core/.kube/config become_user: "{{ k3d_user }}" - name: Verify Kubernetes nodes are Ready for the standard profile ansible.builtin.raw: "{{ k3d_tool_dir }}/kubectl get nodes --no-headers" become_user: "{{ k3d_user }}" register: k3d_nodes changed_when: false when: not (cilium_enabled | bool) retries: 12 delay: 10 until: - k3d_nodes.rc == 0 - k3d_nodes.stdout is search(' Ready ') - name: Verify Kubernetes API and node objects for the Cilium profile ansible.builtin.raw: "{{ k3d_tool_dir }}/kubectl get nodes --no-headers" become_user: "{{ k3d_user }}" register: k3d_nodes_cilium changed_when: false when: cilium_enabled | bool retries: 12 delay: 10 until: - k3d_nodes_cilium.rc == 0 - k3d_nodes_cilium.stdout | trim | length > 0 - name: Configure reachable upstream DNS servers for CoreDNS ansible.builtin.raw: >- {{ k3d_tool_dir }}/kubectl -n kube-system create configmap coredns-custom --from-literal=upstream.override='forward . {{ (k3d_dns_servers | string | from_yaml) | join(' ') }}' --dry-run=client -o yaml | {{ k3d_tool_dir }}/kubectl apply -f - become_user: "{{ k3d_user }}" when: k3d_dns_servers | length > 0 - name: Restart CoreDNS after changing upstream resolvers ansible.builtin.raw: >- {{ k3d_tool_dir }}/kubectl -n kube-system rollout restart deployment/coredns && {{ k3d_tool_dir }}/kubectl -n kube-system rollout status deployment/coredns --timeout=120s become_user: "{{ k3d_user }}" when: k3d_dns_servers | length > 0 - name: Ensure local kubeconfig artifact directory exists ansible.builtin.file: path: "{{ kubeconfig_artifact_dir }}" state: directory mode: '0700' delegate_to: localhost become: false run_once: true when: kubeconfig_fetch_enabled | bool - name: Fetch kubeconfig artifact to the Ansible controller ansible.posix.synchronize: src: /home/core/.kube/config dest: "{{ kubeconfig_artifact_dir }}/{{ inventory_hostname }}-kubeconfig" mode: pull archive: true rsync_opts: - "--checksum" delegate_to: localhost become: false when: kubeconfig_fetch_enabled | bool - name: Replace the k3d wildcard API address in the local artifact ansible.builtin.replace: path: "{{ kubeconfig_artifact_dir }}/{{ inventory_hostname }}-kubeconfig" regexp: '(?m)^(\s+server:\s+https://)0\.0\.0\.0(:[0-9]+\s*)$' replace: '\g<1>{{ kubeconfig_server_host }}\g<2>' delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Read the rewritten local kubeconfig server endpoint ansible.builtin.command: cmd: >- kubectl config view --kubeconfig {{ kubeconfig_artifact_dir }}/{{ inventory_hostname }}-kubeconfig --minify -o jsonpath={.clusters[0].cluster.server} register: rewritten_kubeconfig_server changed_when: false delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Require a reachable host address in the local kubeconfig artifact ansible.builtin.assert: that: - rewritten_kubeconfig_server.stdout | trim is match('^https://' ~ (kubeconfig_server_host | regex_escape) ~ ':[0-9]+$') - rewritten_kubeconfig_server.stdout | trim is not search('0\.0\.0\.0') fail_msg: >- The fetched kubeconfig still points to an unusable API address: {{ rewritten_kubeconfig_server.stdout | trim }} delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Ensure the default kubeconfig directory exists ansible.builtin.file: path: "{{ kubeconfig_default_path | dirname }}" state: directory mode: '0700' delegate_to: localhost become: false run_once: true when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Merge the fetched kubeconfig into the operator default ansible.builtin.command: cmd: kubectl config view --flatten environment: # Put the freshly fetched artifact first so it overrides an older entry # with the same cluster and context name. KUBECONFIG: "{{ kubeconfig_artifact_dir }}/{{ inventory_hostname }}-kubeconfig:{{ kubeconfig_default_path }}" register: merged_kubeconfig changed_when: false delegate_to: localhost become: false no_log: true when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Install the merged kubeconfig as the operator default ansible.builtin.copy: content: "{{ merged_kubeconfig.stdout }}" dest: "{{ kubeconfig_default_path }}" mode: '0600' delegate_to: localhost become: false no_log: true when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Select the bootstrapped cluster context ansible.builtin.command: cmd: kubectl config use-context {{ kubeconfig_context_name }} --kubeconfig {{ kubeconfig_default_path }} register: selected_kubeconfig_context changed_when: false delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Verify the selected kubeconfig context ansible.builtin.command: cmd: kubectl config current-context --kubeconfig {{ kubeconfig_default_path }} register: selected_kubeconfig_context_check changed_when: false delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool - name: Require the expected bootstrapped context to be current ansible.builtin.assert: that: - selected_kubeconfig_context_check.stdout | trim == kubeconfig_context_name fail_msg: >- The default kubeconfig context was not changed to {{ kubeconfig_context_name }}. delegate_to: localhost become: false when: - kubeconfig_fetch_enabled | bool - kubeconfig_import_enabled | bool