diff --git a/api/core/v1alpha1/task_types.go b/api/core/v1alpha1/task_types.go index 3b4e96de..2896699a 100644 --- a/api/core/v1alpha1/task_types.go +++ b/api/core/v1alpha1/task_types.go @@ -77,6 +77,7 @@ type TaskHostResult struct { Host string `json:"host,omitempty"` Stdout string `json:"stdout,omitempty"` StdErr string `json:"stdErr,omitempty"` + Error string `json:"error,omitempty"` } // +genclient diff --git a/builtin/capkk/roles/install/cni/tasks/calico.yaml b/builtin/capkk/roles/install/cni/tasks/calico.yaml index f353b546..82bfb058 100644 --- a/builtin/capkk/roles/install/cni/tasks/calico.yaml +++ b/builtin/capkk/roles/install/cni/tasks/calico.yaml @@ -5,7 +5,7 @@ register: calicoctl_install_version register_type: yaml - name: Install calicoctl - when: .calicoctl_install_version.stderr | empty | not + when: .calicoctl_install_version.error | empty | not block: - name: Sync calicoctl to remote copy: @@ -29,4 +29,4 @@ - name: Apply calico command: | - helm install --create-namespace --namespace tigera-operator calico /etc/kubernetes/cni/tigera-operator-{{ .calico_version }}.tgz -f /etc/kubernetes/cni/calico-values.yaml + helm upgrade --install --create-namespace --namespace tigera-operator calico /etc/kubernetes/cni/tigera-operator-{{ .calico_version }}.tgz -f /etc/kubernetes/cni/calico-values.yaml diff --git a/builtin/capkk/roles/install/cni/tasks/cilium.yaml b/builtin/capkk/roles/install/cni/tasks/cilium.yaml index 74667b11..31bdb4ea 100644 --- a/builtin/capkk/roles/install/cni/tasks/cilium.yaml +++ b/builtin/capkk/roles/install/cni/tasks/cilium.yaml @@ -22,4 +22,4 @@ # https://docs.cilium.io/en/stable/installation/k8s-install-helm/ - name: Install cilium command: | - helm install --namespace kube-system cilium /etc/kubernetes/cni/cilium-{{ .cilium_version }}.tgz -f /etc/kubernetes/cni/cilium-values.yaml + helm upgrade --install --namespace kube-system cilium /etc/kubernetes/cni/cilium-{{ .cilium_version }}.tgz -f /etc/kubernetes/cni/cilium-values.yaml diff --git a/builtin/capkk/roles/install/cni/tasks/flannel.yaml b/builtin/capkk/roles/install/cni/tasks/flannel.yaml index 438f0ce7..9e11e75e 100644 --- a/builtin/capkk/roles/install/cni/tasks/flannel.yaml +++ b/builtin/capkk/roles/install/cni/tasks/flannel.yaml @@ -14,4 +14,4 @@ - name: Apply flannel command: | - helm install --create-namespace --namespace kube-flannel flannel /etc/kubernetes/cni/flannel.tgz -f /etc/kubernetes/cni/flannel-values.yaml + helm upgrade --install --create-namespace --namespace kube-flannel flannel /etc/kubernetes/cni/flannel.tgz -f /etc/kubernetes/cni/flannel-values.yaml diff --git a/builtin/capkk/roles/install/cri/tasks/install_containerd.yaml b/builtin/capkk/roles/install/cri/tasks/install_containerd.yaml index 99693f2a..6f822f1f 100644 --- a/builtin/capkk/roles/install/cri/tasks/install_containerd.yaml +++ b/builtin/capkk/roles/install/cri/tasks/install_containerd.yaml @@ -4,7 +4,7 @@ command: runc --version register: runc_install_version - name: Sync runc binary to remote - when: or (.runc_install_version.stderr | empty | not) (.runc_install_version.stdout | contains (printf "runc version %s\n" (.runc_version | default "" | trimPrefix "v" )) | not) + when: or (.runc_install_version.error | empty | not) (.runc_install_version.stdout | contains (printf "runc version %s\n" (.runc_version | default "" | trimPrefix "v" )) | not) copy: src: >- {{ .binary_dir }}/runc/{{ .runc_version }}/{{ .binary_type }}/runc.{{ .binary_type }} @@ -16,7 +16,7 @@ command: containerd --version register: containerd_install_version - name: Install containerd - when: or (.containerd_install_version.stderr | empty | not) (.containerd_install_version.stdout | contains (printf " %s " .containerd_version) | not) + when: or (.containerd_install_version.error | empty | not) (.containerd_install_version.stdout | contains (printf " %s " .containerd_version) | not) block: - name: Sync containerd binary to remote copy: diff --git a/builtin/capkk/roles/install/cri/tasks/install_crictl.yaml b/builtin/capkk/roles/install/cri/tasks/install_crictl.yaml index e60aa231..36b6f27a 100644 --- a/builtin/capkk/roles/install/cri/tasks/install_crictl.yaml +++ b/builtin/capkk/roles/install/cri/tasks/install_crictl.yaml @@ -5,7 +5,7 @@ register: crictl_install_version - name: Install crictl - when: or (.crictl_install_version.stderr | empty | not) (.crictl_install_version.stdout | ne (printf "crictl version %s" .crictl_version)) + when: or (.crictl_install_version.error | empty | not) (.crictl_install_version.stdout | ne (printf "crictl version %s" .crictl_version)) block: - name: Sync crictl binary to remote copy: diff --git a/builtin/capkk/roles/install/cri/tasks/install_cridockerd.yaml b/builtin/capkk/roles/install/cri/tasks/install_cridockerd.yaml index 1824b363..b50777aa 100644 --- a/builtin/capkk/roles/install/cri/tasks/install_cridockerd.yaml +++ b/builtin/capkk/roles/install/cri/tasks/install_cridockerd.yaml @@ -5,7 +5,7 @@ register: cridockerd_install_version - name: Install cri-dockerd - when: or (.cridockerd_install_version.stderr | empty | not) (.cridockerd_install_version.stdout | hasPrefix (printf "cri-dockerd %s " .cridockerd_version) | not) + when: or (.cridockerd_install_version.error | empty | not) (.cridockerd_install_version.stdout | hasPrefix (printf "cri-dockerd %s " .cridockerd_version) | not) block: - name: Sync cri-dockerd Binary to remote copy: diff --git a/builtin/capkk/roles/install/cri/tasks/install_docker.yaml b/builtin/capkk/roles/install/cri/tasks/install_docker.yaml index 08528ddf..b1907c90 100644 --- a/builtin/capkk/roles/install/cri/tasks/install_docker.yaml +++ b/builtin/capkk/roles/install/cri/tasks/install_docker.yaml @@ -5,7 +5,7 @@ register: docker_install_version - name: Install docker - when: or (.docker_install_version.stderr | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) + when: or (.docker_install_version.error | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) block: - name: Sync docker binary to remote copy: diff --git a/builtin/capkk/roles/install/kubernetes/tasks/main.yaml b/builtin/capkk/roles/install/kubernetes/tasks/main.yaml index 53203a6f..a7a2e1e5 100644 --- a/builtin/capkk/roles/install/kubernetes/tasks/main.yaml +++ b/builtin/capkk/roles/install/kubernetes/tasks/main.yaml @@ -1,10 +1,10 @@ --- - name: Check if helm is installed ignore_errors: true - command: helm version + command: helm version --template "{{ .Version }}" register: helm_install_version - name: Install helm - when: or (.helm_install_version.stderr | empty | not) (.helm_install_version.stdout | contains (printf "Version:\"%s\"" .helm_version) | not) + when: or (.helm_install_version.error | empty | not) (.helm_install_version.stdout | ne .helm_version) block: - name: Sync helm to remote copy: @@ -21,7 +21,7 @@ command: kubeadm version -o short register: kubeadm_install_version - name: Install kubeadm - when: or (.kubeadm_install_version.stderr | empty | not) (.kubeadm_install_version.stdout | ne .kube_version) + when: or (.kubeadm_install_version.error | empty | not) (.kubeadm_install_version.stdout | ne .kube_version) copy: src: >- {{ .binary_dir }}/kube/{{ .kube_version }}/{{ .binary_type }}/kubeadm @@ -35,7 +35,7 @@ register_type: yaml - name: Sync kubectl to remote when: | - or (.kubectl_install_version.stderr | empty | not) ((get .kubectl_install_version.stdout "Server Version") | ne .kube_version) + or (.kubectl_install_version.error | empty | not) ((get .kubectl_install_version.stdout "Server Version") | ne .kube_version) copy: src: >- {{ .binary_dir }}/kube/{{ .kube_version }}/{{ .binary_type }}/kubectl @@ -47,7 +47,7 @@ command: kubelet --version register: kubelet_install_version - name: Install kubelet - when: or (.kubelet_install_version.stderr | empty | not) (.kubelet_install_version.stdout | ne (printf "Kubernetes %s" .kube_version)) + when: or (.kubelet_install_version.error | empty | not) (.kubelet_install_version.stdout | ne (printf "Kubernetes %s" .kube_version)) block: - name: Sync kubelet to remote copy: diff --git a/builtin/capkk/roles/precheck/env_check/tasks/kubernetes.yaml b/builtin/capkk/roles/precheck/env_check/tasks/kubernetes.yaml index 1b0cfae4..849d925f 100644 --- a/builtin/capkk/roles/precheck/env_check/tasks/kubernetes.yaml +++ b/builtin/capkk/roles/precheck/env_check/tasks/kubernetes.yaml @@ -33,17 +33,24 @@ - name: Check if kubernetes installed when: .groups.k8s_cluster | default list | has .inventory_hostname block: - - name: Get kubernetes service - ignore_errors: true - command: systemctl is-active kubelet.service - register: kubernetes_install_service + - name: Get kubelet.service LoadState and save to variable + command: systemctl show kubelet.service -p LoadState --value + register: kubernetes_install_LoadState + - name: Get kubelet.service ActiveState and save to variable + command: systemctl show kubelet.service -p ActiveState --value + register: kubernetes_install_ActiveState - name: Get kubernetes version ignore_errors: true command: kubelet --version register: kubernetes_install_version - name: Check kubernetes service and version - when: .kubernetes_install_service.stdout | eq "active" + when: .kubernetes_install_LoadState.stdout | eq "loaded" block: + - name: Kubernetes should be active + assert: + that: .kubernetes_install_ActiveState.stdout | eq "active" + fail_msg: >- + kubernetes should be active when it's loaded - name: Check kubernetes version assert: that: .kubernetes_install_version.stdout | default "" | trimPrefix "Kubernetes " | eq .kube_version diff --git a/builtin/core/playbooks/add_nodes.yaml b/builtin/core/playbooks/add_nodes.yaml index 30d084da..f97f4578 100644 --- a/builtin/core/playbooks/add_nodes.yaml +++ b/builtin/core/playbooks/add_nodes.yaml @@ -49,7 +49,7 @@ init_kubernetes_node: >- {{- $initNodes := list -}} {{- range .groups.kube_control_plane -}} - {{- if index $.hostvars . "kubernetes_install_service" "stdout" | eq "active" -}} + {{- if index $.hostvars . "kubernetes_install_LoadState" "stdout" | eq "loaded" -}} {{- $initNodes = append $initNodes . -}} {{- end -}} {{- end -}} diff --git a/builtin/core/playbooks/certs_renew.yaml b/builtin/core/playbooks/certs_renew.yaml index eb29968f..f32e4652 100644 --- a/builtin/core/playbooks/certs_renew.yaml +++ b/builtin/core/playbooks/certs_renew.yaml @@ -14,24 +14,9 @@ - init/init-cert - hosts: - - etcd + - all tags: ["certs"] roles: - - role: certs/renew-etcd - when: and (.groups.etcd | default list | empty | not) .renew_etcd - -- hosts: - - image_registry - tags: ["certs"] - roles: - - role: certs/renew-registry - when: and (.groups.image_registry | default list | empty | not) .renew_image_registry - -- hosts: - - kube_control_plane - tags: ["certs"] - roles: - - role: certs/renew-kubernetes - when: and (.groups.kube_control_plane | default list | empty | not) .renew_kubernetes + - role: certs/renew - import_playbook: hook/post_install.yaml \ No newline at end of file diff --git a/builtin/core/playbooks/delete_nodes.yaml b/builtin/core/playbooks/delete_nodes.yaml index 0f21ba6f..1e9d7239 100644 --- a/builtin/core/playbooks/delete_nodes.yaml +++ b/builtin/core/playbooks/delete_nodes.yaml @@ -11,16 +11,26 @@ - kube_control_plane gather_facts: true tasks: - - name: Get kubernetes service - ignore_errors: true - command: systemctl is-active kubelet.service - register: kubernetes_install_service + - name: Get kubelet.service LoadState and save to variable + command: systemctl show kubelet.service -p LoadState --value + register: kubernetes_install_LoadState + - name: Get kubelet.service ActiveState and save to variable + command: systemctl show kubelet.service -p ActiveState --value + register: kubernetes_install_ActiveState + - name: Check kubernetes service and version + when: .kubernetes_install_LoadState.stdout | eq "loaded" + block: + - name: Kubernetes should be active + assert: + that: .kubernetes_install_ActiveState.stdout | eq "active" + fail_msg: >- + kubernetes should be active when it's loaded - name: Keep at least one control_plane node. run_once: true command: | {{- $cpNodes := list -}} {{- range .groups.kube_control_plane -}} - {{- if index $.hostvars . "kubernetes_install_service" "stdout" | eq "active" -}} + {{- if index $.hostvars . "kubernetes_install_LoadState" "stdout" | eq "loaded" -}} {{- $cpNodes = append $cpNodes . -}} {{- end -}} {{- end -}} diff --git a/builtin/core/playbooks/hook/post_install.yaml b/builtin/core/playbooks/hook/post_install.yaml index d3120ece..a48f7428 100644 --- a/builtin/core/playbooks/hook/post_install.yaml +++ b/builtin/core/playbooks/hook/post_install.yaml @@ -14,7 +14,7 @@ register: execute_result - name: Execute post install scripts - when: .execute_result.stderr | empty + when: .execute_result.error | empty command: | for file in /etc/kubekey/scripts/post_install_*.sh; do if [ -f $file ]; then diff --git a/builtin/core/playbooks/hook/pre_install.yaml b/builtin/core/playbooks/hook/pre_install.yaml index a1172a73..1444f044 100644 --- a/builtin/core/playbooks/hook/pre_install.yaml +++ b/builtin/core/playbooks/hook/pre_install.yaml @@ -46,7 +46,7 @@ register: execute_result - name: Execute pre install scripts - when: .execute_result.stderr | empty + when: .execute_result.error | empty command: | for file in /etc/kubekey/scripts/pre_install_*.sh; do if [ -f $file ]; then diff --git a/builtin/core/playbooks/vars/certs_renew.yaml b/builtin/core/playbooks/vars/certs_renew.yaml index 6a6115ab..2609b7f9 100644 --- a/builtin/core/playbooks/vars/certs_renew.yaml +++ b/builtin/core/playbooks/vars/certs_renew.yaml @@ -1,6 +1,3 @@ -renew_etcd: true -renew_image_registry: true -renew_kubernetes: true kubernetes: etcd: deployment_type: external diff --git a/builtin/core/roles/certs/renew-etcd/tasks/main.yaml b/builtin/core/roles/certs/renew/etcd/tasks/main.yaml similarity index 59% rename from builtin/core/roles/certs/renew-etcd/tasks/main.yaml rename to builtin/core/roles/certs/renew/etcd/tasks/main.yaml index 22c624be..8bd995c3 100644 --- a/builtin/core/roles/certs/renew-etcd/tasks/main.yaml +++ b/builtin/core/roles/certs/renew/etcd/tasks/main.yaml @@ -1,25 +1,21 @@ --- -- name: Sync ca file to remote - tags: ["certs"] +- name: ETCD | Copy CA certificate to remote host copy: src: >- {{ .binary_dir }}/pki/root.crt dest: /etc/ssl/etcd/ssl/ca.crt -- name: Sync etcd cert file to remote - tags: ["certs"] +- name: ETCD | Copy server certificate to remote host copy: src: >- {{ .binary_dir }}/pki/etcd.crt dest: /etc/ssl/etcd/ssl/server.crt -- name: Sync etcd key file to remote - tags: ["certs"] +- name: ETCD | Copy server private key to remote host copy: src: >- {{ .binary_dir }}/pki/etcd.key dest: /etc/ssl/etcd/ssl/server.key -- name: Restart etcd service - tags: ["certs"] +- name: ETCD | Restart etcd service to apply new certificates command: systemctl restart etcd diff --git a/builtin/core/roles/certs/renew-registry/tasks/harbor.yaml b/builtin/core/roles/certs/renew/image-registry/tasks/harbor.yaml similarity index 62% rename from builtin/core/roles/certs/renew-registry/tasks/harbor.yaml rename to builtin/core/roles/certs/renew/image-registry/tasks/harbor.yaml index 7c38bb74..8f886fd2 100644 --- a/builtin/core/roles/certs/renew-registry/tasks/harbor.yaml +++ b/builtin/core/roles/certs/renew/image-registry/tasks/harbor.yaml @@ -1,20 +1,17 @@ --- -- name: Sync image registry cert file to remote - tags: ["certs"] +- name: Harbor | Copy image registry certificate to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /opt/harbor/{{ .harbor_version }}/ssl/server.crt -- name: Sync image registry key file to remote - tags: ["certs"] +- name: Harbor | Copy image registry private key to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.key dest: >- /opt/harbor/{{ .harbor_version }}/ssl/server.key -- name: Restart harbor service - tags: ["certs"] +- name: Harbor | Restart Harbor service to apply new certificates command: systemctl restart harbor.service diff --git a/builtin/core/roles/certs/renew-registry/tasks/main.yaml b/builtin/core/roles/certs/renew/image-registry/tasks/main.yaml similarity index 55% rename from builtin/core/roles/certs/renew-registry/tasks/main.yaml rename to builtin/core/roles/certs/renew/image-registry/tasks/main.yaml index eb7ef14e..8154f1df 100644 --- a/builtin/core/roles/certs/renew-registry/tasks/main.yaml +++ b/builtin/core/roles/certs/renew/image-registry/tasks/main.yaml @@ -1,6 +1,4 @@ - include_tasks: harbor.yaml - tags: ["certs"] when: .image_registry.type | eq "harbor" - include_tasks: registry.yaml - tags: ["certs"] - when: .image_registry.type | eq "registry" + when: .image_registry.type | eq "docker-registry" diff --git a/builtin/core/roles/certs/renew-registry/tasks/registry.yaml b/builtin/core/roles/certs/renew/image-registry/tasks/registry.yaml similarity index 61% rename from builtin/core/roles/certs/renew-registry/tasks/registry.yaml rename to builtin/core/roles/certs/renew/image-registry/tasks/registry.yaml index 9b7409ea..f664f455 100644 --- a/builtin/core/roles/certs/renew-registry/tasks/registry.yaml +++ b/builtin/core/roles/certs/renew/image-registry/tasks/registry.yaml @@ -1,20 +1,17 @@ --- -- name: Sync image registry cert file to remote - tags: ["certs"] +- name: Docker Registry | Copy image registry certificate to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /opt/docker-registry/{{ .docker_registry_version }}/ssl/server.crt -- name: Sync image registry key file to remote - tags: ["certs"] +- name: Docker Registry | Copy image registry private key to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.key dest: >- /opt/docker-registry/{{ .docker_registry_version }}/ssl/server.key -- name: Restart registry service - tags: ["certs"] +- name: Docker Registry | Restart registry service to apply new certificates command: systemctl restart registry.service diff --git a/builtin/core/roles/certs/renew-kubernetes/tasks/etcd.yaml b/builtin/core/roles/certs/renew/kubernetes/tasks/etcd.yaml similarity index 67% rename from builtin/core/roles/certs/renew-kubernetes/tasks/etcd.yaml rename to builtin/core/roles/certs/renew/kubernetes/tasks/etcd.yaml index db646c43..ad83998a 100644 --- a/builtin/core/roles/certs/renew-kubernetes/tasks/etcd.yaml +++ b/builtin/core/roles/certs/renew/kubernetes/tasks/etcd.yaml @@ -1,20 +1,19 @@ --- -- name: Sync etcd ca file to remote - tags: ["certs"] +- name: ETCD | Copy CA certificate to remote host copy: src: >- {{ .binary_dir }}/pki/root.crt dest: /etc/kubernetes/pki/etcd/ca.crt mode: 0755 -- name: Sync etcd cert files to remote - tags: ["certs"] + +- name: ETCD | Copy client certificate to remote host copy: src: >- {{ .binary_dir }}/pki/etcd.crt dest: /etc/kubernetes/pki/etcd/client.crt mode: 0755 -- name: Sync etcd key files to remote - tags: ["certs"] + +- name: ETCD | Copy client key to remote host copy: src: >- {{ .binary_dir }}/pki/etcd.key diff --git a/builtin/core/roles/certs/renew-kubernetes/tasks/kube.yaml b/builtin/core/roles/certs/renew/kubernetes/tasks/kube.yaml similarity index 74% rename from builtin/core/roles/certs/renew-kubernetes/tasks/kube.yaml rename to builtin/core/roles/certs/renew/kubernetes/tasks/kube.yaml index bcf34edc..14b6b3c4 100644 --- a/builtin/core/roles/certs/renew-kubernetes/tasks/kube.yaml +++ b/builtin/core/roles/certs/renew/kubernetes/tasks/kube.yaml @@ -1,50 +1,48 @@ --- -- name: Check kubeadm version - tags: ["certs"] +- name: Kubernetes | Determine installed kubeadm version run_once: true command: kubeadm version -o short register: kubeadm_install_version -- name: Renew cert by kubeadm - tags: ["certs"] +- name: Kubernetes | Renew certificates using kubeadm run_once: true command: | {{- if .kubeadm_install_version.stdout | semverCompare "- {{ .binary_dir }}/kubeconfig -- name: Sync kubeconfig to remote - tags: ["certs"] +- name: Kubernetes | Distribute kubeconfig to remote host copy: src: >- {{ .binary_dir }}/kubeconfig diff --git a/builtin/core/roles/certs/renew-kubernetes/tasks/main.yaml b/builtin/core/roles/certs/renew/kubernetes/tasks/main.yaml similarity index 66% rename from builtin/core/roles/certs/renew-kubernetes/tasks/main.yaml rename to builtin/core/roles/certs/renew/kubernetes/tasks/main.yaml index f85a851d..a084f200 100644 --- a/builtin/core/roles/certs/renew-kubernetes/tasks/main.yaml +++ b/builtin/core/roles/certs/renew/kubernetes/tasks/main.yaml @@ -1,29 +1,29 @@ --- - include_tasks: kube.yaml - tags: ["certs"] - include_tasks: etcd.yaml - tags: ["certs"] when: - - .kubernetes.etcd.deployment_type | eq "external" - - .groups.etcd | default list | empty | not - - .renew_etcd + - .kubernetes.etcd.deployment_type | eq "external" + - .groups.etcd | default list | empty | not -- name: Reload kubernetes pods - tags: [ "certs" ] +- name: Kubernetes | Restart Kubernetes control plane pods command: | {{- if .cri.container_manager | eq "docker" }} + # Restarting Kubernetes control plane pods using Docker docker ps -af name=k8s_PODS_kube-apiserver* -q | xargs --no-run-if-empty docker rm -f docker ps -af name=k8s_PODS_kube-controller-manager* -q | xargs --no-run-if-empty docker rm -f docker ps -af name=k8s_PODS_kube-scheduler* -q | xargs --no-run-if-empty docker rm -f - {{- if and (.kubernetes.etcd.deployment_type | eq "docker") .renew_etcd }} + {{- if .kubernetes.etcd.deployment_type | eq "docker" }} + # Restarting etcd pods managed by Docker docker ps -af name=k8s_PODS_etcd* -q | xargs --no-run-if-empty docker rm -f {{- end }} {{- else }} + # Restarting Kubernetes control plane pods using crictl crictl pods --name kube-apiserver-* -q | xargs -I% --no-run-if-empty bash -c 'crictl stopp % && crictl rmp %' crictl pods --name kube-controller-manager-* -q | xargs -I% --no-run-if-empty bash -c 'crictl stopp % && crictl rmp %' crictl pods --name kube-scheduler-* -q | xargs -I% --no-run-if-empty bash -c 'crictl stopp % && crictl rmp %' - {{- if and (.kubernetes.etcd.deployment_type | eq "internal") .renew_etcd }} + {{- if .kubernetes.etcd.deployment_type | eq "internal" }} + # Restarting etcd pods managed by the container runtime crictl pods --name etcd-* -q | xargs -I% --no-run-if-empty bash -c 'crictl stopp % && crictl rmp %' {{- end }} {{- end }} diff --git a/builtin/core/roles/certs/renew/meta/main.yaml b/builtin/core/roles/certs/renew/meta/main.yaml new file mode 100644 index 00000000..477da2a8 --- /dev/null +++ b/builtin/core/roles/certs/renew/meta/main.yaml @@ -0,0 +1,13 @@ +--- +dependencies: + - role: renew/etcd + tags: ["certs", "etcd"] + when: .groups.etcd | default list | has .inventory_hostname + + - role: renew/kubernetes + tags: ["certs", "kubernetes"] + when: .groups.kube_control_plane | default list | has .inventory_hostname + + - role: renew/image-registry + tags: ["certs", "image-registry"] + when: .groups.image_registry | default list | has .inventory_hostname diff --git a/builtin/core/roles/init/init-artifact/tasks/download_binary.yaml b/builtin/core/roles/init/init-artifact/tasks/download_binary.yaml index cd39f70e..76070d1a 100644 --- a/builtin/core/roles/init/init-artifact/tasks/download_binary.yaml +++ b/builtin/core/roles/init/init-artifact/tasks/download_binary.yaml @@ -1,88 +1,88 @@ --- -- name: Check binaries for etcd +- name: Binary | Ensure etcd binary is present tags: ["etcd"] command: | artifact_name={{ get .artifact.artifact_url.etcd .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/etcd/{{ .etcd_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then - mkdir -p $artifact_path - # download online - http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.etcd .item }}) - if [ $http_code != 200 ]; then - echo "http code is $http_code" - exit 1 - fi - curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.etcd .item }} + mkdir -p $artifact_path + # Attempt to download etcd binary + http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.etcd .item }}) + if [ $http_code != 200 ]; then + echo "Failed to download etcd binary. HTTP status code: $http_code" + exit 1 + fi + curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.etcd .item }} fi loop: "{{ .artifact.arch | toJson }}" when: .etcd_version | empty | not -- name: Check binaries for kube +- name: Binary | Ensure Kubernetes binaries are present tags: ["kube"] command: | kube_path={{ .binary_dir }}/kube/{{ .kube_version }}/{{ .item }} if [ ! -f $kube_path/kubelet ]; then - mkdir -p $kube_path - # download online - http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubelet .item }}) - if [ $http_code != 200 ]; then - echo "http code is $http_code" - exit 1 - fi - curl -L -o $kube_path/kubelet {{ get .artifact.artifact_url.kubelet .item }} + mkdir -p $kube_path + # Download kubelet if missing + http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubelet .item }}) + if [ $http_code != 200 ]; then + echo "Failed to download kubelet. HTTP status code: $http_code" + exit 1 + fi + curl -L -o $kube_path/kubelet {{ get .artifact.artifact_url.kubelet .item }} fi if [ ! -f $kube_path/kubeadm ]; then - mkdir -p $kube_path - # download online - http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubeadm .item }}) - if [ $http_code != 200 ]; then - echo "http code is $http_code" - exit 1 - fi - curl -L -o $kube_path/kubeadm {{ get .artifact.artifact_url.kubeadm .item }} + mkdir -p $kube_path + # Download kubeadm if missing + http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubeadm .item }}) + if [ $http_code != 200 ]; then + echo "Failed to download kubeadm. HTTP status code: $http_code" + exit 1 + fi + curl -L -o $kube_path/kubeadm {{ get .artifact.artifact_url.kubeadm .item }} fi if [ ! -f $kube_path/kubectl ]; then - mkdir -p $kube_path - # download online - http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubectl .item }}) - if [ $http_code != 200 ]; then - echo "http code is $http_code" - exit 1 - fi - curl -L -o $kube_path/kubectl {{ get .artifact.artifact_url.kubectl .item }} + mkdir -p $kube_path + # Download kubectl if missing + http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.kubectl .item }}) + if [ $http_code != 200 ]; then + echo "Failed to download kubectl. HTTP status code: $http_code" + exit 1 + fi + curl -L -o $kube_path/kubectl {{ get .artifact.artifact_url.kubectl .item }} fi loop: "{{ .artifact.arch | toJson }}" when: .kube_version | empty | not -- name: Check binaries for cni +- name: Binary | Ensure CNI plugins are present tags: ["cni"] command: | artifact_name={{ get .artifact.artifact_url.cni_plugins .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/plugins/{{ .cni_plugins_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online - http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.cni_plugins .item }}) - if [ $http_code != 200 ]; then - echo "http code is $http_code" - exit 1 - fi + # Attempt to download CNI plugins + http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.cni_plugins .item }}) + if [ $http_code != 200 ]; then + echo "Failed to download CNI plugins. HTTP status code: $http_code" + exit 1 + fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.cni_plugins .item }} fi loop: "{{ .artifact.arch | toJson }}" when: .cni_plugins_version | empty | not -- name: Check binaries for helm +- name: Binary | Ensure Helm binary is present tags: ["helm"] command: | artifact_name={{ get .artifact.artifact_url.helm .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/helm/{{ .helm_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download Helm binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.helm .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download Helm binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.helm .item }} @@ -90,17 +90,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .helm_version | empty | not -- name: Check binaries for crictl +- name: Binary | Ensure crictl binary is present tags: ["crictl"] command: | artifact_name={{ get .artifact.artifact_url.crictl .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/crictl/{{ .crictl_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download crictl binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.crictl .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download crictl binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.crictl .item }} @@ -108,17 +108,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .crictl_version | empty | not -- name: Check binaries for docker +- name: Binary | Ensure Docker binary is present tags: ["docker"] command: | artifact_name={{ get .artifact.artifact_url.docker .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/docker/{{ .docker_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download Docker binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.docker .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download Docker binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.docker .item }} @@ -126,17 +126,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .docker_version | empty | not -- name: Check binaries for cridockerd +- name: Binary | Ensure cri-dockerd binary is present tags: ["cridockerd"] command: | artifact_name={{ get .artifact.artifact_url.cridockerd .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/cri-dockerd/{{ .cridockerd_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download cri-dockerd binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.cridockerd .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download cri-dockerd binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.cridockerd .item }} @@ -144,17 +144,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .cridockerd_version | empty | not -- name: Check binaries for containerd +- name: Binary | Ensure containerd binary is present tags: ["containerd"] command: | artifact_name={{ get .artifact.artifact_url.containerd .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/containerd/{{ .containerd_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download containerd binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.containerd .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download containerd binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.containerd .item }} @@ -162,17 +162,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .containerd_version | empty | not -- name: Check binaries for runc +- name: Binary | Ensure runc binary is present tags: ["runc"] command: | artifact_name={{ get .artifact.artifact_url.runc .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/runc/{{ .runc_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download runc binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.runc .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download runc binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.runc .item }} @@ -180,17 +180,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .runc_version | empty | not -- name: Check binaries for calicoctl +- name: Binary | Ensure calicoctl binary is present tags: ["calicoctl"] command: | artifact_name=calicoctl artifact_path={{ .binary_dir }}/cni/calico/{{ .calico_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download calicoctl binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.calicoctl .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download calicoctl binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.calicoctl .item }} @@ -198,17 +198,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .calico_version | empty | not -- name: Check binaries for registry +- name: Binary | Ensure Docker Registry binary is present tags: ["registry"] command: | artifact_name={{ get .artifact.artifact_url.docker_registry .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/image-registry/docker-registry/{{ .docker_registry_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download Docker Registry binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.docker_registry .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download Docker Registry binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.docker_registry .item }} @@ -216,30 +216,30 @@ loop: "{{ .artifact.arch | toJson }}" when: .docker_registry_version | empty | not -- name: Check binaries for docker-compose +- name: Binary | Ensure docker-compose binary is present tags: ["docker-compose"] command: | compose_name=docker-compose compose_path={{ .binary_dir }}/image-registry/docker-compose/{{ .dockercompose_version }}/{{ .item }} if [ ! -f $compose_path/$compose_name ]; then mkdir -p $compose_path - # download online + # Attempt to download docker-compose binary curl -L -o $compose_path/$compose_name {{ get .artifact.artifact_url.dockercompose .item }} fi loop: "{{ .artifact.arch | toJson }}" when: .dockercompose_version | empty | not -- name: Check binaries for harbor +- name: Binary | Ensure Harbor binary is present tags: ["harbor"] command: | harbor_name={{ get .artifact.artifact_url.harbor .item | splitList "/" | last }} harbor_path={{ .binary_dir }}/image-registry/harbor/{{ .harbor_version }}/{{ .item }} if [ ! -f $harbor_path/$harbor_name ]; then mkdir -p $harbor_path - # download online + # Attempt to download Harbor binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.harbor .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download Harbor binary. HTTP status code: $http_code" exit 1 fi curl -L -o $harbor_path/$harbor_name {{ get .artifact.artifact_url.harbor .item }} @@ -247,17 +247,17 @@ loop: "{{ .artifact.arch | toJson }}" when: .harbor_version | empty | not -- name: Check binaries for keepalived +- name: Binary | Ensure keepalived binary is present tags: ["keepalived"] command: | artifact_name={{ get .artifact.artifact_url.keepalived .item | splitList "/" | last }} artifact_path={{ .binary_dir }}/image-registry/keepalived/{{ .keepalived_version }}/{{ .item }} if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Attempt to download keepalived binary http_code=$(curl -Lo /dev/null -s -w "%{http_code}" {{ get .artifact.artifact_url.keepalived .item }}) if [ $http_code != 200 ]; then - echo "http code is $http_code" + echo "Failed to download keepalived binary. HTTP status code: $http_code" exit 1 fi curl -L -o $artifact_path/$artifact_name {{ get .artifact.artifact_url.keepalived .item }} diff --git a/builtin/core/roles/init/init-artifact/tasks/download_helm.yaml b/builtin/core/roles/init/init-artifact/tasks/download_helm.yaml index 2a8db2f6..3383fc2f 100644 --- a/builtin/core/roles/init/init-artifact/tasks/download_helm.yaml +++ b/builtin/core/roles/init/init-artifact/tasks/download_helm.yaml @@ -1,69 +1,69 @@ --- -- name: Check binaries for calico +- name: Helm | Ensure the Calico binary is available command: | artifact_name={{ .artifact.artifact_url.calico | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/calico if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the Calico binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.calico }} fi when: .calico_version | empty | not -- name: Check binaries for cilium +- name: Helm | Ensure the Cilium binary is available command: | artifact_name={{ .artifact.artifact_url.cilium | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/cilium if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the Cilium binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.cilium }} fi when: .cilium_version | empty | not -- name: Check binaries for flannel +- name: Helm | Ensure the Flannel binary is available command: | artifact_name={{ .artifact.artifact_url.flannel | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/flannel if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the Flannel binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.flannel }} fi when: .flannel_version | empty | not -- name: Check binaries for kubeovn +- name: Helm | Ensure the Kube-OVN binary is available tags: ["kubeovn"] command: | artifact_name={{ .artifact.artifact_url.kubeovn | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/kubeovn if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the Kube-OVN binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.kubeovn }} fi when: .kubeovn_version | empty | not -- name: Check binaries for hybridnet +- name: Helm | Ensure the Hybridnet binary is available tags: ["hybridnet"] command: | artifact_name={{ .artifact.artifact_url.hybridnet | splitList "/" | last }} artifact_path={{ .binary_dir }}/cni/hybridnet if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the Hybridnet binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.hybridnet }} fi when: .hybridnet_version | empty | not -- name: Check binaries for nfs_provisioner +- name: Helm | Ensure the NFS Provisioner binary is available tags: ["nfs_provisioner"] command: | - artifact_name={{ .artifact.artifact_url.nfs_provisioner |splitList "/" | last }} + artifact_name={{ .artifact.artifact_url.nfs_provisioner | splitList "/" | last }} artifact_path={{ .binary_dir }}/sc if [ ! -f $artifact_path/$artifact_name ]; then mkdir -p $artifact_path - # download online + # Download the NFS Provisioner binary if it does not exist curl -Lo $artifact_path/$artifact_name {{ .artifact.artifact_url.nfs_provisioner }} fi when: .nfs_provisioner_version | empty | not diff --git a/builtin/core/roles/init/init-artifact/tasks/main.yaml b/builtin/core/roles/init/init-artifact/tasks/main.yaml index 616e41f8..32369bf6 100644 --- a/builtin/core/roles/init/init-artifact/tasks/main.yaml +++ b/builtin/core/roles/init/init-artifact/tasks/main.yaml @@ -1,5 +1,5 @@ --- -- name: Extract artifact to work_dir +- name: Artifact | Extract artifact archive to working directory tags: ["always"] command: | if [ -f "{{ .artifact_file }}" ]; then @@ -8,15 +8,15 @@ fi when: .artifact_file | empty | not -- name: Download binaries +- name: Artifact | Download required binaries and images when: .artifact_file | empty block: - # the binaries which download binary + # Download core binaries - include_tasks: download_binary.yaml - # the binaries which download helm + # Download Helm and CNI binaries - include_tasks: download_helm.yaml - # download remote images to local - - name: Download images + # Download remote images to the local images directory + - name: Download container images image: pull: images_dir: >- @@ -25,7 +25,7 @@ when: - .image_manifests | default list | empty | not -- name: Chown work_dir to sudo +- name: Artifact | Set ownership of working directory to sudo user tags: ["always"] ignore_errors: true command: | diff --git a/builtin/core/roles/init/init-cert/tasks/main.yaml b/builtin/core/roles/init/init-cert/tasks/main.yaml index 1013e380..c3016589 100644 --- a/builtin/core/roles/init/init-cert/tasks/main.yaml +++ b/builtin/core/roles/init/init-cert/tasks/main.yaml @@ -1,5 +1,5 @@ --- -- name: Generate root ca file +- name: Cert | Generate the root CA certificate file gen_cert: cn: root date: "{{ .certs.ca.date }}" @@ -9,9 +9,9 @@ out_cert: >- {{ .binary_dir }}/pki/root.crt -- name: Generate kubernetes ca file +- name: Cert | Generate Kubernetes CA certificates block: - - name: Generate ca file for kubernetes + - name: Cert | Generate the Kubernetes CA certificate file gen_cert: root_key: >- {{ .binary_dir }}/pki/root.key @@ -25,7 +25,7 @@ {{ .binary_dir }}/pki/kubernetes.key out_cert: >- {{ .binary_dir }}/pki/kubernetes.crt - - name: Generate front-proxy ca file for kubernetes + - name: Cert | Generate the front-proxy CA certificate for Kubernetes gen_cert: root_key: >- {{ .binary_dir }}/pki/root.key @@ -40,7 +40,7 @@ out_cert: >- {{ .binary_dir }}/pki/front-proxy.crt -- name: Generate etcd cert file +- name: Cert | Generate the etcd certificate file gen_cert: root_key: >- {{ .binary_dir }}/pki/root.key @@ -68,7 +68,7 @@ {{ .binary_dir }}/pki/etcd.crt when: .groups.etcd | default list | empty | not -- name: Generate registry image cert file +- name: Cert | Generate the image registry certificate file gen_cert: root_key: >- {{ .binary_dir }}/pki/root.key @@ -99,9 +99,9 @@ {{ .binary_dir }}/pki/image_registry.crt when: .groups.image_registry | default list | empty | not -- name: Chown pki to sudo +- name: Cert | Set ownership of the PKI directory to the sudo user block: - - name: Chown pki to sudo + - name: Cert | Change ownership of the PKI directory to the sudo user ignore_errors: true command: | chown -R ${SUDO_UID}:${SUDO_GID} {{ .binary_dir }}/pki diff --git a/builtin/core/roles/init/init-os/tasks/init_localdns.yaml b/builtin/core/roles/init/init-os/tasks/init_localdns.yaml index 0ec29274..1f445b42 100644 --- a/builtin/core/roles/init/init-os/tasks/init_localdns.yaml +++ b/builtin/core/roles/init/init-os/tasks/init_localdns.yaml @@ -1,13 +1,13 @@ -- name: Set local DNS +- name: DNS | Configure local DNS entries loop: "{{ .localDNS | toJson }}" command: | - # clear old dns configuration + # Remove any previous Kubekey-managed DNS entries sed -i ':a;$!{N;ba};s@# kubekey hosts BEGIN.*# kubekey hosts END@@' {{ .item }} sed -i '/^$/N;/\n$/N;//D' {{ .item }} - # defined new dns configuration + # Add updated Kubekey DNS configuration cat >> {{ .item }} <> $chronyConfigFile echo "allow ::/0" >> $chronyConfigFile echo "local stratum 10" >> $chronyConfigFile - # add server config + + # Add NTP server entries {{- range $server := .ntp.servers }} {{- $internalIPv4 := "" }} {{- $internalIPv6 := "" }} @@ -21,7 +25,7 @@ {{- $internalIPv6 = .internal_ipv6 | default "" }} {{- end }} {{- end }} - # add ntp server: {{ $server }} + # Configuring NTP server: {{ $server }} {{- if $internalIPv4 | empty | not }} grep -q '^server {{ $internalIPv4 }} iburst' $chronyConfigFile || sed '1a server {{ $internalIPv4 }} iburst' -i $chronyConfigFile {{- end }} @@ -30,19 +34,19 @@ {{- end }} {{- if and ($internalIPv4 | empty) ($internalIPv6 | empty) }} grep -q '^server {{ $server }} iburst' $chronyConfigFile || sed '1a server {{ $server }} iburst' -i $chronyConfigFile - {{- end }} + {{- end }} {{- end }} when: - .ntp.enabled - .ntp.servers | empty | not -- name: Set timezone +- name: Timezone | Set system timezone and NTP synchronization command: | timedatectl set-timezone {{ .timezone }} timedatectl set-ntp {{ and .ntp.enabled (.ntp.servers | empty | not) }} when: or (and .ntp.enabled (.ntp.servers | empty | not)) (.timezone | empty | not) -- name: Restart ntp server +- name: NTP | Restart NTP service command: | {{- if or (.os.release.ID | eq "ubuntu") (.os.release.ID_LIKE | eq "debian") }} systemctl restart chrony.service diff --git a/builtin/core/roles/init/init-os/tasks/init_repository.yaml b/builtin/core/roles/init/init-os/tasks/init_repository.yaml index af3ab59f..51d43293 100644 --- a/builtin/core/roles/init/init-os/tasks/init_repository.yaml +++ b/builtin/core/roles/init/init-os/tasks/init_repository.yaml @@ -1,28 +1,28 @@ --- -- name: Sync repository +- name: Kubekey Repository | Synchronize local repository ISO image block: - - name: Sync repository file + - name: Kubekey Repository | Copy local repository ISO file ignore_errors: true copy: src: >- {{ .binary_dir }}/repository/{{ .os.release.ID_LIKE }}-{{ .os.release.VERSION_ID }}-{{ .binary_type }}.iso dest: >- {{ .tmp_dir }}/repository.iso - - name: Mount iso file + - name: Kubekey Repository | Mount repository ISO to temporary directory command: | if [ -f "{{ .tmp_dir }}/repository.iso" ]; then mount -t iso9660 -o loop {{ .tmp_dir }}/repository.iso {{ .tmp_dir }}/iso fi rescue: - - name: Unmount iso file + - name: Kubekey Repository | Unmount repository ISO from temporary directory command: | if [ -f "{{ .tmp_dir }}/repository.iso" ]; then umount {{ .tmp_dir }}/iso fi -- name: Init repository +- name: Kubekey Repository | Initialize package repositories and install system dependencies block: - - name: Init debian repository + - name: Kubekey Repository | Initialize Debian-based repository and install required system packages command: | now=$(date +"%Y-%m-%d %H:%M:%S") PKGS="socat conntrack ipset ebtables chrony ipvsadm{{ if .groups.nfs | default list | has .inventory_hostname }} nfs-kernel-server{{ end }}" @@ -32,32 +32,33 @@ dpkg -s $pkg >/dev/null 2>&1 || PKGS_TO_INSTALL="$PKGS_TO_INSTALL $pkg" fi done - if [ -f "{{ .tmp_dir }}/repository.iso" ];then - # backup + if [ -f "{{ .tmp_dir }}/repository.iso" ]; then + # Backup current APT sources mv /etc/apt/sources.list /etc/apt/sources.list.kubekey-$now.bak mv /etc/apt/sources.list.d /etc/apt/sources.list.d.kubekey-$now.bak mkdir -p /etc/apt/sources.list.d - # add repository + # Configure local repository rm -rf /etc/apt/sources.list.d/* - echo 'deb [trusted=yes] file://{{ .tmp_dir }}/iso /' > /etc/apt/sources.list.d/kubekey.list - # update repository + echo 'deb [trusted=yes] file://{{ .tmp_dir }}/iso /' > /etc/apt/sources.list.d/kubekey.list + # Update package index apt-get update - # install + # Install missing packages if [ -n "$PKGS_TO_INSTALL" ]; then apt install -y $PKGS_TO_INSTALL fi - # reset repository + # Restore original APT sources rm -rf /etc/apt/sources.list.d mv /etc/apt/sources.list.kubekey.bak-$now /etc/apt/sources.list mv /etc/apt/sources.list.d.kubekey.bak-$now /etc/apt/sources.list.d else + # No local ISO found, using default repositories apt-get update if [ -n "$PKGS_TO_INSTALL" ]; then apt install -y $PKGS_TO_INSTALL fi fi when: .os.release.ID_LIKE | eq "debian" - - name: Init rhel repository + - name: Kubekey Repository | Initialize RHEL-based repository and install required system packages command: | now=$(date +"%Y-%m-%d %H:%M:%S") PKGS="socat conntrack ipset ebtables chrony ipvsadm{{ if .groups.nfs | default list | has .inventory_hostname }} nfs-kernel-server{{ end }}" @@ -66,34 +67,31 @@ if [ -n "$pkg" ]; then rpm -q $pkg >/dev/null 2>&1 || PKGS_TO_INSTALL="$PKGS_TO_INSTALL $pkg" fi - if [ -f "{{ .tmp_dir }}/repository.iso" ];then - # backup + done + if [ -f "{{ .tmp_dir }}/repository.iso" ]; then + # Backup current YUM repositories mv /etc/yum.repos.d /etc/yum.repos.d.kubekey.bak-$now mkdir -p /etc/yum.repos.d - # add repository + # Configure local repository rm -rf /etc/yum.repos.d/* cat < /etc/yum.repos.d/CentOS-local.repo [base-local] - name=rpms-local - + name=Local RPM Repository baseurl=file://{{ .tmp_dir }}/repository.iso - - enabled=1 - + enabled=1 gpgcheck=0 - EOF - # update repository + # Refresh repository cache yum clean all && yum makecache - # install + # Install missing packages if [ -n "$PKGS_TO_INSTALL" ]; then yum install -y $PKGS_TO_INSTALL fi - # reset repository + # Restore original YUM repositories rm -rf /etc/yum.repos.d mv /etc/yum.repos.d.kubekey.bak-$now /etc/yum.repos.d else - # install + # No local ISO found, using default repositories if [ -n "$PKGS_TO_INSTALL" ]; then yum install -y $PKGS_TO_INSTALL fi diff --git a/builtin/core/roles/init/init-os/tasks/main.yaml b/builtin/core/roles/init/init-os/tasks/main.yaml index 19ea96ef..25d5985b 100644 --- a/builtin/core/roles/init/init-os/tasks/main.yaml +++ b/builtin/core/roles/init/init-os/tasks/main.yaml @@ -1,15 +1,15 @@ --- -- name: Init for new kubernetes nodes - when: .kubernetes_install_service.stdout | eq "inactive" +- name: OS | Initialize new Kubernetes nodes + when: .kubernetes_install_LoadState.stdout | eq "not-found" block: - include_tasks: init_repository.yaml - - name: Reset tmp dir + - name: OS | Reset temporary directory command: | if [ -d {{ .tmp_dir }} ]; then rm -rf {{ .tmp_dir }} fi mkdir -m 777 -p {{ .tmp_dir }} - - name: Set hostname + - name: OS | Set system hostname command: | hostnamectl set-hostname {{ .inventory_hostname }} \ && sed -i '/^127.0.1.1/s/.*/127.0.1.1 {{ .inventory_hostname }}/g' {{ .item }} @@ -17,16 +17,16 @@ - .set_hostname - .inventory_hostname | ne "localhost" loop: "{{ .localDNS | toJson }}" - - name: Sync init os to remote + - name: OS | Synchronize initialization script to remote node template: src: init-os.sh dest: /etc/kubekey/scripts/init-os.sh mode: 0755 - - name: Execute init os script + - name: OS | Execute initialization script on remote node command: | /etc/kubekey/scripts/init-os.sh -- name: Init for all nodes always +- name: OS | Always perform initialization steps for all nodes block: - include_tasks: init_ntpserver.yaml - include_tasks: init_localdns.yaml \ No newline at end of file diff --git a/builtin/core/roles/install/cni/calico/tasks/main.yaml b/builtin/core/roles/install/cni/calico/tasks/main.yaml index f353b546..93fb6649 100644 --- a/builtin/core/roles/install/cni/calico/tasks/main.yaml +++ b/builtin/core/roles/install/cni/calico/tasks/main.yaml @@ -1,32 +1,33 @@ --- -- name: Check if calicoctl is installed +- name: Calico | calico-check-calicoctl-installed ignore_errors: true command: calicoctl version register: calicoctl_install_version register_type: yaml -- name: Install calicoctl - when: .calicoctl_install_version.stderr | empty | not + +- name: Calico | calico-install-calicoctl-if-missing + when: .calicoctl_install_version.error | empty | not block: - - name: Sync calicoctl to remote + - name: Calico | calico-sync-calicoctl-to-remote copy: src: >- {{ .binary_dir }}/cni/calico/{{ .calico_version }}/{{ .binary_type }}/calicoctl dest: /usr/local/bin/calicoctl mode: 0755 -- name: Sync calico package to remote +- name: Calico | calico-sync-calico-package-to-remote copy: src: >- {{ .binary_dir }}/cni/calico/tigera-operator-{{ .calico_version }}.tgz dest: >- /etc/kubernetes/cni/tigera-operator-{{ .calico_version }}.tgz -- name: Generate calico custom value file +- name: Calico | calico-generate-custom-values-file copy: content: | {{ .cni.calico.values }} dest: /etc/kubernetes/cni/calico-values.yaml -- name: Apply calico +- name: Calico | calico-apply-helm-chart command: | - helm install --create-namespace --namespace tigera-operator calico /etc/kubernetes/cni/tigera-operator-{{ .calico_version }}.tgz -f /etc/kubernetes/cni/calico-values.yaml + helm upgrade --install --create-namespace --namespace tigera-operator calico /etc/kubernetes/cni/tigera-operator-{{ .calico_version }}.tgz -f /etc/kubernetes/cni/calico-values.yaml diff --git a/builtin/core/roles/install/cni/cilium/tasks/main.yaml b/builtin/core/roles/install/cni/cilium/tasks/main.yaml index 74667b11..bfdc48f4 100644 --- a/builtin/core/roles/install/cni/cilium/tasks/main.yaml +++ b/builtin/core/roles/install/cni/cilium/tasks/main.yaml @@ -1,25 +1,25 @@ --- -- name: Sync cilium cli package +- name: Cilium | Ensure cilium CLI package is present when: .ciliumcli_version | empty | not copy: src: >- {{ .binary_dir }}/cni/cilium/ciliumcli-{{ .ciliumcli_version }}/{{ .item }} dest: /usr/local/bin/cilium -- name: Sync cilium helm chart package +- name: Cilium | Ensure cilium Helm chart package is present copy: src: >- {{ .binary_dir }}/cni/cilium/cilium-{{ .cilium_version }}.tgz dest: >- /etc/kubernetes/cni/cilium-{{ .cilium_version }}.tgz -- name: Sync cilium helm chart custom value file +- name: Cilium | Generate cilium Helm custom values file copy: content: | {{ .cni.cilium.values }} dest: /etc/kubernetes/cni/cilium-values.yaml -# https://docs.cilium.io/en/stable/installation/k8s-install-helm/ -- name: Install cilium +# Reference: https://docs.cilium.io/en/stable/installation/k8s-install-helm/ +- name: Cilium | Install cilium using Helm command: | - helm install --namespace kube-system cilium /etc/kubernetes/cni/cilium-{{ .cilium_version }}.tgz -f /etc/kubernetes/cni/cilium-values.yaml + helm upgrade --install --namespace kube-system cilium /etc/kubernetes/cni/cilium-{{ .cilium_version }}.tgz -f /etc/kubernetes/cni/cilium-values.yaml diff --git a/builtin/core/roles/install/cni/flannel/tasks/main.yaml b/builtin/core/roles/install/cni/flannel/tasks/main.yaml index 438f0ce7..47254aa6 100644 --- a/builtin/core/roles/install/cni/flannel/tasks/main.yaml +++ b/builtin/core/roles/install/cni/flannel/tasks/main.yaml @@ -1,17 +1,18 @@ --- -# https://github.com/flannel-io/flannel/blob/master/Documentation/kubernetes.md -- name: Sync flannel package to remote +# For more information, see: https://github.com/flannel-io/flannel/blob/master/Documentation/kubernetes.md + +- name: Flannel | Sync flannel package to remote node copy: src: >- {{ .binary_dir }}/cni/flannel/flannel.tgz dest: /etc/kubernetes/cni/flannel.tgz -- name: Generate flannel custom value file +- name: Flannel | Generate flannel custom values file copy: content: | {{ .cni.flannel.values }} dest: /etc/kubernetes/cni/flannel-values.yaml -- name: Apply flannel +- name: Flannel | Install flannel using Helm command: | - helm install --create-namespace --namespace kube-flannel flannel /etc/kubernetes/cni/flannel.tgz -f /etc/kubernetes/cni/flannel-values.yaml + helm upgrade --install --create-namespace --namespace kube-flannel flannel /etc/kubernetes/cni/flannel.tgz -f /etc/kubernetes/cni/flannel-values.yaml diff --git a/builtin/core/roles/install/cni/hybridnet/tasks/main.yaml b/builtin/core/roles/install/cni/hybridnet/tasks/main.yaml index 53419a52..8d006e71 100644 --- a/builtin/core/roles/install/cni/hybridnet/tasks/main.yaml +++ b/builtin/core/roles/install/cni/hybridnet/tasks/main.yaml @@ -1,18 +1,18 @@ --- -- name: Sync hybridnet helm chart to remote +- name: Hybridnet | Synchronize Hybridnet Helm chart package to remote node copy: src: >- {{ .binary_dir }}/cni/hybridnet-{{ .hybridnet_version }}.tgz dest: >- /etc/kubernetes/cni/hybridnet-{{ .hybridnet_version }}.tgz -- name: Generate hybridnet custom value file +- name: Hybridnet | Generate Hybridnet custom values file copy: content: | {{ .cni.hybridnet.values }} dest: /etc/kubernetes/cni/hybridnet-values.yaml -# https://artifacthub.io/packages/helm/hybridnet/hybridnet -- name: Install hybridnet +# Reference: https://artifacthub.io/packages/helm/hybridnet/hybridnet +- name: Hybridnet | Install Hybridnet using Helm command: | - helm install --namespace kube-system hybridnet /etc/kubernetes/cni/hybridnet-{{ .hybridnet_version }}.tgz -f /etc/kubernetes/cni/hybridnet-values.yaml + helm upgrade --install --namespace kube-system hybridnet /etc/kubernetes/cni/hybridnet-{{ .hybridnet_version }}.tgz -f /etc/kubernetes/cni/hybridnet-values.yaml diff --git a/builtin/core/roles/install/cni/kubeovn/tasks/main.yaml b/builtin/core/roles/install/cni/kubeovn/tasks/main.yaml index fca3cb48..c6867c55 100644 --- a/builtin/core/roles/install/cni/kubeovn/tasks/main.yaml +++ b/builtin/core/roles/install/cni/kubeovn/tasks/main.yaml @@ -1,27 +1,27 @@ --- -- name: Sync kubeovn package to remote +- name: Kubeovn | Synchronize Kube-OVN Helm chart package to remote node copy: src: >- {{ .binary_dir }}/cni/kubeovn/kubeovn-{{ .kubeovn_version }}.tgz dest: >- /etc/kubernetes/cni/kubeovn-{{ .kubeovn_version }}.tgz -- name: Generate kubeovn custom value file +- name: Kubeovn | Generate Kube-OVN custom values file copy: content: | {{ .cni.kubeovn.values }} dest: /etc/kubernetes/cni/kubeovn-values.yaml -- name: Add kubeovn label to node +- name: Kubeovn | Add Kube-OVN labels to nodes command: | kubectl label node -lbeta.kubernetes.io/os=linux kubernetes.io/os=linux --overwrite kubectl label node -lnode-role.kubernetes.io/control-plane kube-ovn/role=master --overwrite -- name: Apply kubeovn +- name: Kubeovn | Install Kube-OVN using Helm with custom values command: | - helm install --namespace kubeovn-system kubeovn /etc/kubernetes/cni/kubeovn-{{ .kubeovn_version }}.tgz -f /etc/kubernetes/cni/kubeovn-values.yaml + helm upgrade --install --namespace kubeovn-system kubeovn /etc/kubernetes/cni/kubeovn-{{ .kubeovn_version }}.tgz -f /etc/kubernetes/cni/kubeovn-values.yaml -# https://kubeovn.github.io/docs/stable/start/one-step-install/#helm-chart -- name: Install kubeovn +# Reference: https://kubeovn.github.io/docs/stable/start/one-step-install/#helm-chart +- name: Kubeovn | Install Kube-OVN using Helm command: | - helm install --namespace kubeovn-system kubeovn /etc/kubernetes/cni/kubeovn-{{ .kubeovn_version }}.tgz + helm upgrade --install --namespace kubeovn-system kubeovn /etc/kubernetes/cni/kubeovn-{{ .kubeovn_version }}.tgz diff --git a/builtin/core/roles/install/cni/multus/tasks/main.yaml b/builtin/core/roles/install/cni/multus/tasks/main.yaml index 5eb2ed56..ef6b9d37 100644 --- a/builtin/core/roles/install/cni/multus/tasks/main.yaml +++ b/builtin/core/roles/install/cni/multus/tasks/main.yaml @@ -1,9 +1,9 @@ --- -- name: Generate multus yaml +- name: Multus | Generate Multus configuration YAML file template: src: multus/multus.yaml - desc: /etc/kubernetes/cni/multus.yaml + dest: /etc/kubernetes/cni/multus.yaml -- name: Apply multus +- name: Multus | Apply Multus configuration to the cluster command: | kubectl apply -f /etc/kubernetes/cni/multus.yaml diff --git a/builtin/core/roles/install/cri/containerd/tasks/main.yaml b/builtin/core/roles/install/cri/containerd/tasks/main.yaml index 282f6007..be0eaa5b 100644 --- a/builtin/core/roles/install/cri/containerd/tasks/main.yaml +++ b/builtin/core/roles/install/cri/containerd/tasks/main.yaml @@ -1,60 +1,62 @@ --- -- name: Check if runc is installed +- name: Containerd | Verify if runc is installed on the system ignore_errors: true command: runc --version register: runc_install_version -- name: Sync runc binary to remote - when: or (.runc_install_version.stderr | empty | not) (.runc_install_version.stdout | contains (printf "runc version %s\n" (.runc_version | default "" | trimPrefix "v" )) | not) + +- name: Containerd | Ensure the runc binary is present on the remote node + when: or (.runc_install_version.error | empty | not) (.runc_install_version.stdout | contains (printf "runc version %s\n" (.runc_version | default "" | trimPrefix "v" )) | not) copy: src: >- {{ .binary_dir }}/runc/{{ .runc_version }}/{{ .binary_type }}/runc.{{ .binary_type }} dest: /usr/local/bin/runc mode: 0755 -- name: Check if containerd is installed +- name: Containerd | Check if containerd is installed on the system ignore_errors: true command: containerd --version register: containerd_install_version -- name: Install containerd - when: or (.containerd_install_version.stderr | empty | not) (.containerd_install_version.stdout | contains (printf " %s " .containerd_version) | not) + +- name: Containerd | Install and configure containerd if not present or version mismatch + when: or (.containerd_install_version.error | empty | not) (.containerd_install_version.stdout | contains (printf " %s " .containerd_version) | not) block: - - name: Sync containerd binary to remote + - name: Containerd | Copy containerd binary archive to the remote node copy: src: >- {{ .binary_dir }}/containerd/{{ .containerd_version }}/{{ .binary_type }}/containerd-{{ .containerd_version | default "" | trimPrefix "v" }}-linux-{{ .binary_type }}.tar.gz dest: >- {{ .tmp_dir }}/containerd-{{ .containerd_version | default "" | trimPrefix "v" }}-linux-{{ .binary_type }}.tar.gz - - name: Unpackage containerd binary + - name: Containerd | Extract containerd binaries to /usr/local/bin command: | tar -xvf {{ .tmp_dir }}/containerd-{{ .containerd_version | default "" | trimPrefix "v" }}-linux-{{ .binary_type }}.tar.gz --strip-components=1 -C /usr/local/bin/ - - name: Generate containerd config file + - name: Containerd | Generate the containerd configuration file template: src: config.toml dest: /etc/containerd/config.toml - - name: Generate containerd Service file + - name: Containerd | Deploy the containerd systemd service file copy: src: containerd.service dest: /etc/systemd/system/containerd.service - - name: Start containerd + - name: Containerd | Start and enable the containerd service command: | systemctl daemon-reload && systemctl start containerd.service && systemctl enable containerd.service -- name: Sync image registry tls to remote +- name: Containerd | Synchronize image registry TLS certificates to the remote node when: .groups.image_registry | default list | empty | not block: - - name: Sync image registry cert file to remote + - name: Containerd | Copy image registry CA certificate to the remote node copy: src: >- {{ .binary_dir }}/pki/root.crt dest: >- /etc/containerd/certs.d/{{ .image_registry.auth.registry }}/ca.crt - - name: Sync image registry cert file to remote + - name: Containerd | Copy image registry server certificate to the remote node copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /etc/containerd/certs.d/{{ .image_registry.auth.registry }}/server.crt - - name: Sync image registry key file to remote + - name: Containerd | Copy image registry server key to the remote node copy: src: >- {{ .binary_dir }}/pki/image_registry.key diff --git a/builtin/core/roles/install/cri/crictl/tasks/main.yaml b/builtin/core/roles/install/cri/crictl/tasks/main.yaml index 4cf02b35..64f955e0 100644 --- a/builtin/core/roles/install/cri/crictl/tasks/main.yaml +++ b/builtin/core/roles/install/cri/crictl/tasks/main.yaml @@ -1,22 +1,22 @@ --- -- name: Check if crictl is installed +- name: Crictl | Verify if crictl is installed on the system ignore_errors: true command: crictl --version register: crictl_install_version -- name: Install crictl - when: or (.crictl_install_version.stderr | empty | not) (.crictl_install_version.stdout | ne (printf "crictl version %s" .crictl_version)) +- name: Crictl | Install and configure crictl if not present or version mismatch + when: or (.crictl_install_version.error | empty | not) (.crictl_install_version.stdout | ne (printf "crictl version %s" .crictl_version)) block: - - name: Sync crictl binary to remote + - name: Crictl | Copy crictl binary archive to the remote node copy: src: >- {{ .binary_dir }}/crictl/{{ .crictl_version }}/{{ .binary_type }}/crictl-{{ .crictl_version }}-linux-{{ .binary_type }}.tar.gz dest: >- {{ .tmp_dir }}/crictl-{{ .crictl_version }}-linux-{{ .binary_type }}.tar.gz - - name: Unpackage crictl binary + - name: Crictl | Extract crictl binary to /usr/local/bin command: | tar -xvf {{ .tmp_dir }}/crictl-{{ .crictl_version }}-linux-{{ .binary_type }}.tar.gz -C /usr/local/bin/ - - name: Generate crictl config file + - name: Crictl | Generate crictl configuration file template: src: crictl.yaml dest: /etc/crictl.yaml diff --git a/builtin/core/roles/install/cri/docker/tasks/cridockerd.yaml b/builtin/core/roles/install/cri/docker/tasks/cridockerd.yaml index 1824b363..d570a0f6 100644 --- a/builtin/core/roles/install/cri/docker/tasks/cridockerd.yaml +++ b/builtin/core/roles/install/cri/docker/tasks/cridockerd.yaml @@ -1,25 +1,25 @@ --- -- name: Check if cri-dockerd is installed +- name: Cridockerd | Check if cri-dockerd is installed on the system ignore_errors: true command: cri-dockerd --version register: cridockerd_install_version -- name: Install cri-dockerd - when: or (.cridockerd_install_version.stderr | empty | not) (.cridockerd_install_version.stdout | hasPrefix (printf "cri-dockerd %s " .cridockerd_version) | not) +- name: Cridockerd | Install and configure cri-dockerd if not present or version mismatch + when: or (.cridockerd_install_version.error | empty | not) (.cridockerd_install_version.stdout | hasPrefix (printf "cri-dockerd %s " .cridockerd_version) | not) block: - - name: Sync cri-dockerd Binary to remote + - name: Cridockerd | Copy cri-dockerd binary archive to the remote node copy: src: >- {{ .binary_dir }}/cri-dockerd/{{ .cridockerd_version }}/{{ .binary_type }}/cri-dockerd-{{ .cridockerd_version | default "" | trimPrefix "v" }}.{{ .binary_type }}.tgz dest: >- {{ .tmp_dir }}/cri-dockerd-{{ .cridockerd_version | default "" | trimPrefix "v" }}.{{ .binary_type }}.tgz - - name: Unpackage cri-dockerd binary + - name: Cridockerd | Extract cri-dockerd binary to /usr/local/bin command: | tar -xvf {{ .tmp_dir }}/cri-dockerd-{{ .cridockerd_version | default "" | trimPrefix "v" }}.{{ .binary_type }}.tgz --strip-components=1 -C /usr/local/bin/ - - name: Generate cri-dockerd Service file + - name: Cridockerd | Generate cri-dockerd systemd service file template: src: cri-dockerd.service dest: /etc/systemd/system/cri-dockerd.service - - name: Start cri-dockerd service + - name: Cridockerd | Start and enable the cri-dockerd service command: | systemctl daemon-reload && systemctl start cri-dockerd.service && systemctl enable cri-dockerd.service diff --git a/builtin/core/roles/install/cri/docker/tasks/main.yaml b/builtin/core/roles/install/cri/docker/tasks/main.yaml index 5235dee1..868531c1 100644 --- a/builtin/core/roles/install/cri/docker/tasks/main.yaml +++ b/builtin/core/roles/install/cri/docker/tasks/main.yaml @@ -1,59 +1,59 @@ --- -# install cridockerd +# Docker | Install cri-dockerd if required for Kubernetes >= v1.24.0 - include_tasks: cridockerd.yaml when: - - .kube_version | semverCompare ">=v1.24.0" + - .kube_version | semverCompare ">=v1.24.0" -- name: Check if docker is installed +- name: Docker | Check if Docker is installed on the system ignore_errors: true command: docker --version register: docker_install_version -- name: Install docker - when: or (.docker_install_version.stderr | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) +- name: Docker | Install and configure Docker if not present or version mismatch + when: or (.docker_install_version.error | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) block: - - name: Sync docker binary to remote + - name: Docker | Copy Docker binary archive to the remote node copy: src: >- {{ .binary_dir }}/docker/{{ .docker_version }}/{{ .binary_type }}/docker-{{ .docker_version }}.tgz dest: >- {{ .tmp_dir }}/docker-{{ .docker_version }}.tgz - - name: Unpackage docker binary + - name: Docker | Extract Docker binaries to /usr/local/bin command: | tar -C /usr/local/bin/ --strip-components=1 -xvf {{ .tmp_dir }}/docker-{{ .docker_version }}.tgz --wildcards docker/* - - name: Generate docker config file + - name: Docker | Generate Docker configuration file template: src: daemon.json dest: /etc/docker/daemon.json - - name: Generate docker service file + - name: Docker | Deploy the Docker systemd service file copy: src: docker.service dest: /etc/systemd/system/docker.service - - name: Generate containerd service file + - name: Docker | Deploy the containerd systemd service file copy: src: containerd.service dest: /etc/systemd/system/containerd.service - - name: Start docker service + - name: Docker | Start and enable Docker and containerd services command: | systemctl daemon-reload && systemctl start containerd.service && systemctl enable containerd.service systemctl daemon-reload && systemctl start docker.service && systemctl enable docker.service -- name: Sync image registry tls to remote +- name: Docker | Synchronize image registry TLS certificates to the remote node when: .groups.image_registry | default list | empty | not block: - - name: Sync image registry cert file to remote + - name: Docker | Copy image registry CA certificate to the remote node copy: src: >- {{ .binary_dir }}/pki/root.crt dest: >- /etc/docker/certs.d/{{ .image_registry.auth.registry }}/ca.crt - - name: Sync image registry cert file to remote + - name: Docker | Copy image registry client certificate to the remote node copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /etc/docker/certs.d/{{ .image_registry.auth.registry }}/client.cert - - name: Sync image registry key file to remote + - name: Docker | Copy image registry client key to the remote node copy: src: >- {{ .binary_dir }}/pki/image_registry.key diff --git a/builtin/core/roles/install/etcd/tasks/backup_etcd.yaml b/builtin/core/roles/install/etcd/tasks/backup_service.yaml similarity index 62% rename from builtin/core/roles/install/etcd/tasks/backup_etcd.yaml rename to builtin/core/roles/install/etcd/tasks/backup_service.yaml index 8c945e51..6975bdd0 100644 --- a/builtin/core/roles/install/etcd/tasks/backup_etcd.yaml +++ b/builtin/core/roles/install/etcd/tasks/backup_service.yaml @@ -1,21 +1,21 @@ --- -- name: Sync custom backup etcd script +- name: Backup | Synchronize custom etcd backup script template: src: >- {{ .etcd.backup.etcd_backup_script }} dest: /usr/local/bin/kube-scripts/backup_etcd.sh mode: 777 -- name: Generate backup etcd service +- name: Backup | Deploy systemd service for etcd backup copy: src: backup.service dest: /etc/systemd/system/backup-etcd.service -- name: Generate backup etcd timer +- name: Backup | Deploy systemd timer for scheduled etcd backup template: src: backup.timer dest: /etc/systemd/system/backup-etcd.timer -- name: Enable etcd timer +- name: Backup | Reload systemd and enable etcd backup timer command: | systemctl daemon-reload && systemctl enable --now backup-etcd.timer diff --git a/builtin/core/roles/install/etcd/tasks/expansion.yaml b/builtin/core/roles/install/etcd/tasks/expansion.yaml new file mode 100644 index 00000000..e2fbea33 --- /dev/null +++ b/builtin/core/roles/install/etcd/tasks/expansion.yaml @@ -0,0 +1,37 @@ +- name: Expansion | Expand cluster on existing etcd nodes + when: .etcd_install_LoadState.stdout | eq "loaded" + block: + - name: Expansion | Update /etc/etcd.env configuration file + template: + src: etcd.env + dest: /etc/etcd.env + - name: Expansion | Restart etcd service + command: | + systemctl restart etcd.service + - name: Expansion | Verify etcd service becomes healthy within 1 minute + command: | + for ((i=1; i<=12; i++)); do + if ETCDCTL_API=3 etcdctl \ + --endpoints=https://localhost:2379 \ + --cacert=/etc/ssl/etcd/ssl/ca.crt \ + --cert=/etc/ssl/etcd/ssl/server.crt \ + --key=/etc/ssl/etcd/ssl/server.key \ + endpoint health >/dev/null 2>&1; then + echo "✅ etcd is health" + exit 0 + fi + sleep 5 + done + echo "❌ etcd etcd is not health in 1 minute" + exit 1 + +- name: Expansion | Add new etcd member from non-installed node + when: .etcd_install_LoadState.stdout | eq "not-found" + delegate_to: "{{ .installed_etcd }}" + command: | + ETCDCTL_API=3 etcdctl \ + --endpoints=https://localhost:2379 \ + --cacert=/etc/ssl/etcd/ssl/ca.crt \ + --cert=/etc/ssl/etcd/ssl/server.crt \ + --key=/etc/ssl/etcd/ssl/server.key \ + member add {{ .inventory_hostname }} \ No newline at end of file diff --git a/builtin/core/roles/install/etcd/tasks/install.yaml b/builtin/core/roles/install/etcd/tasks/install.yaml new file mode 100644 index 00000000..f562ceb5 --- /dev/null +++ b/builtin/core/roles/install/etcd/tasks/install.yaml @@ -0,0 +1,41 @@ +--- +- name: Install | Initialize etcd environment + block: + - name: Install | Create etcd system user + command: | + id etcd &>/dev/null || useradd -M -c 'Etcd user' -s /sbin/nologin -r etcd || : + - name: Install | Create etcd data directory and set ownership + command: | + if [ ! -d "{{ .item }}" ]; then + mkdir -p {{ .item }} && chown -R etcd {{ .item }} + fi + loop: + - "{{ .etcd.env.data_dir }}" + +- name: Install | Generate etcd environment configuration file + template: + src: etcd.env + dest: /etc/etcd.env + +- name: Install | Deploy etcd systemd service file + copy: + src: etcd.service + dest: /etc/systemd/system/etcd.service + +# refer: https://etcd.io/docs/v3.5/tuning/ +- name: Install | Set CPU governor to performance mode + command: | + echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor + when: .etcd.performance + +- name: Install | Configure network traffic priority for etcd + command: | + tc qdisc add dev eth0 root handle 1: prio bands 3 + tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1 + tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1 + tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2379 0xffff flowid 1:1 + tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2379 0xffff flowid 1:1 + when: .etcd.traffic_priority + +- name: Install | Start and enable etcd systemd service + command: systemctl daemon-reload && systemctl start etcd && systemctl enable etcd diff --git a/builtin/core/roles/install/etcd/tasks/install_etcd.yaml b/builtin/core/roles/install/etcd/tasks/install_etcd.yaml deleted file mode 100644 index fc6901c4..00000000 --- a/builtin/core/roles/install/etcd/tasks/install_etcd.yaml +++ /dev/null @@ -1,58 +0,0 @@ ---- -- name: Sync etcd binary to node - copy: - src: >- - {{ .binary_dir }}/etcd/{{ .etcd_version }}/{{ .binary_type }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz - dest: >- - {{ .tmp_dir }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz - -- name: Extract etcd binary - command: | - tar --strip-components=1 -C /usr/local/bin/ -xvf {{ .tmp_dir }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz \ - --wildcards etcd-{{ .etcd_version }}-linux-{{ .binary_type }}/etcd* - -- name: Sync ca file to remote - copy: - src: >- - {{ .binary_dir }}/pki/root.crt - dest: /etc/ssl/etcd/ssl/ca.crt - -- name: Sync etcd cert file to remote - copy: - src: >- - {{ .binary_dir }}/pki/etcd.crt - dest: /etc/ssl/etcd/ssl/server.crt - -- name: Sync etcd key file to remote - copy: - src: >- - {{ .binary_dir }}/pki/etcd.key - dest: /etc/ssl/etcd/ssl/server.key - -- name: Generate etcd env file - template: - src: etcd.env - dest: /etc/etcd.env - -- name: Generate etcd systemd service file - copy: - src: etcd.service - dest: /etc/systemd/system/etcd.service - -# refer: https://etcd.io/docs/v3.5/tuning/ -- name: Set cpu to performance - command: | - echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor - when: .etcd.performance - -- name: Set Traffic Priority - command: | - tc qdisc add dev eth0 root handle 1: prio bands 3 - tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1 - tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1 - tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2379 0xffff flowid 1:1 - tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2379 0xffff flowid 1:1 - when: .etcd.traffic_priority - -- name: Start etcd service - command: systemctl daemon-reload && systemctl start etcd && systemctl enable etcd diff --git a/builtin/core/roles/install/etcd/tasks/main.yaml b/builtin/core/roles/install/etcd/tasks/main.yaml index 1ba9f8ba..1213f3ec 100644 --- a/builtin/core/roles/install/etcd/tasks/main.yaml +++ b/builtin/core/roles/install/etcd/tasks/main.yaml @@ -1,18 +1,20 @@ --- -- name: Install etcd - when: .etcd_install_version.stderr | empty | not +- include_tasks: prepare.yaml + +- name: ETCD | Upgrade etcd if a newer version is available + when: + - .etcd_install_LoadState.stdout | eq "loaded" + - .etcd_version | semverCompare (printf ">v%s" (index .etcd_install_version "stdout" "etcd Version")) + include_tasks: upgrade.yaml + +- name: ETCD | Expand the etcd cluster by adding new nodes if required + when: + - .installed_etcd | empty | not + - .need_installed_etcd | fromJson | empty | not + include_tasks: expansion.yaml + +- name: ETCD | Install etcd and set up the backup service if not already present + when: .etcd_install_LoadState.stdout | eq "not-found" block: - - name: Init etcd - block: - - name: Add etcd user - command: | - id etcd &>/dev/null || useradd -M -c 'Etcd user' -s /sbin/nologin -r etcd - - name: Create etcd directories - command: | - if [ ! -d "{{ .item }}" ]; then - mkdir -p {{ .item }} && chown -R etcd {{ .item }} - fi - loop: - - "{{ .etcd.env.data_dir }}" - - include_tasks: install_etcd.yaml - - include_tasks: backup_etcd.yaml + - include_tasks: install.yaml + - include_tasks: backup_service.yaml diff --git a/builtin/core/roles/install/etcd/tasks/prepare.yaml b/builtin/core/roles/install/etcd/tasks/prepare.yaml new file mode 100644 index 00000000..ea41ef39 --- /dev/null +++ b/builtin/core/roles/install/etcd/tasks/prepare.yaml @@ -0,0 +1,99 @@ + +- name: Prepare | Check etcd.service status in systemd + block: + - name: Prepare | Get etcd.service LoadState and save to variable + command: systemctl show etcd.service -p LoadState --value + register: etcd_install_LoadState + - name: Prepare | Get etcd.service ActiveState and save to variable + command: systemctl show etcd.service -p ActiveState --value + register: etcd_install_ActiveState + - name: Prepare | Ensure installed etcd is running and healthy + when: .etcd_install_LoadState.stdout | eq "loaded" + assert: + that: .etcd_install_ActiveState.stdout | eq "active" + fail_msg: >- + etcd service is installed but not running + +- name: Prepare | Set etcd node parameters + block: + - name: Prepare | Set etcd state to existing if already installed + when: .etcd_install_LoadState.stdout | eq "loaded" + set_fact: + etcd: + state: existing + - name: Prepare | Identify nodes with installed or missing etcd + run_once: true + add_hostvars: + hosts: etcd + vars: + installed_etcd: >- + {{- $needInstalled := list -}} + {{- range .groups.etcd -}} + {{- if (index $.hostvars . "etcd_install_LoadState" "stdout") | eq "loaded" -}} + {{- $needInstalled = append $needInstalled . -}} + {{- end -}} + {{- end -}} + {{ $needInstalled | first | default "" }} + need_installed_etcd: >- + {{- $needInstalled := list -}} + {{- range .groups.etcd -}} + {{- if (index $.hostvars . "etcd_install_LoadState" "stdout") | eq "not-found" -}} + {{- $needInstalled = append $needInstalled . -}} + {{- end -}} + {{- end -}} + {{ $needInstalled | toJson }} + +- name: Prepare | Check installed etcd version + when: .etcd_install_LoadState.stdout | eq "loaded" + block: + - name: Prepare | Get installed etcd version + command: etcd --version + register: etcd_install_version + register_type: yaml + - name: Prepare | Ensure target etcd version is not lower than installed version + when: .etcd_install_LoadState.stdout | eq "loaded" + assert: + that: .etcd_version | semverCompare (printf ">=v%s" (index .etcd_install_version "stdout" "etcd Version")) + fail_msg: >- + Installed etcd version: {{ index .etcd_install_version "stdout" "etcd Version" }} is lower than target etcd version: {{ .etcd_version }} + +- name: Prepare | Synchronize etcd package to node if new install or upgrade + when: + - .etcd_install_version.error | empty + - or (eq .etcd_install_version.stdout "skip") (eq .etcd_version (printf ">=v%s" (index .etcd_install_version "stdout" "etcd Version"))) + block: + - name: Prepare | Copy etcd binary package to remote node + copy: + src: >- + {{ .binary_dir }}/etcd/{{ .etcd_version }}/{{ .binary_type }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz + dest: >- + {{ .tmp_dir }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz + - name: Prepare | Extract etcd binary package to /usr/local/bin/ + command: | + tar --strip-components=1 -C /usr/local/bin/ -xvf {{ .tmp_dir }}/etcd-{{ .etcd_version }}-linux-{{ .binary_type }}.tar.gz \ + --wildcards etcd-{{ .etcd_version }}-linux-{{ .binary_type }}/etcd* + +- name: Prepare | Synchronize certificates to node for new install or expansion + when: >- + or + (eq .etcd_install_version.stdout "skip") + (and + (.installed_etcd | empty | not) + (.need_installed_etcd | fromJson | empty | not) + ) + block: + - name: Prepare | Copy CA certificate to etcd node + copy: + src: >- + {{ .binary_dir }}/pki/root.crt + dest: /etc/ssl/etcd/ssl/ca.crt + - name: Prepare | Copy server certificate to etcd node + copy: + src: >- + {{ .binary_dir }}/pki/etcd.crt + dest: /etc/ssl/etcd/ssl/server.crt + - name: Prepare | Copy server key to etcd node + copy: + src: >- + {{ .binary_dir }}/pki/etcd.key + dest: /etc/ssl/etcd/ssl/server.key diff --git a/builtin/core/roles/install/etcd/tasks/upgrade.yaml b/builtin/core/roles/install/etcd/tasks/upgrade.yaml new file mode 100644 index 00000000..e969b3bd --- /dev/null +++ b/builtin/core/roles/install/etcd/tasks/upgrade.yaml @@ -0,0 +1,23 @@ +- name: Upgrade | Backup etcd data before upgrade + command: BACKUP_DIR="{{ .etcd.backup.backup_dir }}/install/etcd-v{{ index .etcd_install_version "stdout" "etcd Version" }}-$(date +%Y-%m-%d-%H-%M-%S)" /usr/local/bin/kube-scripts/backup_etcd.sh + +- name: Upgrade | Restart etcd service after upgrade + command: | + systemctl restart etcd.service + +- name: Upgrade | Ensure etcd service becomes healthy within 1 minute + command: | + for ((i=1; i<=12; i++)); do + if ETCDCTL_API=3 etcdctl \ + --endpoints=https://localhost:2379 \ + --cacert=/etc/ssl/etcd/ssl/ca.crt \ + --cert=/etc/ssl/etcd/ssl/server.crt \ + --key=/etc/ssl/etcd/ssl/server.key \ + endpoint health >/dev/null 2>&1; then + echo "✅ etcd is healthy" + exit 0 + fi + sleep 5 + done + echo "❌ etcd is not healthy within 1 minute" + exit 1 diff --git a/builtin/core/roles/install/etcd/templates/backup.sh b/builtin/core/roles/install/etcd/templates/backup.sh index 98bdae7b..20e64ec5 100644 --- a/builtin/core/roles/install/etcd/templates/backup.sh +++ b/builtin/core/roles/install/etcd/templates/backup.sh @@ -11,7 +11,7 @@ ENDPOINTS='https://{{ .internal_ipv4 }}:2379' ENDPOINTS='https://{{ .internal_ipv6 }}:2379' {{- end }} ETCD_DATA_DIR="{{ .etcd.env.data_dir }}" -BACKUP_DIR="{{ .etcd.backup.backup_dir }}/etcd-$(date +%Y-%m-%d-%H-%M-%S)" +BACKUP_DIR="${BACKUP_DIR:-{{ .etcd.backup.backup_dir }}/timer/etcd-$(date +%Y-%m-%d-%H-%M-%S)}" KEEPBACKUPNUMBER='{{ .etcd.backup.keep_backup_number }}' ((KEEPBACKUPNUMBER++)) @@ -21,7 +21,7 @@ ETCDCTL_CA_FILE="/etc/ssl/etcd/ssl/ca.crt" [ ! -d $BACKUP_DIR ] && mkdir -p $BACKUP_DIR -export ETCDCTL_API=2;$ETCDCTL_PATH backup --data-dir $ETCD_DATA_DIR --backup-dir $BACKUP_DIR +export ETCDCTL_API=3;$ETCDCTL_PATH backup --data-dir $ETCD_DATA_DIR --backup-dir $BACKUP_DIR sleep 3 diff --git a/builtin/core/roles/install/image-registry/docker-compose/tasks/docker.yaml b/builtin/core/roles/install/image-registry/docker-compose/tasks/docker.yaml index b3dca9c1..cdbc5610 100644 --- a/builtin/core/roles/install/image-registry/docker-compose/tasks/docker.yaml +++ b/builtin/core/roles/install/image-registry/docker-compose/tasks/docker.yaml @@ -1,34 +1,34 @@ --- -- name: Check if docker is installed +- name: Docker | Check if Docker is installed on the system ignore_errors: true command: docker --version register: docker_install_version -- name: Install docker - when: or (.docker_install_version.stderr | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) +- name: Docker | Install and configure Docker if not present or version mismatch + when: or (.docker_install_version.error | empty | not) (.docker_install_version.stdout | hasPrefix (printf "Docker version %s," .docker_version) | not) block: - - name: Sync docker binary to remote + - name: Docker | Copy Docker binary archive to the remote node copy: src: >- {{ .binary_dir }}/docker/{{ .docker_version }}/{{ .binary_type }}/docker-{{ .docker_version }}.tgz dest: >- {{ .tmp_dir }}/docker-{{ .docker_version }}.tgz - - name: Generate docker config file + - name: Docker | Generate Docker configuration file template: src: daemon.json dest: /etc/docker/daemon.json - - name: Unpackage docker binary + - name: Docker | Extract Docker binaries to /usr/local/bin command: | tar -C /usr/local/bin/ --strip-components=1 -xvf {{ .tmp_dir }}/docker-{{ .docker_version }}.tgz --wildcards docker/* - - name: Generate docker service file + - name: Docker | Deploy the Docker systemd service file copy: src: docker.service dest: /etc/systemd/system/docker.service - - name: Generate containerd service file + - name: Docker | Deploy the containerd systemd service file copy: src: containerd.service dest: /etc/systemd/system/containerd.service - - name: Start docker service + - name: Docker | Start and enable Docker and containerd services command: | systemctl daemon-reload && systemctl start containerd.service && systemctl enable containerd.service systemctl daemon-reload && systemctl start docker.service && systemctl enable docker.service diff --git a/builtin/core/roles/install/image-registry/docker-compose/tasks/docker_compose.yaml b/builtin/core/roles/install/image-registry/docker-compose/tasks/docker_compose.yaml deleted file mode 100644 index 8ded52be..00000000 --- a/builtin/core/roles/install/image-registry/docker-compose/tasks/docker_compose.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -- name: Check if docker-compose is installed - ignore_errors: true - command: docker-compose --version - register: dockercompose_install_version - -- name: Sync docker-compose to remote - when: or (.dockercompose_install_version.stderr | empty | not) (.dockercompose_install_version.stdout | ne (printf "Docker Compose version %s" .dockercompose_version)) - copy: - src: >- - {{ .binary_dir }}/image-registry/docker-compose/{{ .dockercompose_version }}/{{ .binary_type }}/docker-compose - dest: /usr/local/bin/docker-compose - mode: 0755 diff --git a/builtin/core/roles/install/image-registry/docker-compose/tasks/main.yaml b/builtin/core/roles/install/image-registry/docker-compose/tasks/main.yaml index 1c430e41..7a106f1a 100644 --- a/builtin/core/roles/install/image-registry/docker-compose/tasks/main.yaml +++ b/builtin/core/roles/install/image-registry/docker-compose/tasks/main.yaml @@ -1,4 +1,15 @@ --- - include_tasks: docker.yaml -- include_tasks: docker_compose.yaml \ No newline at end of file +- name: DockerCompose | Verify if Docker Compose is installed on the system + ignore_errors: true + command: docker-compose --version + register: dockercompose_install_version + +- name: DockerCompose | Install or update Docker Compose if not present or version mismatch + when: or (.dockercompose_install_version.error | empty | not) (.dockercompose_install_version.stdout | ne (printf "Docker Compose version %s" .dockercompose_version)) + copy: + src: >- + {{ .binary_dir }}/image-registry/docker-compose/{{ .dockercompose_version }}/{{ .binary_type }}/docker-compose + dest: /usr/local/bin/docker-compose + mode: 0755 \ No newline at end of file diff --git a/builtin/core/roles/install/image-registry/docker-registry/tasks/main.yaml b/builtin/core/roles/install/image-registry/docker-registry/tasks/main.yaml index 24a43ae0..766de93d 100644 --- a/builtin/core/roles/install/image-registry/docker-registry/tasks/main.yaml +++ b/builtin/core/roles/install/image-registry/docker-registry/tasks/main.yaml @@ -1,12 +1,12 @@ --- -- name: Sync registry image to remote +- name: DockerRegistry | Synchronize registry image archive to remote host copy: src: >- {{ .binary_dir }}/image-registry/docker-registry/{{ .docker_registry_version }}/{{ .binary_type }}/docker-registry-{{ .docker_registry_version }}-linux-{{ .binary_type }}.tgz dest: >- /opt/docker-registry/{{ .docker_registry_version }}/docker-registry-{{ .docker_registry_version }}-linux-{{ .binary_type }}.tgz -- name: Mount NFS dir +- name: DockerRegistry | Ensure NFS directory is mounted for registry storage command: | {{- if .os.release.ID_LIKE | eq "debian" }} yum update && yum install -y nfs-utils @@ -26,47 +26,47 @@ - .image_registry.docker_registry.storage.filesystem.nfs_mount | empty | not - .groups.nfs | default list | len | eq 1 -- name: Load registry image +- name: DockerRegistry | Load registry image into Docker command: | docker load -i /opt/docker-registry/{{ .docker_registry_version }}/docker-registry-{{ .docker_registry_version }}-linux-{{ .binary_type }}.tgz -- name: Sync image registry cert file to remote +- name: DockerRegistry | Synchronize registry certificate to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /opt/docker-registry/{{ .docker_registry_version }}/ssl/server.crt -- name: Sync image registry key file to remote +- name: DockerRegistry | Synchronize registry private key to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.key dest: >- /opt/docker-registry/{{ .docker_registry_version }}/ssl/server.key -- name: Generate registry docker compose +- name: DockerRegistry | Generate Docker Compose file for registry template: src: docker-compose.yaml dest: >- /opt/docker-registry/{{ .docker_registry_version }}/docker-compose.yml -- name: Generate registry config +- name: DockerRegistry | Generate registry configuration file template: src: config.yaml dest: >- /opt/docker-registry/{{ .docker_registry_version }}/config.yml -- name: Register registry service +- name: DockerRegistry | Register registry as a systemd service template: src: docker-registry.service dest: /etc/systemd/system/docker-registry.service -- name: Start registry service +- name: DockerRegistry | Start and enable registry systemd service command: systemctl daemon-reload && systemctl start docker-registry.service && systemctl enable docker-registry.service -- name: wait registry service ready +- name: DockerRegistry | Wait for registry service to become available command: | if ! timeout 300 bash -c 'while ! nc -zv localhost 443; do sleep 2; done'; then - echo "ERROR: Harbor did not start within 5 minutes!" + echo "ERROR: Docker Registry did not start within 5 minutes!" exit 1 fi diff --git a/builtin/core/roles/install/image-registry/harbor/tasks/main.yaml b/builtin/core/roles/install/image-registry/harbor/tasks/main.yaml index 845f36fe..ee7cef88 100644 --- a/builtin/core/roles/install/image-registry/harbor/tasks/main.yaml +++ b/builtin/core/roles/install/image-registry/harbor/tasks/main.yaml @@ -1,53 +1,53 @@ --- -- name: Sync harbor package to remote +- name: Harbor | Synchronize Harbor offline package to remote host copy: src: >- {{ .binary_dir }}/image-registry/harbor/{{ .harbor_version }}/{{ .binary_type }}/harbor-offline-installer-{{ .harbor_version }}.tgz dest: >- /opt/harbor/{{ .harbor_version }}/harbor-offline-installer-{{ .harbor_version }}.tgz -- name: Untar harbor package +- name: Harbor | Extract Harbor offline package command: | cd /opt/harbor/{{ .harbor_version }}/ && tar -zxvf harbor-offline-installer-{{ .harbor_version }}.tgz -- name: Sync image registry cert file to remote +- name: Harbor | Synchronize image registry certificate to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.crt dest: >- /opt/harbor/{{ .harbor_version }}/ssl/server.crt -- name: Sync image registry key file to remote +- name: Harbor | Synchronize image registry private key to remote host copy: src: >- {{ .binary_dir }}/pki/image_registry.key dest: >- /opt/harbor/{{ .harbor_version }}/ssl/server.key -- name: Generate harbor config +- name: Harbor | Generate Harbor configuration file template: src: harbor.yml dest: >- /opt/harbor/{{ .harbor_version }}/harbor/harbor.yml -- name: Install harbor +- name: Harbor | Install Harbor registry command: | cd /opt/harbor/{{ .harbor_version }}/harbor && /bin/bash install.sh -- name: Register harbor service +- name: Harbor | Register Harbor as a systemd service template: src: harbor.service dest: /etc/systemd/system/harbor.service -- name: Start harbor service +- name: Harbor | Start and enable Harbor service command: systemctl daemon-reload && systemctl start harbor.service && systemctl enable harbor.service -- name: HA harbor sync images +- name: Harbor | Configure HA and synchronize Harbor images when: - .image_registry.ha_vip | empty | not - .groups.image_registry | len | lt 1 block: - - name: add keepalived service to docker-compose + - name: Harbor | Add keepalived service to Harbor docker-compose command: | KEEPALIVED_SERVICE='# keepalived is generated by kubekey. keepalived: @@ -86,17 +86,16 @@ { print } ' "$TARGET_FILE" > "$TMP_FILE" && mv "$TMP_FILE" "$TARGET_FILE" systemctl restart harbor.service - - name: wait harbor service ready + - name: Harbor | Wait for Harbor service to become ready command: | if ! timeout 300 bash -c 'while ! nc -zv localhost 443; do sleep 2; done'; then echo "ERROR: Harbor did not start within 5 minutes!" exit 1 fi - - name: sync harbor-replications scripts to remote + - name: Harbor | Synchronize harbor-replications script to remote host template: src: harbor-replications.sh dest: /opt/harbor/scripts/harbor-replications.sh mode: 0755 - - name: execute harbor-replications.sh - command: bash /opt/harbor/scripts/harbor-replications.sh - \ No newline at end of file + - name: Harbor | Execute harbor-replications script + command: bash /opt/harbor/scripts/harbor-replications.sh \ No newline at end of file diff --git a/builtin/core/roles/install/image-registry/keepalived/tasks/main.yaml b/builtin/core/roles/install/image-registry/keepalived/tasks/main.yaml index df12d1c8..1ef1db44 100644 --- a/builtin/core/roles/install/image-registry/keepalived/tasks/main.yaml +++ b/builtin/core/roles/install/image-registry/keepalived/tasks/main.yaml @@ -1,7 +1,7 @@ --- -- name: Get interface from ha_vip +- name: Keepalived | Discover network interface for HA VIP block: - - name: Get all interface with cidr + - name: Keepalived | Gather all network interfaces with CIDR addresses command: | ip -o addr show | awk ' BEGIN { @@ -24,40 +24,40 @@ ' register: interface register_type: json - - name: filter interface by ha_vip + - name: Keepalived | Select interface matching HA VIP set_fact: - ha_vip_interface: >- - {{- $interface := "" }} - {{- range .interface.stdout | default list -}} - {{- if .cidr | ipInCIDR | has $.image_registry.ha_vip -}} - {{- $interface = .interface -}} - {{- end -}} + ha_vip_interface: >- + {{- $interface := "" }} + {{- range .interface.stdout | default list -}} + {{- if .cidr | ipInCIDR | has $.image_registry.ha_vip -}} + {{- $interface = .interface -}} {{- end -}} - {{ $interface }} - - name: Check if network is exist + {{- end -}} + {{ $interface }} + - name: Keepalived | Ensure matching network interface exists assert: that: .kube_vip_interface | empty - fail_msg: "cannot find network interface to match ha_vip" + fail_msg: "Cannot find a network interface that matches the HA VIP." -- name: Sync keepalived image to remote +- name: Keepalived | Synchronize keepalived image to remote host copy: src: >- {{ .binary_dir }}/image-registry/keepalived/{{ .keepalived_version }}/{{ .binary_type }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz dest: >- /opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz -- name: Load keeplived image +- name: Keepalived | Load keepalived image into Docker command: | docker load -i /opt/keepalived/{{ .keepalived_version }}/keepalived-{{ .keepalived_version }}-linux-{{ .binary_type }}.tgz -- name: Sync keeplived config to remote +- name: Keepalived | Synchronize keepalived configuration file to remote host template: src: keepalived.conf dest: >- /opt/keepalived/{{ .keepalived_version }}/keepalived.conf mode: 0664 -- name: Sync healthcheck shell to remote +- name: Keepalived | Synchronize healthcheck script to remote host copy: src: healthcheck.sh dest: >- diff --git a/builtin/core/roles/install/image-registry/tasks/main.yaml b/builtin/core/roles/install/image-registry/tasks/main.yaml index 8e1ffac8..65964fee 100644 --- a/builtin/core/roles/install/image-registry/tasks/main.yaml +++ b/builtin/core/roles/install/image-registry/tasks/main.yaml @@ -1,5 +1,5 @@ --- -- name: Sync images to remote +- name: ImageRegistry | Synchronize images to remote host tags: ["only_image"] copy: src: >- @@ -7,24 +7,24 @@ dest: >- {{ .image_registry.images_dir }} -- name: Create harbor project for each image +- name: ImageRegistry | Ensure Harbor project exists for each image tags: ["only_image"] command: | - # Iterate through first-level subdirectories in images_dir (skip blobs) + # Traverse first-level subdirectories in images_dir, skipping 'blobs' for registry_dir in {{ .image_registry.images_dir }}*; do if [ ! -d "$registry_dir" ] || [ "$(basename "$registry_dir")" = "blobs" ]; then continue fi - - # Iterate through second-level subdirectories in registry_dir + + # Traverse second-level subdirectories in each registry_dir for project_dir in "$registry_dir"/*; do if [ ! -d "$project_dir" ]; then continue fi - + project=$(basename "$project_dir") - - # Check if project exists, create if not + + # Check if the Harbor project exists; create it if it does not resp=$(curl -u "{{ .image_registry.auth.username }}:{{ .image_registry.auth.password }}" -k -X GET "https://{{ .image_registry.auth.registry }}/api/v2.0/projects/${project}") if echo "$resp" | grep -q '"code":"NOT_FOUND"'; then curl -u "{{ .image_registry.auth.username }}:{{ .image_registry.auth.password }}" -k -X POST \ @@ -36,7 +36,7 @@ done when: .image_registry.type | eq "harbor" -- name: Sync images package to image_registry +- name: ImageRegistry | Push images package to image registry tags: ["only_image"] image: push: diff --git a/builtin/core/roles/install/nfs/tasks/main.yaml b/builtin/core/roles/install/nfs/tasks/main.yaml index 3f77c6e1..a3cd9120 100644 --- a/builtin/core/roles/install/nfs/tasks/main.yaml +++ b/builtin/core/roles/install/nfs/tasks/main.yaml @@ -1,10 +1,10 @@ --- -- name: Generate nfs config +- name: NFS | Generate NFS server export configuration template: src: exports dest: /etc/exports -- name: Create share directory +- name: NFS | Ensure NFS share directories exist with correct permissions loop: "{{ .nfs.share_dir | toJson }}" command: | if [ ! -d {{ .item }} ]; then @@ -13,11 +13,11 @@ chown nobody:nobody {{ .item }} fi -- name: Export share directory and start nfs server +- name: NFS | Export share directories and start NFS server service command: | exportfs -a {{- if .os.release.ID_LIKE | eq "debian" }} systemctl enable nfs-kernel-server && systemctl restart nfs-kernel-server {{- else if .os.release.ID_LIKE | eq "rhel fedora"}} - systemctl enable nfs-server.service && systemctl restart nfs-server.service + systemctl enable nfs-server.service && systemctl restart nfs-server.service {{- end }} \ No newline at end of file diff --git a/builtin/core/roles/install/security/tasks/main.yaml b/builtin/core/roles/install/security/tasks/main.yaml index 78b829e3..e549883e 100644 --- a/builtin/core/roles/install/security/tasks/main.yaml +++ b/builtin/core/roles/install/security/tasks/main.yaml @@ -1,5 +1,5 @@ --- -- name: security enhancement for etcd +- name: Security | Enhance etcd node security permissions command: | chmod 700 /etc/ssl/etcd/ssl && chown root:root /etc/ssl/etcd/ssl chmod 600 /etc/ssl/etcd/ssl/* && chown root:root /etc/ssl/etcd/ssl/* @@ -7,7 +7,7 @@ chmod 550 /usr/local/bin/etcd* && chown root:root /usr/local/bin/etcd* when: .groups.etcd | default list | has .inventory_hostname -- name: security enhancement for control plane +- name: Security | Apply security best practices for control plane nodes command: | chmod 644 /etc/kubernetes && chown root:root /etc/kubernetes chmod 600 -R /etc/kubernetes && chown root:root -R /etc/kubernetes/* @@ -23,7 +23,7 @@ chmod 640 /etc/systemd/system/k8s-certs-renew* && chown root:root /etc/systemd/system/k8s-certs-renew* when: .groups.kube_control_plane | default list | has .inventory_hostname -- name: security enhancement for worker +- name: Security | Apply security best practices for worker nodes command: | chmod 644 /etc/kubernetes && chown root:root /etc/kubernetes chmod 600 -R /etc/kubernetes && chown root:root -R /etc/kubernetes/* @@ -36,4 +36,4 @@ chmod 550 -R /opt/cni/bin && chown root:root -R /opt/cni/bin chmod 640 /var/lib/kubelet/config.yaml && chown root:root /var/lib/kubelet/config.yaml chmod 640 -R /etc/systemd/system/kubelet.service* && chown root:root -R /etc/systemd/system/kubelet.service* - when: .groups.kube_worker | default list | has .inventory_hostname + when: .groups.kube_worker | default list | has .inventory_hostname diff --git a/builtin/core/roles/install/storageclass/local/tasks/main.yaml b/builtin/core/roles/install/storageclass/local/tasks/main.yaml index 4b09e706..ea63ec15 100644 --- a/builtin/core/roles/install/storageclass/local/tasks/main.yaml +++ b/builtin/core/roles/install/storageclass/local/tasks/main.yaml @@ -1,9 +1,9 @@ --- -- name: Generate local manifest +- name: Local | Generate the local storage manifest template: src: local-volume.yaml dest: /etc/kubernetes/addons/local-volume.yaml -- name: deploy local +- name: Local | Deploy the local storage manifest command: | kubectl apply -f /etc/kubernetes/addons/local-volume.yaml diff --git a/builtin/core/roles/install/storageclass/nfs/tasks/main.yaml b/builtin/core/roles/install/storageclass/nfs/tasks/main.yaml index aae3288f..cc0343b7 100644 --- a/builtin/core/roles/install/storageclass/nfs/tasks/main.yaml +++ b/builtin/core/roles/install/storageclass/nfs/tasks/main.yaml @@ -1,12 +1,12 @@ --- -- name: Sync nfs provisioner helm to remote +- name: NFS | Synchronize NFS provisioner Helm chart to remote host copy: src: >- {{ .work_dir }}/kubekey/sc/nfs-subdir-external-provisioner-{{ .nfs_provisioner_version }}.tgz dest: >- /etc/kubernetes/addons/nfs-subdir-external-provisioner-{{ .nfs_provisioner_version }}.tgz -- name: Deploy nfs provisioner +- name: NFS | Deploy the NFS provisioner using Helm command: | helm upgrade --install nfs-subdir-external-provisioner /etc/kubernetes/addons/nfs-subdir-external-provisioner-{{ .nfs_provisioner_version }}.tgz --namespace kube-system \ --set nfs.server={{ .sc.nfs.server }} --set nfs.path={{ .sc.nfs.path }} \ diff --git a/builtin/core/roles/kubernetes/certs/tasks/main.yaml b/builtin/core/roles/kubernetes/certs/tasks/main.yaml index bb615344..70127d86 100644 --- a/builtin/core/roles/kubernetes/certs/tasks/main.yaml +++ b/builtin/core/roles/kubernetes/certs/tasks/main.yaml @@ -1,20 +1,19 @@ --- -- name: Generate renew script +- name: Certs | Generate Kubernetes certificate renewal script template: src: renew_script.sh dest: /usr/local/bin/kube-scripts/renew_script.sh mode: 0755 -- name: Sync renew service +- name: Certs | Deploy certificate renewal systemd service copy: src: k8s-certs-renew.service dest: /etc/systemd/system/k8s-certs-renew.service -- name: Sync renew timer +- name: Certs | Deploy certificate renewal systemd timer copy: src: k8s-certs-renew.timer dest: /etc/systemd/system/k8s-certs-renew.timer -- name: Enable renew service - command: - systemctl daemon-reload && systemctl enable --now k8s-certs-renew.timer +- name: Certs | Enable and start certificate renewal timer + command: systemctl daemon-reload && systemctl enable --now k8s-certs-renew.timer diff --git a/builtin/core/roles/kubernetes/init-kubernetes/tasks/deploy_cluster_dns.yaml b/builtin/core/roles/kubernetes/init-kubernetes/tasks/deploy_cluster_dns.yaml index 9dd81ffb..c3072c2a 100644 --- a/builtin/core/roles/kubernetes/init-kubernetes/tasks/deploy_cluster_dns.yaml +++ b/builtin/core/roles/kubernetes/init-kubernetes/tasks/deploy_cluster_dns.yaml @@ -1,21 +1,20 @@ --- -- name: Generate coredns config +- name: DNS | Generate CoreDNS configuration file template: src: dns/coredns.yaml dest: /etc/kubernetes/coredns.yaml -# change clusterIP for service -# change configmap for coredns -- name: Apply coredns config +# Update the clusterIP for the service and modify the CoreDNS ConfigMap as needed +- name: DNS | Apply CoreDNS configuration and restart deployment command: | kubectl delete svc kube-dns -n kube-system kubectl apply -f /etc/kubernetes/coredns.yaml && kubectl rollout restart deployment -n kube-system coredns -- name: Generate nodelocaldns daemonset +- name: DNS | Generate NodeLocalDNS DaemonSet manifest template: src: dns/nodelocaldns.yaml dest: /etc/kubernetes/nodelocaldns.yaml -- name: Apply nodelocaldns daemonset +- name: DNS | Deploy NodeLocalDNS DaemonSet command: | kubectl apply -f /etc/kubernetes/nodelocaldns.yaml diff --git a/builtin/core/roles/kubernetes/init-kubernetes/tasks/init_kubernetes.yaml b/builtin/core/roles/kubernetes/init-kubernetes/tasks/init_kubernetes.yaml index 3b922eb1..bb545dbf 100644 --- a/builtin/core/roles/kubernetes/init-kubernetes/tasks/init_kubernetes.yaml +++ b/builtin/core/roles/kubernetes/init-kubernetes/tasks/init_kubernetes.yaml @@ -1,29 +1,5 @@ --- -- name: Sync external etcd config - when: - - and (.kubernetes.etcd.deployment_type | eq "external") (.groups.etcd | default list | empty | not) - - .groups.kube_control_plane | default list | has .inventory_hostname - block: - - name: Sync etcd ca file to remote - copy: - src: >- - {{ .work_dir }}/kubekey/pki/root.crt - dest: /etc/kubernetes/pki/etcd/ca.crt - mode: 0755 - - name: Sync etcd cert files to remote - copy: - src: >- - {{ .work_dir }}/kubekey/pki/etcd.crt - dest: /etc/kubernetes/pki/etcd/client.crt - mode: 0755 - - name: Sync etcd key files to remote - copy: - src: >- - {{ .work_dir }}/kubekey/pki/etcd.key - dest: /etc/kubernetes/pki/etcd/client.key - mode: 0755 - -- name: Generate kubeadm init config +- name: Init | Generate kubeadm initialization configuration template: src: >- {{- if .kube_version | semverCompare ">=v1.24.0" -}} @@ -33,19 +9,19 @@ {{- end -}} dest: /etc/kubernetes/kubeadm-config.yaml -- name: Init kubernetes cluster +- name: Init | Initialize Kubernetes cluster block: - - name: pre init + - name: Init | Pre-initialization for kube-vip when: - .kube_version | semverCompare ">=v1.29.0" - eq .kubernetes.control_plane_endpoint.type "kube_vip" command: | sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' \ /etc/kubernetes/manifests/kube-vip.yaml - - name: init + - name: Init | Run kubeadm init command: | /usr/local/bin/kubeadm init --config=/etc/kubernetes/kubeadm-config.yaml --ignore-preflight-errors=FileExisting-crictl,ImagePull {{ if not .kubernetes.kube_proxy.enabled }}--skip-phases=addon/kube-proxy{{ end }} - - name: post init + - name: Init | Post-initialization for kube-vip when: - .kube_version | semverCompare ">=v1.29.0" - eq .kubernetes.control_plane_endpoint.type "kube_vip" @@ -53,9 +29,10 @@ sed -i 's#path: /etc/kubernetes/super-admin.conf#path: /etc/kubernetes/admin.conf#' \ /etc/kubernetes/manifests/kube-vip.yaml -# reset localDNS 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }}. -# if not the control_plane_endpoint will valid after kube_vip pod running. the task which will execute kubectl apply in current node may be failed. -- name: reset control_plane_endpoint localDNS +# Reset local DNS for control_plane_endpoint to 127.0.0.1 and ::1. +# This ensures the control_plane_endpoint resolves locally before kube-vip is running, +# preventing failures for tasks that execute kubectl apply on the current node. +- name: Init | Reset local DNS for control_plane_endpoint command: | sed -i ':a;$!{N;ba};s@# kubekey control_plane_endpoint BEGIN.*# kubekey control_plane_endpoint END@@' {{ .item }} cat >> {{ .item }} <- {{ .work_dir }}/kubekey/kubeconfig - - name: Generate certificate key by kubeadm + - name: InitKubernetes | Generate certificate key using kubeadm command: | /usr/local/bin/kubeadm init phase upload-certs --upload-certs --config=/etc/kubernetes/kubeadm-config.yaml 2>&1 \ | awk '/Using certificate key:/{getline; print}' register: kubeadm_cert_result - - name: add certificate key to all hosts + - name: InitKubernetes | Distribute certificate key to all cluster hosts add_hostvars: hosts: k8s_cluster vars: kubeadm_cert: >- {{ .kubeadm_cert_result.stdout }} - - name: Generate kubeadm token + - name: InitKubernetes | Generate and distribute kubeadm token block: - - name: Generate token by kubeadm + - name: InitKubernetes | Generate kubeadm join token command: /usr/local/bin/kubeadm token create register: kubeadm_token_result - - name: add token to all hosts + - name: InitKubernetes | Share kubeadm token with all cluster hosts add_hostvars: hosts: k8s_cluster vars: diff --git a/builtin/core/roles/kubernetes/join-kubernetes/tasks/join_kubernetes.yaml b/builtin/core/roles/kubernetes/join-kubernetes/tasks/join_kubernetes.yaml index 4e99f06d..ddc3f6e0 100644 --- a/builtin/core/roles/kubernetes/join-kubernetes/tasks/join_kubernetes.yaml +++ b/builtin/core/roles/kubernetes/join-kubernetes/tasks/join_kubernetes.yaml @@ -1,5 +1,5 @@ --- -- name: Generate kubeadm join config +- name: Join | Generate kubeadm join configuration file template: src: >- {{- if .kube_version | semverCompare ">=v1.24.0" -}} @@ -9,38 +9,39 @@ {{- end -}} dest: /etc/kubernetes/kubeadm-config.yaml -- name: Join kubernetes cluster +- name: Join | Execute kubeadm join to add node to the Kubernetes cluster command: | /usr/local/bin/kubeadm join --config=/etc/kubernetes/kubeadm-config.yaml --ignore-preflight-errors=FileExisting-crictl,ImagePull -- name: Sync kubeconfig to remote +- name: Join | Synchronize kubeconfig to remote node copy: src: >- {{ .work_dir }}/kubekey/kubeconfig dest: /root/.kube/config -- name: Set to worker node +- name: Join | Configure node as worker when: .groups.kube_worker | default list | has .inventory_hostname block: - - name: Remote master taint + - name: Join | Remove master and control-plane taints from node ignore_errors: true command: | /usr/local/bin/kubectl taint nodes {{ .hostname }} node-role.kubernetes.io/master=:NoSchedule- /usr/local/bin/kubectl taint nodes {{ .hostname }} node-role.kubernetes.io/control-plane=:NoSchedule- - - name: Add work label + - name: Join | Add worker label to node command: | /usr/local/bin/kubectl label --overwrite node {{ .hostname }} node-role.kubernetes.io/worker= -- name: Add annotations +- name: Join | Add custom annotations to node when: .annotations | empty | not command: | kubectl annotate {{ .hostname }} {{- range $k,$v := .annotations }}{{ printf "%s=%s" $k $v}} {{- end }} -# reset localDNS 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }}. -# if not the control_plane_endpoint will valid after kube_vip pod running. the task which will execute kubectl apply in current node may be failed. -- name: reset control_plane_endpoint localDNS +# Reset local DNS for control_plane_endpoint to 127.0.0.1 and ::1. +# This ensures the control_plane_endpoint resolves locally before kube-vip is running, +# preventing failures for tasks that execute kubectl apply on the current node. +- name: Join | Reset local DNS for control_plane_endpoint block: - - name: reset control_plane localDNS + - name: Join | Reset local DNS on control plane nodes when: - .groups.kube_control_plane | default list | has .inventory_hostname command: | @@ -52,7 +53,7 @@ # kubekey control_plane_endpoint END EOF loop: "{{ .localDNS | toJson }}" - - name: reset worker localDNS + - name: Join | Reset local DNS on worker nodes (for haproxy endpoint) when: - .groups.kube_worker | default list | has .inventory_hostname - .kubernetes.control_plane_endpoint.type | eq "haproxy" diff --git a/builtin/core/roles/kubernetes/join-kubernetes/tasks/main.yaml b/builtin/core/roles/kubernetes/join-kubernetes/tasks/main.yaml index f82b2b49..056d85aa 100644 --- a/builtin/core/roles/kubernetes/join-kubernetes/tasks/main.yaml +++ b/builtin/core/roles/kubernetes/join-kubernetes/tasks/main.yaml @@ -1,4 +1,4 @@ - include_tasks: join_kubernetes.yaml when: - ne .inventory_hostname .init_kubernetes_node - - .kubernetes_install_service.stdout | eq "inactive" + - .kubernetes_install_LoadState.stdout | eq "not-found" diff --git a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/haproxy.yaml b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/haproxy.yaml index cfc5b8c8..cf827e26 100644 --- a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/haproxy.yaml +++ b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/haproxy.yaml @@ -1,15 +1,15 @@ --- -- name: Generate haproxy config +- name: Haproxy | Generate HAProxy configuration file template: src: haproxy/haproxy.cfg dest: /etc/kubekey/haproxy/haproxy.cfg -- name: Get md5 for haproxy config +- name: Haproxy | Calculate MD5 checksum of HAProxy configuration command: | md5sum /etc/kubekey/haproxy/haproxy.cfg | cut -d" " -f1 register: haproxy_cfg_md5 -- name: Genrate haproxy manifest +- name: Haproxy | Generate HAProxy manifest for Kubernetes template: src: haproxy/haproxy.yaml dest: /etc/kubernetes/manifests/haproxy.yaml diff --git a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/kube_vip.yaml b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/kube_vip.yaml index 19a3ddbf..43687076 100644 --- a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/kube_vip.yaml +++ b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/kube_vip.yaml @@ -1,7 +1,7 @@ --- -- name: Get interface from kube_vip +- name: Kubevip | Discover network interface for kube-vip block: - - name: Get all interface with cidr + - name: Kubevip | Gather all network interfaces with CIDR addresses command: | ip -o addr show | awk ' BEGIN { @@ -24,22 +24,22 @@ ' register: interface register_type: json - - name: filter interface by ha_vip + - name: Kubevip | Select network interface matching kube-vip address set_fact: - kube_vip_interface: >- - {{- $interface := "" }} - {{- range .interface.stdout | default list -}} - {{- if .cidr | ipInCIDR | has $.kubernetes.control_plane_endpoint.kube_vip.address -}} - {{- $interface = .interface -}} - {{- end -}} + kube_vip_interface: >- + {{- $interface := "" }} + {{- range .interface.stdout | default list -}} + {{- if .cidr | ipInCIDR | has $.kubernetes.control_plane_endpoint.kube_vip.address -}} + {{- $interface = .interface -}} {{- end -}} - {{ $interface }} - - name: Check if network is exist + {{- end -}} + {{ $interface }} + - name: Kubevip | Ensure matching network interface exists assert: that: .kube_vip_interface | empty - fail_msg: "cannot find network interface to match kube_vip" + fail_msg: "Kubevip: Unable to find a network interface matching the kube-vip address." -- name: Generate kube_vip manifest +- name: Kubevip | Generate kube-vip manifest file template: src: >- kubevip/kubevip.{{ .kubernetes.control_plane_endpoint.kube_vip.mode }} diff --git a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/main.yaml b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/main.yaml index b76e4b03..5ac17c96 100644 --- a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/main.yaml +++ b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/high-availability/main.yaml @@ -1,46 +1,48 @@ -# set localDNS for each .kubernetes.control_plane_endpoint.type -# local: -# before init cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# after init cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# before join cluster -# - control_plane: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} -# after join cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} +# HighAvailability: Configure localDNS for each .kubernetes.control_plane_endpoint.type +# +# For 'local' endpoint type: +# Before cluster initialization: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# After cluster initialization: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# Before joining cluster: +# - Control plane: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} +# After joining cluster: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} # -# kube_vip: -# before init cluster -# - control_plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# after init cluster -# - control_plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# before join cluster -# - control_plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} -# after join cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# For 'kube_vip' endpoint type: +# Before cluster initialization: +# - Control plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# After cluster initialization: +# - Control plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# Before joining cluster: +# - Control plane: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} +# After joining cluster: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .kubernetes.control_plane_endpoint.kube_vip.address }} {{ .kubernetes.control_plane_endpoint.host }} # -# haproxy: -# before init cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# after init cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# before join cluster -# - control_plane: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} -# - worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} -# after join cluster -# - control_plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -# - worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} -- name: Set Control Plane to localDNS file +# For 'haproxy' endpoint type: +# Before cluster initialization: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# After cluster initialization: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# Before joining cluster: +# - Control plane: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: {{ .init_kubernetes_node }} {{ .kubernetes.control_plane_endpoint.host }} +# After joining cluster: +# - Control plane: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} +# - Worker: 127.0.0.1 {{ .kubernetes.control_plane_endpoint.host }} + +- name: HighAvailability | Configure localDNS for control plane endpoint command: | sed -i ':a;$!{N;ba};s@# kubekey control_plane_endpoint BEGIN.*# kubekey control_plane_endpoint END@@' {{ .item }} cat >> {{ .item }} <- {{ .binary_dir }}/helm/{{ .helm_version }}/{{ .binary_type }}/helm-{{ .helm_version }}-linux-{{ .binary_type }}.tar.gz dest: >- {{ .tmp_dir }}/helm-{{ .helm_version }}-linux-{{ .binary_type }}.tar.gz - - name: Install helm + - name: Binary | Extract and install Helm binary command: | tar --strip-components=1 -zxvf {{ .tmp_dir }}/helm-{{ .helm_version }}-linux-{{ .binary_type }}.tar.gz -C /usr/local/bin linux-{{ .binary_type }}/helm -- name: Check if kubeadm is installed +- name: Binary | Check if kubeadm is installed ignore_errors: true command: kubeadm version -o short register: kubeadm_install_version -- name: Install kubeadm - when: or (.kubeadm_install_version.stderr | empty | not) (.kubeadm_install_version.stdout | ne .kube_version) + +- name: Binary | Install kubeadm if not present or version mismatch + when: or (.kubeadm_install_version.error | empty | not) (.kubeadm_install_version.stdout | ne .kube_version) copy: src: >- {{ .binary_dir }}/kube/{{ .kube_version }}/{{ .binary_type }}/kubeadm dest: /usr/local/bin/kubeadm mode: 0755 -- name: Check if kubectl is installed +- name: Binary | Check if kubectl is installed ignore_errors: true command: kubectl version --short register: kubectl_install_version register_type: yaml -- name: Sync kubectl to remote + +- name: Binary | Install kubectl if not present or version mismatch when: | - or (.kubectl_install_version.stderr | empty | not) ((get .kubectl_install_version.stdout "Server Version") | ne .kube_version) + or (.kubectl_install_version.error | empty | not) ((get .kubectl_install_version.stdout "Server Version") | ne .kube_version) copy: src: >- {{ .binary_dir }}/kube/{{ .kube_version }}/{{ .binary_type }}/kubectl dest: /usr/local/bin/kubectl mode: 0755 -- name: Check if kubelet is installed +- name: Binary | Check if kubelet is installed ignore_errors: true command: kubelet --version register: kubelet_install_version -- name: Install kubelet - when: or (.kubelet_install_version.stderr | empty | not) (.kubelet_install_version.stdout | ne (printf "Kubernetes %s" .kube_version)) + +- name: Binary | Install kubelet if not present or version mismatch + when: or (.kubelet_install_version.error | empty | not) (.kubelet_install_version.stdout | ne (printf "Kubernetes %s" .kube_version)) block: - - name: Sync kubelet to remote + - name: Binary | Copy kubelet binary to remote host copy: src: >- {{ .binary_dir }}/kube/{{ .kube_version }}/{{ .binary_type }}/kubelet dest: /usr/local/bin/kubelet mode: 0755 - - name: Sync kubelet env to remote + - name: Binary | Deploy kubelet environment configuration template: src: kubelet/kubelet.env dest: /etc/systemd/system/kubelet.service.d/10-kubeadm.conf - - name: Sync kubelet service to remote + - name: Binary | Copy kubelet systemd service file copy: src: kubelet.service dest: /etc/systemd/system/kubelet.service - - name: Register kubelet service + - name: Binary | Reload systemd and enable kubelet service command: systemctl daemon-reload && systemctl enable kubelet.service -- name: Install cni plugins +- name: Binary | Install CNI plugins if version specified when: .cni_plugins_version | empty | not block: - - name: Sync cni-plugin to remote + - name: Binary | Copy CNI plugins archive to remote host copy: src: >- {{ .binary_dir }}/cni/plugins/{{ .cni_plugins_version }}/{{ .binary_type }}/cni-plugins-linux-{{ .binary_type }}-{{ .cni_plugins_version }}.tgz dest: >- {{ .tmp_dir }}/cni-plugins-linux-{{ .binary_type }}-{{ .cni_plugins_version }}.tgz - - name: Install cni-plugin + - name: Binary | Extract and install CNI plugins command: | tar -zxvf {{ .tmp_dir }}/cni-plugins-linux-{{ .binary_type }}-{{ .cni_plugins_version }}.tgz -C /opt/cni/bin/ \ No newline at end of file diff --git a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/main.yaml b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/main.yaml index 601484c5..ec9361ba 100644 --- a/builtin/core/roles/kubernetes/pre-kubernetes/tasks/main.yaml +++ b/builtin/core/roles/kubernetes/pre-kubernetes/tasks/main.yaml @@ -2,11 +2,11 @@ - include_tasks: high-availability/main.yaml -- name: Add kube user +- name: PreKubernetes | Ensure the 'kube' system user exists command: | id kube &>/dev/null || useradd -M -c 'Kubernetes user' -s /sbin/nologin -r kube -- name: Create kube directories +- name: PreKubernetes | Create and set ownership for required Kubernetes directories command: | if [ ! -d "{{ .item.path }}" ]; then mkdir -p {{ .item.path }} && chown kube -R {{ .item.chown }} @@ -22,41 +22,62 @@ - {path: "/opt/cni/bin", chown: "/opt/cni"} - {path: "/var/lib/calico", chown: "/var/lib/calico"} -- name: Sync audit policy file to remote +- name: PreKubernetes | Synchronize audit policy file to remote node copy: src: audit dest: /etc/kubernetes/audit/ when: .kubernetes.audit -- name: Sync ca file to kube_control_plane +- name: PreKubernetes | Synchronize cluster CA files to control plane nodes when: - .kubernetes.certs.ca_cert | empty | not - .kubernetes.certs.ca_key | empty | not - .groups.kube_control_plane | has .inventory_hostname block: - - name: Sync ca cert to kube_control_plane + - name: PreKubernetes | Copy CA certificate to control plane node copy: src: >- {{ .kubernetes.certs.ca_cert }} dest: /etc/kubernetes/pki/ca.crt - - name: Sync ca key to kube_control_plane + - name: PreKubernetes | Copy CA private key to control plane node copy: src: >- {{ .kubernetes.certs.ca_key }} dest: /etc/kubernetes/pki/ca.key -- name: Sync front-proxy ca file to kube_control_plane +- name: PreKubernetes | Ensure external etcd certificates are present on control plane nodes + when: + - .kubernetes.etcd.deployment_type | eq "external" + - .groups.kube_control_plane | default list | has .inventory_hostname + block: + - name: PreKubernetes | Copy etcd CA certificate to control plane node + copy: + src: >- + {{ .work_dir }}/kubekey/pki/root.crt + dest: /etc/kubernetes/pki/etcd/ca.crt + - name: PreKubernetes | Copy etcd client certificate to control plane node + copy: + src: >- + {{ .work_dir }}/kubekey/pki/etcd.crt + dest: /etc/kubernetes/pki/etcd/client.crt + - name: PreKubernetes | Copy etcd client key to control plane node + copy: + src: >- + {{ .work_dir }}/kubekey/pki/etcd.key + dest: /etc/kubernetes/pki/etcd/client.key + +- name: PreKubernetes | Synchronize front-proxy CA files to control plane nodes when: - .kubernetes.certs.front_proxy_cert | empty | not - .kubernetes.certs.front_proxy_key | empty | not - .groups.kube_control_plane | has .inventory_hostname block: - - name: Sync front-proxy cert to kube_control_plane + - name: PreKubernetes | Copy front-proxy CA certificate to control plane node copy: src: >- {{ .kubernetes.certs.front_proxy_cert }} dest: /etc/kubernetes/pki/front-proxy-ca.crt - - name: Sync front-proxy key to kube_control_plane + - name: PreKubernetes | Copy front-proxy CA private key to control plane node copy: src: >- {{ .kubernetes.certs.front_proxy_key }} diff --git a/builtin/core/roles/precheck/artifact_check/tasks/main.yaml b/builtin/core/roles/precheck/artifact_check/tasks/main.yaml index 6eda4265..7725f7e0 100644 --- a/builtin/core/roles/precheck/artifact_check/tasks/main.yaml +++ b/builtin/core/roles/precheck/artifact_check/tasks/main.yaml @@ -1,20 +1,24 @@ --- -- name: Check artifact is exits - command: +- name: Artifact | Ensure artifact file exists + command: | if [ ! -f "{{ .artifact.artifact_file }}" ]; then + echo "Error: Artifact file '{{ .artifact.artifact_file }}' does not exist." exit 1 fi -- name: Check artifact file type - command: +- name: Artifact | Validate artifact file extension + command: | if [[ "{{ .artifact.artifact_file }}" != *{{ .item }} ]]; then + echo "Error: Artifact file '{{ .artifact.artifact_file }}' does not have the required extension '{{ .item }}'." exit 1 fi loop: ['.tgz','.tar.gz'] -- name: Check md5 of artifact - command: - if [[ "$(md5sum {{ .artifact.artifact_file }})" != "{{ .artifact.artifact_md5 }}" ]]; then +- name: Artifact | Verify artifact MD5 checksum + command: | + actual_md5=$(md5sum {{ .artifact.artifact_file }} | awk '{print $1}') + if [[ "$actual_md5" != "{{ .artifact.artifact_md5 }}" ]]; then + echo "Error: MD5 checksum mismatch for '{{ .artifact.artifact_file }}'. Expected '{{ .artifact.artifact_md5 }}', got '$actual_md5'." exit 1 fi when: diff --git a/builtin/core/roles/precheck/env_check/tasks/cri.yaml b/builtin/core/roles/precheck/env_check/tasks/cri.yaml index 1055cf46..045b06d2 100644 --- a/builtin/core/roles/precheck/env_check/tasks/cri.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/cri.yaml @@ -1,17 +1,17 @@ --- -- name: Stop if container manager is not docker or containerd +- name: CRI | Fail if container manager is not docker or containerd assert: that: .cluster_require.require_container_manager | has .cri.container_manager fail_msg: >- - the container manager:{{ .cri.container_manager }}, must in "{{ .cluster_require.require_container_manager | toJson }}" + The specified container manager "{{ .cri.container_manager }}" is not supported. Please use one of the following: {{ .cluster_require.require_container_manager | toJson }}. run_once: true when: .cri.container_manager | empty | not -- name: Ensure minimum containerd version +- name: CRI | Validate minimum required containerd version assert: that: .containerd_version | semverCompare (printf ">=%s" .cluster_require.containerd_min_version_required) fail_msg: >- - containerd_version is too low. Minimum version {{ .cluster_require.containerd_min_version_required }} + The detected containerd version ({{ .containerd_version }}) is below the minimum required version: {{ .cluster_require.containerd_min_version_required }}. run_once: true when: - .containerd_version | empty | not diff --git a/builtin/core/roles/precheck/env_check/tasks/etcd.yaml b/builtin/core/roles/precheck/env_check/tasks/etcd.yaml index df0a574b..e951093c 100644 --- a/builtin/core/roles/precheck/env_check/tasks/etcd.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/etcd.yaml @@ -1,68 +1,50 @@ --- -- name: Stop if etcd deployment type is not internal or external +- name: ETCD | Fail if etcd deployment type is not 'internal' or 'external' assert: that: .cluster_require.require_etcd_deployment_type | has .kubernetes.etcd.deployment_type fail_msg: >- - the etcd deployment type, should be internal or external but got {{ .kubernetes.etcd.deployment_type }} + Invalid etcd deployment type: '{{ .kubernetes.etcd.deployment_type }}'. Expected 'internal' or 'external'. run_once: true when: .kubernetes.etcd.deployment_type | empty | not -- name: Stop if etcd group is empty in external etcd mode +- name: ETCD | Fail if etcd group is empty in external etcd mode assert: that: .groups.etcd | empty | not - fail_msg: "group \"etcd\" cannot be empty in external etcd mode" + fail_msg: >- + The "etcd" group must not be empty when using external etcd mode. run_once: true when: .kubernetes.etcd.deployment_type | eq "external" -- name: Stop if even number of etcd hosts +- name: ETCD | Fail if the number of etcd hosts is even assert: that: (mod (.groups.etcd | len) 2) | eq 1 - fail_msg: "etcd number should be odd number" + fail_msg: >- + The number of etcd nodes must be odd to ensure quorum. Current count: {{ .groups.etcd | len }}. run_once: true when: .kubernetes.etcd.deployment_type | eq "external" ## https://cwiki.yunify.com/pages/viewpage.action?pageId=145920824 -- name: Check dev io for etcd +- name: ETCD | Validate disk I/O performance for etcd when: - .groups.etcd | default list | has .inventory_hostname block: - - name: Check fio is exist + - name: ETCD | Check if fio is installed ignore_errors: true command: fio --version register: fio_install_version - - name: Test dev io by fio - when: .fio_install_version.stderr | empty + - name: ETCD | Run fio disk I/O test + when: .fio_install_version.error | empty block: - - name: Get fio result + - name: ETCD | Execute fio and collect results command: | mkdir -p {{ .tmp_dir }}/etcd/test-data fio --rw=write --ioengine=sync --fdatasync=1 --directory={{ .tmp_dir }}/etcd/test-data --size=22m --bs=2300 --name=mytest --output-format=json register: fio_result - - name: Check fio result + - name: ETCD | Assert disk fsync latency meets requirements assert: that: (index (.fio_result.stdout.jobs | first) "sync" "lat_ns" "percentile" "90.000000") | le .cluster_require.etcd_disk_wal_fysnc_duration_seconds fail_msg: >- - etcd_disk_wal_fysnc_duration_seconds: {{ index (.fio_result.stdout.jobs | first) "sync" "lat_ns" "percentile" "90.000000" }}ns is more than {{ .cluster_require.etcd_disk_wal_fysnc_duration_seconds }}ns + The 90th percentile fsync latency is {{ index (.fio_result.stdout.jobs | first) "sync" "lat_ns" "percentile" "90.000000" }}ns, which exceeds the maximum allowed: {{ .cluster_require.etcd_disk_wal_fysnc_duration_seconds }}ns. always: - - name: Clean test data dir + - name: ETCD | Clean up fio test data directory command: rm -rf {{ .tmp_dir }}/etcd/test-data - -- name: Check if etcd has installed - when: .groups.etcd | default list | has .inventory_hostname - block: - - name: Get etcd service - ignore_errors: true - command: systemctl is-active etcd.service - register: etcd_install_service - - name: Get etcd version - ignore_errors: true - command: etcd --version - register: etcd_install_version - register_type: yaml - - name: Check if etcd has match the version - when: .etcd_install_service.stdout | eq "active" - assert: - that: | - eq (get .etcd_install_version.stdout "etcd Version") (.etcd_version | default "" | trimPrefix "v") - fail_msg: >- - excepted install etcd with version: {{ .etcd_version }} but has installed with: {{ get .etcd_install_version.stdout "etcd Version" }}. diff --git a/builtin/core/roles/precheck/env_check/tasks/image_registry.yaml b/builtin/core/roles/precheck/env_check/tasks/image_registry.yaml index 991c4896..948038f4 100644 --- a/builtin/core/roles/precheck/env_check/tasks/image_registry.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/image_registry.yaml @@ -1,29 +1,29 @@ -- name: Ensure image registry authentication is successful +- name: ImageRegistry | Verify successful authentication to image registry when: .image_registry.auth | empty | not run_once: true command: | HTTP_CODE=$(curl -skLI -w "%{http_code}" -u "{{ .image_registry.auth.username }}:{{ .image_registry.auth.password }}" "https://{{ .image_registry.auth.registry }}/v2/" -o /dev/null) if [[ "$HTTP_CODE" == "200" ]]; then - echo "Authentication to image registry succeeded." + echo "Successfully authenticated to the image registry." else - echo "Authentication to image registry {{ .image_registry.auth.registry }} failed." >&2 + echo "Failed to authenticate to the image registry at {{ .image_registry.auth.registry }}." >&2 fi -# image_registry is installed by docker_compose -- name: Ensure docker and docker-compose versions are set for image registry +# The image_registry is deployed using docker_compose +- name: ImageRegistry | Ensure docker and docker-compose versions are specified when: .groups.image_registry | empty | not assert: that: - - .docker_version | empty | not - - .dockercompose_version | empty | not + - .docker_version | empty | not + - .dockercompose_version | empty | not msg: >- - Both "docker_version" and "dockercompose_version" must be specified for the image registry. + Both "docker_version" and "dockercompose_version" must be provided for the image registry deployment. -- name: Ensure keepalived_version is set for high availability image registry +- name: ImageRegistry | Ensure keepalived_version is specified for high availability when: - .image_registry.ha_vip | empty | not - .groups.image_registry | len | lt 1 assert: that: .keepalived_version | empty | not msg: >- - "keepalived_version" must be specified when the image registry is configured for high availability. \ No newline at end of file + "keepalived_version" must be specified when configuring the image registry for high availability. \ No newline at end of file diff --git a/builtin/core/roles/precheck/env_check/tasks/kubernetes.yaml b/builtin/core/roles/precheck/env_check/tasks/kubernetes.yaml index a4040e73..ae364045 100644 --- a/builtin/core/roles/precheck/env_check/tasks/kubernetes.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/kubernetes.yaml @@ -1,10 +1,10 @@ -- name: Should defined internal_ipv4 or internal_ipv6 +- name: Kubernetes | Ensure either internal_ipv4 or internal_ipv6 is defined assert: that: or (.internal_ipv4 | empty | not) (.internal_ipv6 | empty | not) fail_msg: >- - "internal_ipv4" and "internal_ipv6" cannot both be empty + Either "internal_ipv4" or "internal_ipv6" must be specified. Both cannot be empty. -- name: Check kubevip if valid +- name: Kubernetes | Validate kube-vip address run_once: true assert: that: @@ -19,31 +19,41 @@ {{- end }} {{ not $existIP }} fail_msg: >- - "kubernetes.control_plane_endpoint.kube_vip.address" should be a un-used ip address. + The value of "kubernetes.control_plane_endpoint.kube_vip.address" must be an IP address that is not currently assigned to any node. + when: .kubernetes.control_plane_endpoint.type | eq "kube_vip" -- name: Stop if unsupported version of Kubernetes +- name: Kubernetes | Fail if unsupported Kubernetes version run_once: true assert: that: .kube_version | semverCompare (printf ">=%s" .cluster_require.kube_version_min_required) fail_msg: >- - the current release of KubeKey only support newer version of Kubernetes than {{ .cluster_require.kube_version_min_required }} - You are trying to apply {{ .kube_version }} + This version of KubeKey only supports Kubernetes versions greater than or equal to {{ .cluster_require.kube_version_min_required }}. You are attempting to use version {{ .kube_version }}. when: .kube_version | empty | not -- name: Check if kubernetes installed +- name: Kubernetes | Check if Kubernetes is installed when: .groups.k8s_cluster | default list | has .inventory_hostname block: - - name: Get kubernetes service - ignore_errors: true - command: systemctl is-active kubelet.service - register: kubernetes_install_service - - name: Get kubernetes version + - name: Kubernetes | Retrieve kubelet.service LoadState + command: systemctl show kubelet.service -p LoadState --value + register: kubernetes_install_LoadState + - name: Retrieve kubelet.service ActiveState + command: systemctl show kubelet.service -p ActiveState --value + register: kubernetes_install_ActiveState + - name: Retrieve installed Kubernetes version ignore_errors: true command: kubelet --version register: kubernetes_install_version - - name: Check kubernetes service and version - when: .kubernetes_install_service.stdout | eq "active" - assert: - that: .kubernetes_install_version.stdout | default "" | trimPrefix "Kubernetes " | eq .kube_version - fail_msg: >- - kubernetes has installed with version:{{ .kubernetes_install_version.stdout | default "" | trimPrefix "Kubernetes " }}. but not match kube_version: {{ .kube_version }} + - name: Validate Kubernetes service status and version + when: .kubernetes_install_LoadState.stdout | eq "loaded" + block: + - name: Ensure kubelet service is active + assert: + that: .kubernetes_install_ActiveState.stdout | eq "active" + fail_msg: >- + The kubelet service must be running and active when it is loaded. + - name: Ensure installed Kubernetes version matches expected version + assert: + that: .kubernetes_install_version.stdout | default "" | trimPrefix "Kubernetes " | eq .kube_version + fail_msg: >- + The installed Kubernetes version ({{ .kubernetes_install_version.stdout | default "" | trimPrefix "Kubernetes " }}) does not match the expected version ({{ .kube_version }}). diff --git a/builtin/core/roles/precheck/env_check/tasks/network.yaml b/builtin/core/roles/precheck/env_check/tasks/network.yaml index ff62e966..05e75845 100644 --- a/builtin/core/roles/precheck/env_check/tasks/network.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/network.yaml @@ -1,86 +1,89 @@ --- -- name: Ensure required network interfaces are present - command: | +- name: Network | Ensure required network interfaces are present + command: | {{- if .internal_ipv4 | empty | not }} if ! ip -o addr show | grep -q {{ .internal_ipv4 }}; then - echo 'IPv4 network interface not found' >&2 + echo 'The specified IPv4 address is not assigned to any network interface.' >&2 fi {{- end }} {{- if .internal_ipv6 | empty | not }} if ! ip -o addr show | grep -q {{ .internal_ipv6 }}; then - echo 'IPv6 network interface not found' >&2 + echo 'The specified IPv6 address is not assigned to any network interface.' >&2 fi {{- end }} # https://kubernetes.io/docs/concepts/services-networking/dual-stack/ -- name: Validate CIDR configuration +- name: Network | Validate dual-stack CIDR configuration run_once: true block: - - name: Validate pod CIDR format + - name: Network | Check pod CIDR includes both IPv4 and IPv6 when: .kubernetes.networking.pod_cidr | empty | not assert: that: .kubernetes.networking.pod_cidr | splitList "," | len | ge 2 fail_msg: >- - kubernetes.networking.pod_cidr must be specified as ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr - - name: Validate service CIDR format + "kubernetes.networking.pod_cidr" must specify both IPv4 and IPv6 ranges, using either the format ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr. + - name: Network | Check service CIDR includes both IPv4 and IPv6 when: .kubernetes.networking.service_cidr | empty | not assert: that: .kubernetes.networking.service_cidr | splitList "," | len | ge 2 fail_msg: >- - kubernetes.networking.service_cidr must be specified as ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr - - name: Ensure pod networking supports dual-stack + "kubernetes.networking.service_cidr" must specify both IPv4 and IPv6 ranges, using either the format ipv4_cidr/ipv6_cidr or ipv4_cidr,ipv6_cidr. + - name: Network | Ensure pod networking is properly configured for dual-stack when: - .kubernetes.networking.pod_cidr | empty | not - .kubernetes.networking.pod_cidr | splitList "," | len | eq 2 assert: - that: + that: - .kube_version | semverCompare ">=v1.20.0" - .kubernetes.networking.pod_cidr | splitList "," | first | ipFamily | eq "IPv4" - .kubernetes.networking.pod_cidr | splitList "," | last | ipFamily | eq "IPv6" fail_msg: >- - Dual-stack pod networking is supported in Kubernetes version v1.20.0 and above. - - name: Ensure service networking supports dual-stack + Dual-stack pod networking is only supported in Kubernetes v1.20.0 or newer. + - name: Network | Ensure service networking is properly configured for dual-stack when: - .kubernetes.networking.service_cidr | empty | not - .kubernetes.networking.service_cidr | splitList "," | len | eq 2 assert: - that: + that: - .kube_version | semverCompare ">=v1.20.0" - .kubernetes.networking.service_cidr | splitList "," | first | ipFamily | eq "IPv4" - .kubernetes.networking.service_cidr | splitList "," | last | ipFamily | eq "IPv6" fail_msg: >- - Dual-stack service networking is supported in Kubernetes version v1.20.0 and above. + Dual-stack service networking is only supported in Kubernetes v1.20.0 or newer. -- name: Fail if network plugin is unsupported +- name: Network | Fail if the selected network plugin is not supported run_once: true assert: that: .cluster_require.require_network_plugin | has .kubernetes.kube_network_plugin fail_msg: >- - The specified kube_network_plugin "{{ .kubernetes.kube_network_plugin }}" is not supported. + The network plugin "{{ .kubernetes.kube_network_plugin }}" is not supported. Please select a supported network plugin. when: .kubernetes.kube_network_plugin | empty | not -# Note: This assertion errs on the side of caution. It is technically possible to schedule more pods on a node than the available CIDR range allows, especially if some pods use the host network namespace. Since the number of such pods cannot be determined at provisioning time, this check provides a conservative guarantee. -# Note: This check intentionally ignores the IPv6-only case. -- name: Ensure sufficient network address space for all pods +# Note: This check is intentionally conservative. While it is technically possible to schedule more pods than the available addresses in the CIDR range (for example, if some pods use the host network), this cannot be reliably determined at provisioning time. This check ensures there is enough address space for the configured maximum pods per node. +# Note: IPv6-only scenarios are not checked here. +- name: Network | Ensure sufficient address space for all pods run_once: true when: .groups.k8s_cluster | default list | has .inventory_hostname block: - - name: Ensure sufficient IPv4 address space for pods + - name: Network | Ensure enough IPv4 addresses are available for pods when: .kubernetes.networking.pod_cidr | default "10.233.64.0/18" | splitList "," | first | ipFamily | eq "IPv4" assert: that: le (.kubernetes.kubelet.max_pods | default 110) (sub (pow 2 (float64 (sub 32 (.kubernetes.networking.ipv4_mask_size | default 24)))) 2) - fail_msg: Do not schedule more pods on a node than there are available IPv4 addresses in the pod CIDR range. - - name: Ensure sufficient IPv6 address space for pods + fail_msg: >- + The configured maximum number of pods per node exceeds the number of available IPv4 addresses in the pod CIDR range. + - name: Network | Ensure enough IPv6 addresses are available for pods when: .kubernetes.networking.pod_cidr | default "10.233.64.0/18" | splitList "," | last | ipFamily | eq "IPv6" assert: that: le (.kubernetes.kubelet.max_pods | default 110) (sub (pow 2 (float64 (sub 128 (.kubernetes.networking.ipv4_mask_size | default 64)))) 2) - fail_msg: Do not schedule more pods on a node than there are available IPv6 addresses in the pod CIDR range. - + fail_msg: >- + The configured maximum number of pods per node exceeds the number of available IPv6 addresses in the pod CIDR range. + # https://github.com/alibaba/hybridnet/wiki/Getting-Started#install -- name: Fail if Kubernetes version is too low for hybridnet +- name: Network | Fail if Kubernetes version is too old for hybridnet run_once: true assert: that: .kube_version | semverCompare ">=v1.16.0" - fail_msg: Hybridnet requires Kubernetes version 1.16 or higher. + fail_msg: >- + Hybridnet requires Kubernetes version 1.16.0 or newer. when: - .kubernetes.kube_network_plugin | eq "hybridnet" \ No newline at end of file diff --git a/builtin/core/roles/precheck/env_check/tasks/nfs.yaml b/builtin/core/roles/precheck/env_check/tasks/nfs.yaml index 8271da20..dac9ce0f 100644 --- a/builtin/core/roles/precheck/env_check/tasks/nfs.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/nfs.yaml @@ -1,6 +1,6 @@ --- -- name: Stop if nfs server is not be one +- name: NFS | Fail if more than one NFS server is defined assert: that: .groups.nfs | default list | len | eq 1 - fail_msg: "only one nfs server is supported" + fail_msg: "Exactly one NFS server must be specified. Multiple NFS servers are not supported." when: .groups.nfs diff --git a/builtin/core/roles/precheck/env_check/tasks/os.yaml b/builtin/core/roles/precheck/env_check/tasks/os.yaml index 1878667f..be2ae4b1 100644 --- a/builtin/core/roles/precheck/env_check/tasks/os.yaml +++ b/builtin/core/roles/precheck/env_check/tasks/os.yaml @@ -1,31 +1,35 @@ --- -- name: Stop if bad hostname +- name: OS | Fail if hostname is invalid assert: that: .hostname | regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$" - fail_msg: "Hostname must consist of lower case alphanumeric characters, '.' or '-', and must start and end with an alphanumeric character" + fail_msg: >- + The hostname "{{ .hostname }}" is invalid. Hostnames must use only lowercase alphanumeric characters, '.', or '-', and must start and end with an alphanumeric character. -- name: Stop if the os does not support +- name: OS | Fail if operating system is not supported assert: that: or (.cluster_require.allow_unsupported_distribution_setup) (.cluster_require.supported_os_distributions | has .os.release.ID) - fail_msg: "{{ .os.release.ID }} is not a known OS" + fail_msg: >- + The operating system "{{ .os.release.ID }}" is not recognized or supported. -- name: Stop if arch supported +- name: OS | Fail if architecture is not supported assert: that: .cluster_require.supported_architectures | has .os.architecture - fail_msg: "{{ .os.architecture }} is not a known arch" + fail_msg: >- + The system architecture "{{ .os.architecture }}" is not supported. -- name: Stop if memory is too small for masters +- name: OS | Fail if master node memory is insufficient assert: that: .process.memInfo.MemTotal | trimSuffix " kB" | atoi | le .cluster_require.minimal_master_memory_mb when: .groups.kube_control_plane | default list | has .inventory_hostname -- name: Stop if memory is too small for nodes +- name: OS | Fail if worker node memory is insufficient assert: that: .process.memInfo.MemTotal | trimSuffix " kB" | atoi | le .cluster_require.minimal_node_memory_mb when: - .groups.kube_worker | default list | has .inventory_hostname -- name: Stop if kernel version is too low +- name: OS | Fail if kernel version is too old assert: that: .os.kernel_version | splitList "-" | first | semverCompare (printf ">=%s" .cluster_require.min_kernel_version) - fail_msg: "kernel version: {{ .os.kernel_version }} is too low, required at least: {{ .cluster_require.min_kernel_version }} " + fail_msg: >- + The kernel version "{{ .os.kernel_version }}" is too old. Minimum required version: {{ .cluster_require.min_kernel_version }}. diff --git a/builtin/core/roles/uninstall/cri/containerd/tasks/main.yaml b/builtin/core/roles/uninstall/cri/containerd/tasks/main.yaml index 6adb1045..928d2825 100644 --- a/builtin/core/roles/uninstall/cri/containerd/tasks/main.yaml +++ b/builtin/core/roles/uninstall/cri/containerd/tasks/main.yaml @@ -1,5 +1,5 @@ --- -- name: Uninstall containerd service +- name: Containerd | Uninstall the containerd system service ignore_errors: true command: | systemctl stop containerd.service @@ -8,7 +8,7 @@ systemctl daemon-reload systemctl reset-failed containerd.service -- name: Delete containerd residue files +- name: Containerd | Remove all containerd-related files and binaries command: | rm -rf {{ .cri.containerd.data_root }} rm -rf /etc/containerd diff --git a/builtin/core/roles/uninstall/cri/crictl/tasks/main.yaml b/builtin/core/roles/uninstall/cri/crictl/tasks/main.yaml index e68d0e60..06252bcd 100644 --- a/builtin/core/roles/uninstall/cri/crictl/tasks/main.yaml +++ b/builtin/core/roles/uninstall/cri/crictl/tasks/main.yaml @@ -1,3 +1,3 @@ -- name: Delete cri residue files +- name: Crictl | Remove crictl binary and clean up any residual files command: | rm -f /usr/local/bin/crictl \ No newline at end of file diff --git a/builtin/core/roles/uninstall/cri/docker/tasks/cridockerd.yaml b/builtin/core/roles/uninstall/cri/docker/tasks/cridockerd.yaml index 74c00965..7447024a 100644 --- a/builtin/core/roles/uninstall/cri/docker/tasks/cridockerd.yaml +++ b/builtin/core/roles/uninstall/cri/docker/tasks/cridockerd.yaml @@ -1,5 +1,5 @@ --- -- name: Stop cri-dockerd service +- name: Cridockerd | Stop and disable the cri-dockerd system service ignore_errors: true command: | systemctl stop cri-dockerd.service @@ -8,7 +8,7 @@ systemctl daemon-reload systemctl reset-failed cri-dockerd.service -- name: Delete cri-dockerd residue files +- name: Cridockerd | Remove all cri-dockerd related files and binaries command: | rm -rf /etc/cri-dockerd rm -f /usr/local/bin/cri-dockerd \ No newline at end of file diff --git a/builtin/core/roles/uninstall/cri/docker/tasks/docker.yaml b/builtin/core/roles/uninstall/cri/docker/tasks/docker.yaml index bc1e1e62..a57dd97d 100644 --- a/builtin/core/roles/uninstall/cri/docker/tasks/docker.yaml +++ b/builtin/core/roles/uninstall/cri/docker/tasks/docker.yaml @@ -1,16 +1,16 @@ --- -- name: Stop docker service +- name: Docker | Gracefully stop and disable the Docker service ignore_errors: true command: | systemctl stop docker.service systemctl disable docker.service rm -rf /etc/systemd/system/docker.service* - systemctl daemon-reload + systemctl daemon-reload systemctl reset-failed docker.service -- name: Uninstall containerd +- name: Docker | Completely uninstall containerd and remove all related files block: - - name: Uninstall containerd service + - name: Docker | Stop and disable the containerd service ignore_errors: true command: | systemctl stop containerd.service @@ -18,8 +18,8 @@ rm -rf /etc/systemd/system/containerd.service* systemctl daemon-reload systemctl reset-failed containerd.service - - - name: Delete containerd residue files + + - name: Docker | Remove all containerd-related files and binaries command: | rm -rf {{ .cri.containerd.data_root }} rm -rf /etc/containerd @@ -27,12 +27,12 @@ rm -f /usr/local/bin/runc rm -f /usr/local/bin/ctr -- name: Delete docker residue files +- name: Docker | Remove all Docker residual files and binaries command: | rm -rf {{ .cri.docker.data_root }} rm -rf /etc/docker rm -rf /usr/local/bin/docker* -- name: Uninstall docker interface +- name: Docker | Remove the docker0 network interface ignore_errors: true command: ip link delete docker0 \ No newline at end of file diff --git a/builtin/core/roles/uninstall/etcd/tasks/main.yaml b/builtin/core/roles/uninstall/etcd/tasks/main.yaml index 893de106..b32dc350 100644 --- a/builtin/core/roles/uninstall/etcd/tasks/main.yaml +++ b/builtin/core/roles/uninstall/etcd/tasks/main.yaml @@ -1,7 +1,7 @@ --- -- name: Uninstall etcd service +- name: ETCD | Completely uninstall the etcd service and remove all related files block: - - name: Stop etcd service + - name: ETCD | Stop and disable the etcd systemd service ignore_errors: true command: | systemctl stop etcd.service @@ -9,19 +9,20 @@ rm -rf /etc/systemd/system/etcd.service* systemctl daemon-reload systemctl reset-failed etcd.service - - name: Unset Traffic Priority + - name: ETCD | Remove traffic priority rules for etcd ports command: | tc filter del dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2379 0xffff tc filter del dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff when: .etcd.traffic_priority - - name: Delete residue files + - name: ETCD | Delete all etcd data, configuration, and binaries command: | rm -rf {{ .etcd.env.data_dir }} rm -rf /etc/ssl/etcd/ rm -rf /etc/etcd.env rm -rf /usr/local/bin/etcd* -- name: Uninstall backup-etcd service +- name: ETCD | Uninstall backup-etcd timer and service, and remove backup scripts + ignore_errors: true command: | systemctl disable --now backup-etcd.timer rm /etc/systemd/system/backup-etcd.timer diff --git a/builtin/core/roles/uninstall/image-registry/docker-compose/tasks/main.yaml b/builtin/core/roles/uninstall/image-registry/docker-compose/tasks/main.yaml index 68d5f58b..48c424c8 100644 --- a/builtin/core/roles/uninstall/image-registry/docker-compose/tasks/main.yaml +++ b/builtin/core/roles/uninstall/image-registry/docker-compose/tasks/main.yaml @@ -1,16 +1,16 @@ --- -- name: Stop docker service +- name: DockerCompose | Gracefully stop and disable the Docker service ignore_errors: true command: | systemctl stop docker.service systemctl disable docker.service rm -rf /etc/systemd/system/docker.service* - systemctl daemon-reload + systemctl daemon-reload systemctl reset-failed docker.service -- name: Uninstall containerd +- name: DockerCompose | Completely uninstall containerd and remove all related files block: - - name: Uninstall containerd service + - name: DockerCompose | Stop and disable the containerd service ignore_errors: true command: | systemctl stop containerd.service @@ -18,21 +18,21 @@ rm -rf /etc/systemd/system/containerd.service* systemctl daemon-reload systemctl reset-failed containerd.service - - - name: Delete containerd residue files + + - name: DockerCompose | Remove all containerd-related files and binaries command: | rm -rf {{ .cri.containerd.data_root }} rm -rf /etc/containerd rm -rf /usr/local/bin/containerd* rm -f /usr/local/bin/runc - rm -f /usr/local/bin/ctr + rm -f /usr/local/bin/ctr -- name: Delete docker residue files +- name: DockerCompose | Remove all Docker residual files and binaries command: | rm -rf {{ .cri.docker.data_root }} rm -rf /etc/docker rm -rf /usr/local/bin/docker* -- name: Uninstall docker interface +- name: DockerCompose | Remove the docker0 network interface ignore_errors: true command: ip link delete docker0 \ No newline at end of file diff --git a/builtin/core/roles/uninstall/image-registry/docker-registry/tasks/main.yaml b/builtin/core/roles/uninstall/image-registry/docker-registry/tasks/main.yaml index b7d57ebd..669b9615 100644 --- a/builtin/core/roles/uninstall/image-registry/docker-registry/tasks/main.yaml +++ b/builtin/core/roles/uninstall/image-registry/docker-registry/tasks/main.yaml @@ -1,4 +1,4 @@ -- name: Stop registry service +- name: DockerRegistry | Gracefully stop and disable the Docker Registry service ignore_errors: true command: | systemctl stop docker-registry.service @@ -7,13 +7,13 @@ systemctl daemon-reload systemctl reset-failed docker-registry.service -- name: unmount nfs +- name: DockerRegistry | Unmount NFS storage for Docker Registry if configured when: - .image_registry.docker_registry.storage.filesystem.nfs_mount | empty | not - .groups.nfs | default list | len | eq 1 command: | unmount {{ .image_registry.docker_registry.storage.filesystem.rootdir }} -- name: Delete residue registry files +- name: DockerRegistry | Remove all residual Docker Registry files and directories command: | rm -rf /opt/docker-registry/ \ No newline at end of file diff --git a/builtin/core/roles/uninstall/image-registry/harbor/tasks/main.yaml b/builtin/core/roles/uninstall/image-registry/harbor/tasks/main.yaml index 258f155b..dcecf07b 100644 --- a/builtin/core/roles/uninstall/image-registry/harbor/tasks/main.yaml +++ b/builtin/core/roles/uninstall/image-registry/harbor/tasks/main.yaml @@ -1,4 +1,4 @@ -- name: Stop harbor service +- name: Harbor | Gracefully stop and disable the Harbor service ignore_errors: true command: | systemctl stop harbor.service @@ -7,6 +7,6 @@ systemctl daemon-reload systemctl reset-failed harbor.service -- name: Delete residue harbor files +- name: Harbor | Remove all residual Harbor files and directories command: | rm -rf /opt/harbor/ \ No newline at end of file diff --git a/builtin/core/roles/uninstall/image-registry/keepalived/tasks/main.yaml b/builtin/core/roles/uninstall/image-registry/keepalived/tasks/main.yaml index dcbfa7f3..06d51eaa 100644 --- a/builtin/core/roles/uninstall/image-registry/keepalived/tasks/main.yaml +++ b/builtin/core/roles/uninstall/image-registry/keepalived/tasks/main.yaml @@ -1,8 +1,8 @@ -- name: Delete arp by kube-vip +- name: Keepalived | Remove ARP and IP address entries associated with kube-vip command: | ip neigh show | grep {{ .image_registry.ha_vip }} | awk '{print $1 " dev " $3}' | xargs -r -L1 ip neigh delete ip -o addr show | grep {{ .image_registry.ha_vip }} | awk '{system("ip addr del "$4" dev "$2)}' -- name: Delete residue keepalived files +- name: Keepalived | Remove all residual Keepalived files and directories command: | rm -rf /opt/keepalived/ \ No newline at end of file diff --git a/builtin/core/roles/uninstall/kubernetes/tasks/kubernetes.yaml b/builtin/core/roles/uninstall/kubernetes/tasks/kubernetes.yaml index f09fbb31..083555fb 100644 --- a/builtin/core/roles/uninstall/kubernetes/tasks/kubernetes.yaml +++ b/builtin/core/roles/uninstall/kubernetes/tasks/kubernetes.yaml @@ -1,10 +1,10 @@ --- -- name: Delete Node +- name: Kubernetes | Completely reset the node using kubeadm ignore_errors: true command: | kubeadm reset -f -- name: Stop kubelet service +- name: Kubernetes | Gracefully stop and disable the kubelet service ignore_errors: true command: | systemctl stop kubelet.service @@ -13,9 +13,11 @@ systemctl daemon-reload systemctl reset-failed kubelet.service -- name: Delete residue files +- name: Kubernetes | Remove all residual Kubernetes files and directories command: | - rm -rf /usr/local/bin/kubeadm && rm -rf /usr/local/bin/kubelet && rm -rf /usr/local/bin/kubectl + rm -rf /usr/local/bin/kubeadm + rm -rf /usr/local/bin/kubelet + rm -rf /usr/local/bin/kubectl rm -rf /var/lib/kubelet/ # If /var/log/pods/ is not cleaned up, static pods may accumulate unexpected restarts due to lingering log files interfering with their lifecycle. rm -rf /var/log/pods/ diff --git a/builtin/core/roles/uninstall/kubernetes/tasks/main.yaml b/builtin/core/roles/uninstall/kubernetes/tasks/main.yaml index 33acd718..a6d86c93 100644 --- a/builtin/core/roles/uninstall/kubernetes/tasks/main.yaml +++ b/builtin/core/roles/uninstall/kubernetes/tasks/main.yaml @@ -3,6 +3,6 @@ - include_tasks: network.yaml -- name: Delete residue files +- name: Kubernetes | Remove all residual Kubekey files and directories command: | rm -rf /etc/kubekey/ \ No newline at end of file diff --git a/builtin/core/roles/uninstall/kubernetes/tasks/network.yaml b/builtin/core/roles/uninstall/kubernetes/tasks/network.yaml index 923a74f4..81b89699 100644 --- a/builtin/core/roles/uninstall/kubernetes/tasks/network.yaml +++ b/builtin/core/roles/uninstall/kubernetes/tasks/network.yaml @@ -1,5 +1,6 @@ --- -- name: Clean iptables +- name: Network | Thoroughly clean up iptables and network interfaces + ignore_errors: true command: | iptables -F iptables -X @@ -24,7 +25,7 @@ {{- end }} ip netns show 2>/dev/null | grep cni- | awk '{print $1}' | xargs -r -t -n 1 ip netns del -- name: Delete net.d +- name: Network | Remove all CNI network configuration and state command: | rm -rf /etc/cni/net.d/ rm -rf /var/lib/cni/ @@ -32,13 +33,13 @@ rm -rf /usr/local/bin/calicoctl {{- end }} -- name: Delete arp by kube-vip +- name: Network | Remove ARP and IP address entries for kube-vip when: eq .kubernetes.control_plane_endpoint.type "kube_vip" command: | ip neigh show | grep {{ .kubernetes.control_plane_endpoint.kube_vip.address }} | awk '{print $1 " dev " $3}' | xargs -r -L1 ip neigh delete ip -o addr show | grep {{ .kubernetes.control_plane_endpoint.kube_vip.address }} | awk '{system("ip addr del "$4" dev "$2)}' -- name: Rebuild cri iptables +- name: Network | Restart container runtime to rebuild iptables rules ignore_errors: true when: or (.deleteCRI | not) (.groups.image_registry | default list | has .inventory_hostname) command: | diff --git a/docs/zh/modules/prometheus.md b/docs/zh/modules/prometheus.md index d8a16c94..ddf3979c 100644 --- a/docs/zh/modules/prometheus.md +++ b/docs/zh/modules/prometheus.md @@ -26,7 +26,6 @@ prometheus: | query | PromQL查询语句 | 字符串 | 是(除非使用info参数) | - | | format | 结果格式化选项:raw、value、table | 字符串 | 否 | raw | | time | 查询的时间点(RFC3339格式或Unix时间戳) | 字符串 | 否 | 当前时间 | -| info | 获取Prometheus服务器信息而不执行查询 | 布尔值 | 否 | false | ## 输出 @@ -67,9 +66,9 @@ prometheus: 4. 获取Prometheus服务器信息: ```yaml - name: 获取Prometheus服务器信息 - prometheus: - info: true - register: prometheus_info + fetch: + src: api/v1/status/buildinfo + dest: info.json ``` 5. 使用表格格式化结果: @@ -84,7 +83,6 @@ prometheus: ## 注意事项 1. 如果需要执行查询,`query`参数是必需的 -2. 当指定`info: true`时,会忽略所有查询相关的参数 -3. 时间参数需要符合RFC3339格式(如:2023-01-01T12:00:00Z)或Unix时间戳格式 -4. 表格格式化仅适用于向量类型的结果,其他类型的结果会返回错误 -5. 为了确保安全,推荐使用HTTPS连接到Prometheus服务器 +2. 时间参数需要符合RFC3339格式(如:2023-01-01T12:00:00Z)或Unix时间戳格式 +3. 表格格式化仅适用于向量类型的结果,其他类型的结果会返回错误 +4. 为了确保安全,推荐使用HTTPS连接到Prometheus服务器 diff --git a/pkg/connector/prometheus_connector.go b/pkg/connector/prometheus_connector.go index 310dbcf7..2a1c0c19 100644 --- a/pkg/connector/prometheus_connector.go +++ b/pkg/connector/prometheus_connector.go @@ -195,7 +195,47 @@ func (pc *PrometheusConnector) PutFile(ctx context.Context, src []byte, dst stri // FetchFile is not supported for Prometheus connector func (pc *PrometheusConnector) FetchFile(ctx context.Context, src string, dst io.Writer) error { - return errors.New("fetchFile operation is not supported for Prometheus connector") + // Build query URL for server info + infoURL, err := url.Parse(pc.url + src) + if err != nil { + return errors.Wrap(err, "failed to parse URL for server info") + } + + // Create request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, infoURL.String(), http.NoBody) + if err != nil { + return errors.Wrap(err, "failed to create request for server info") + } + + // Add authentication headers + pc.addAuthHeaders(req) + + // Execute request + resp, err := pc.client.Do(req) + if err != nil { + return errors.Wrap(err, "failed to get prometheus server info") + } + defer resp.Body.Close() + + // Read response + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return errors.Wrap(err, "failed to read server info response body") + } + + // Check if response is successful + if resp.StatusCode != http.StatusOK { + klog.ErrorS(err, "Prometheus server info request failed", + "statusCode", resp.StatusCode, + "response", string(bodyBytes)) + return errors.Errorf("prometheus server info request failed with status %d", resp.StatusCode) + } + + // Parse response + if _, err := io.Copy(dst, resp.Body); err != nil { + return errors.Wrap(err, "failed to copy response") + } + return nil } // ExecuteCommand executes a PromQL query and returns both stdout and stderr @@ -586,61 +626,3 @@ func addValueAndTimestamp(builder *strings.Builder, sample map[string]any, metri return nil } - -// GetServerInfo returns information about the Prometheus server -// This is useful for checking server version, uptime, and other details -func (pc *PrometheusConnector) GetServerInfo(ctx context.Context) (map[string]any, error) { - if !pc.connected { - return nil, errors.New("prometheus connector is not initialized, call Init() first") - } - - klog.V(4).InfoS("Getting Prometheus server information") - - // Build query URL for server info - infoURL, err := url.Parse(pc.url + "api/v1/status/buildinfo") - if err != nil { - return nil, errors.Wrap(err, "failed to parse URL for server info") - } - - // Create request - req, err := http.NewRequestWithContext(ctx, http.MethodGet, infoURL.String(), http.NoBody) - if err != nil { - return nil, errors.Wrap(err, "failed to create request for server info") - } - - // Add authentication headers - pc.addAuthHeaders(req) - - // Execute request - resp, err := pc.client.Do(req) - if err != nil { - klog.ErrorS(err, "Failed to get Prometheus server info") - return nil, errors.Wrap(err, "failed to get prometheus server info") - } - defer resp.Body.Close() - - // Read response - bodyBytes, err := io.ReadAll(resp.Body) - if err != nil { - klog.ErrorS(err, "Failed to read server info response body") - return nil, errors.Wrap(err, "failed to read server info response body") - } - - // Check if response is successful - if resp.StatusCode != http.StatusOK { - klog.ErrorS(err, "Prometheus server info request failed", - "statusCode", resp.StatusCode, - "response", string(bodyBytes)) - return nil, errors.Errorf("prometheus server info request failed with status %d", resp.StatusCode) - } - - // Parse response - var result map[string]any - if err := json.Unmarshal(bodyBytes, &result); err != nil { - klog.ErrorS(err, "Failed to parse server info response") - return nil, errors.Wrap(err, "failed to parse server info response") - } - - klog.V(4).InfoS("Successfully retrieved Prometheus server information") - return result, nil -} diff --git a/pkg/executor/task_executor.go b/pkg/executor/task_executor.go index 0084b1a0..ab401102 100644 --- a/pkg/executor/task_executor.go +++ b/pkg/executor/task_executor.go @@ -14,6 +14,7 @@ import ( "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" + "k8s.io/utils/ptr" ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" _const "github.com/kubesphere/kubekey/v4/pkg/const" @@ -60,7 +61,7 @@ func (e *taskExecutor) Exec(ctx context.Context) error { if e.task.IsFailed() { failedMsg := "\n" for _, result := range e.task.Status.HostResults { - if result.StdErr != "" { + if result.Error != "" { failedMsg += fmt.Sprintf("[%s]: %s\n", result.Host, result.StdErr) } } @@ -116,7 +117,7 @@ func (e *taskExecutor) execTask(ctx context.Context) { // host result for task e.task.Status.Phase = kkcorev1alpha1.TaskPhaseSuccess for _, data := range e.task.Status.HostResults { - if data.StdErr != "" { + if data.Error != "" { if e.task.Spec.IgnoreError != nil && *e.task.Spec.IgnoreError { e.task.Status.Phase = kkcorev1alpha1.TaskPhaseIgnored } else { @@ -133,37 +134,41 @@ func (e *taskExecutor) execTask(ctx context.Context) { func (e *taskExecutor) execTaskHost(i int, h string) func(ctx context.Context) { return func(ctx context.Context) { // task result - var stdout, stderr string + var resErr error + var stdout, stderr, errMsg string + // task log + deferFunc := e.execTaskHostLogs(ctx, h, &stdout, &stderr, &errMsg) + defer deferFunc() defer func() { - if err := e.dealRegister(stdout, stderr, h); err != nil { - stderr = err.Error() - } - if stderr != "" && e.task.Spec.IgnoreError != nil && *e.task.Spec.IgnoreError { - klog.V(5).ErrorS(nil, "task run failed", "host", h, "stdout", stdout, "stderr", stderr, "task", ctrlclient.ObjectKeyFromObject(e.task)) - } else if stderr != "" { - klog.ErrorS(nil, "task run failed", "host", h, "stdout", stdout, "stderr", stderr, "task", ctrlclient.ObjectKeyFromObject(e.task)) + if resErr != nil { + errMsg = resErr.Error() + if e.task.Spec.IgnoreError != nil && *e.task.Spec.IgnoreError { + klog.V(5).ErrorS(resErr, "task run failed", "host", h, "stdout", stdout, "stderr", stderr, "error", errMsg, "task", ctrlclient.ObjectKeyFromObject(e.task)) + } else { + klog.ErrorS(nil, "task run failed", "host", h, "stdout", stdout, "stderr", stderr, "error", errMsg, "task", ctrlclient.ObjectKeyFromObject(e.task)) + } } + resErr = errors.Join(resErr, e.dealRegister(h, stdout, stderr, errMsg)) + // fill result e.task.Status.HostResults[i] = kkcorev1alpha1.TaskHostResult{ Host: h, Stdout: stdout, StdErr: stderr, + Error: errMsg, } }() - // task log - deferFunc := e.execTaskHostLogs(ctx, h, &stdout, &stderr) - defer deferFunc() // task execute ha, err := e.variable.Get(variable.GetAllVariable(h)) if err != nil { - stderr = fmt.Sprintf("failed to get host %s variable: %v", h, err) - + resErr = err return } // convert hostVariable to map had, ok := ha.(map[string]any) if !ok { - stderr = fmt.Sprintf("host: %s variable is not a map", h) + resErr = errors.Errorf("host: %s variable is not a map", h) + return } // check when condition if skip := e.dealWhen(had, &stdout, &stderr); skip { @@ -172,14 +177,14 @@ func (e *taskExecutor) execTaskHost(i int, h string) func(ctx context.Context) { // execute module in loop with loop item. // if loop is empty. execute once, and the item is null for _, item := range e.dealLoop(had) { - e.executeModule(ctx, e.task, item, h, &stdout, &stderr) + resErr = e.executeModule(ctx, e.task, item, h, &stdout, &stderr) } } } // execTaskHostLogs sets up and manages progress bar logging for task execution on a host. // It returns a cleanup function to be called when execution completes. -func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, stderr *string) func() { +func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, _, errMsg *string) func() { // placeholder format task log var placeholder string if hostnameMaxLen, err := e.variable.Get(variable.GetHostMaxLength()); err == nil { @@ -206,7 +211,7 @@ func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, s bar := progressbar.NewOptions(-1, options...) // run progress go func() { - err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(context.Context) (bool, error) { + if err := wait.PollUntilContextCancel(ctx, 100*time.Millisecond, true, func(context.Context) (bool, error) { if bar.IsFinished() { return true, nil } @@ -215,15 +220,14 @@ func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, s } return false, nil - }) - if err != nil { + }); err != nil { klog.ErrorS(err, "failed to wait for task run to finish", "host", h) } }() return func() { switch { - case *stderr != "": + case ptr.Deref(errMsg, "") != "": if e.task.Spec.IgnoreError != nil && *e.task.Spec.IgnoreError { // ignore bar.Describe(fmt.Sprintf("[\033[36m%s\033[0m]%s \033[34mignore \033[0m", h, placeholder)) if e.logOutput != os.Stdout { @@ -253,20 +257,18 @@ func (e *taskExecutor) execTaskHostLogs(ctx context.Context, h string, stdout, s } // executeModule executes a single module task on a specific host. -func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.Task, item any, host string, stdout, stderr *string) { +func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.Task, item any, host string, stdout, stderr *string) (resErr error) { // Set loop item variable if one was provided if item != nil { // Convert item to runtime variable node, err := converter.ConvertMap2Node(map[string]any{_const.VariableItem: item}) if err != nil { - *stderr = fmt.Sprintf("convert loop item error: %v", err) - return + return errors.Wrap(err, "failed to convert loop item") } // Merge item into host's runtime variables if err := e.variable.Merge(variable.MergeRuntimeVariable(node, host)); err != nil { - *stderr = fmt.Sprintf("set loop item to variable error: %v", err) - return + return errors.Wrap(err, "failed to set loop item to variable") } // Clean up loop item variable after execution @@ -277,11 +279,11 @@ func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.T // Reset item to null resetNode, err := converter.ConvertMap2Node(map[string]any{_const.VariableItem: nil}) if err != nil { - *stderr = fmt.Sprintf("convert loop item error: %v", err) + resErr = errors.Wrap(err, "failed to convert loop item") return } if err := e.variable.Merge(variable.MergeRuntimeVariable(resetNode, host)); err != nil { - *stderr = fmt.Sprintf("clean loop item to variable error: %v", err) + resErr = errors.Wrap(err, "failed to clean loop item to variable") return } }() @@ -290,19 +292,17 @@ func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.T // Get all variables for this host, including any loop item ha, err := e.variable.Get(variable.GetAllVariable(host)) if err != nil { - *stderr = fmt.Sprintf("failed to get host %s variable: %v", host, err) - return + return errors.Wrapf(err, "failed to get host %s variable", host) } // Convert host variables to map type had, ok := ha.(map[string]any) if !ok { - *stderr = fmt.Sprintf("host: %s variable is not a map", host) - return + return errors.Wrapf(err, "host %s variable is not a map", host) } // Execute the actual module with the prepared context - *stdout, *stderr = modules.FindModule(task.Spec.Module.Name)(ctx, modules.ExecOptions{ + *stdout, *stderr, resErr = modules.FindModule(task.Spec.Module.Name)(ctx, modules.ExecOptions{ Args: e.task.Spec.Module.Args, Host: host, Variable: e.variable, @@ -310,8 +310,7 @@ func (e *taskExecutor) executeModule(ctx context.Context, task *kkcorev1alpha1.T Playbook: *e.playbook, LogOutput: e.logOutput, }) - - e.dealFailedWhen(had, stderr) + return e.dealFailedWhen(had, resErr) } // dealLoop parses the loop specification into a slice of items to iterate over. @@ -353,38 +352,49 @@ func (e *taskExecutor) dealWhen(had map[string]any, stdout, stderr *string) bool // dealFailedWhen evaluates the "failed_when" conditions for a task to determine if it should fail. // Returns true if the task should be marked as failed, false if it should proceed. -func (e *taskExecutor) dealFailedWhen(had map[string]any, stderr *string) { +func (e *taskExecutor) dealFailedWhen(had map[string]any, err error) error { + if err != nil { + return err + } if len(e.task.Spec.FailedWhen) > 0 { ok, err := tmpl.ParseBool(had, e.task.Spec.FailedWhen...) if err != nil { - klog.V(5).ErrorS(err, "validate failed_when condition error", "task", ctrlclient.ObjectKeyFromObject(e.task)) - *stderr = fmt.Sprintf("parse failed_when condition error: %v", err) + return errors.Wrap(err, "failed to parse failed_when condition") } if ok { - *stderr = "reach failed_when, failed" + return errors.New("reach failed_when, failed") } } + return nil } // dealRegister handles storing task output in a registered variable if specified. // The output can be stored as raw string, JSON, or YAML based on the register type. -func (e *taskExecutor) dealRegister(stdout, stderr, host string) error { +func (e *taskExecutor) dealRegister(host string, stdout, stderr, errMsg string) error { if e.task.Spec.Register != "" { var stdoutResult any = stdout var stderrResult any = stderr - switch e.task.Spec.RegisterType { + switch e.task.Spec.RegisterType { // if failed the stdout may not be json or yaml case "json": - _ = json.Unmarshal([]byte(stdout), &stdoutResult) + if err := json.Unmarshal([]byte(stdout), &stdoutResult); err != nil { + klog.V(5).ErrorS(err, "failed to register json value") + } case "yaml", "yml": - _ = yaml.Unmarshal([]byte(stdout), &stdoutResult) + if err := yaml.Unmarshal([]byte(stdout), &stdoutResult); err != nil { + klog.V(5).ErrorS(err, "failed to register yaml value") + } default: // store by string + if s, ok := stdoutResult.(string); ok { + stdoutResult = strings.TrimRight(s, "\n") + } } // set variable to parent location node, err := converter.ConvertMap2Node(map[string]any{ e.task.Spec.Register: map[string]any{ "stdout": stdoutResult, "stderr": stderrResult, + "error": errMsg, }, }) if err != nil { diff --git a/pkg/modules/add_hostvars.go b/pkg/modules/add_hostvars.go index 6748b32a..6ab452ca 100644 --- a/pkg/modules/add_hostvars.go +++ b/pkg/modules/add_hostvars.go @@ -2,7 +2,6 @@ package modules import ( "context" - "fmt" "github.com/cockroachdb/errors" "gopkg.in/yaml.v3" @@ -84,32 +83,32 @@ func newAddHostvarsArgs(_ context.Context, raw runtime.RawExtension, vars map[st // ModuleAddHostvars handles the "add_hostvars" module, merging variables into the specified hosts. // Returns empty stdout and stderr on success, or error message in stderr on failure. -func ModuleAddHostvars(ctx context.Context, options ExecOptions) (string, string) { +func ModuleAddHostvars(ctx context.Context, options ExecOptions) (string, string, error) { // Get all host variables (for context, not used directly here). ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } // Parse module arguments. args, err := newAddHostvarsArgs(ctx, options.Args, ha) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } ahn, err := options.Variable.Get(variable.GetHostnames(args.hosts)) if err != nil { - return "", err.Error() + return StdoutFailed, "failed to get hostnames", err } hosts, ok := ahn.([]string) if !ok { - return "", "failed to get actual hosts from given \"hosts\"" + return StdoutFailed, "failed to get actual hosts from given \"hosts\"", errors.Errorf("failed to get actual hosts from given \"hosts\"") } // Merge the provided variables into the specified hosts. if err := options.Variable.Merge(variable.MergeHostsRuntimeVariable(args.vars, options.Host, hosts...)); err != nil { - return "", fmt.Sprintf("add_hostvars error: %v", err) + return StdoutFailed, "failed to add_hostvars", errors.Wrap(err, "failed to add_hostvars") } - return "", "" + return StdoutSuccess, "", nil } func init() { diff --git a/pkg/modules/add_hostvars_test.go b/pkg/modules/add_hostvars_test.go index 27c98ffd..9f385fd4 100644 --- a/pkg/modules/add_hostvars_test.go +++ b/pkg/modules/add_hostvars_test.go @@ -14,7 +14,6 @@ func TestModuleAddHostvars(t *testing.T) { name string opt ExecOptions expectStdout string - expectStderr string } cases := []testcase{ { @@ -29,8 +28,7 @@ vars: `), }, }, - expectStdout: "", - expectStderr: "\"hosts\" should be string or string array", + expectStdout: StdoutFailed, }, { name: "missing vars", @@ -43,8 +41,7 @@ hosts: node1 `), }, }, - expectStdout: "", - expectStderr: "\"vars\" should not be empty", + expectStdout: StdoutFailed, }, { name: "invalid hosts type", @@ -60,8 +57,7 @@ vars: `), }, }, - expectStdout: "", - expectStderr: "\"hosts\" should be string or string array", + expectStdout: StdoutFailed, }, { name: "string value", @@ -76,6 +72,7 @@ vars: `), }, }, + expectStdout: StdoutSuccess, }, { name: "string var value", @@ -90,6 +87,7 @@ vars: `), }, }, + expectStdout: StdoutSuccess, }, { name: "map value", @@ -105,6 +103,7 @@ vars: `), }, }, + expectStdout: StdoutSuccess, }, } @@ -112,9 +111,8 @@ vars: t.Run(tc.name, func(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() - stdout, stderr := ModuleAddHostvars(ctx, tc.opt) + stdout, _, _ := ModuleAddHostvars(ctx, tc.opt) require.Equal(t, tc.expectStdout, stdout, "stdout mismatch") - require.Equal(t, tc.expectStderr, stderr, "stderr mismatch") }) } } diff --git a/pkg/modules/assert.go b/pkg/modules/assert.go index 1dad3ae8..8f173a8c 100644 --- a/pkg/modules/assert.go +++ b/pkg/modules/assert.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" "github.com/cockroachdb/errors" kkprojectv1 "github.com/kubesphere/kubekey/api/project/v1" @@ -105,51 +104,51 @@ func newAssertArgs(_ context.Context, raw runtime.RawExtension, vars map[string] } aa.successMsg, _ = variable.StringVar(vars, args, "success_msg") if aa.successMsg == "" { - aa.successMsg = StdoutTrue + aa.successMsg = StdoutSuccess } aa.failMsg, _ = variable.StringVar(vars, args, "fail_msg") if aa.failMsg == "" { - aa.failMsg = StdoutFalse + aa.failMsg = StdoutFailed } aa.msg, _ = variable.StringVar(vars, args, "msg") if aa.msg == "" { - aa.msg = StdoutFalse + aa.msg = StdoutFailed } return aa, nil } // ModuleAssert handles the "assert" module, evaluating boolean conditions and returning appropriate messages -func ModuleAssert(ctx context.Context, options ExecOptions) (string, string) { +func ModuleAssert(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } aa, err := newAssertArgs(ctx, options.Args, ha) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } ok, err := tmpl.ParseBool(ha, aa.that...) if err != nil { - return "", fmt.Sprintf("parse \"that\" error: %v", err) + return StdoutFailed, "failed to parse argument of that", err } // condition is true if ok { - return aa.successMsg, "" + return aa.successMsg, "", nil } // condition is false and fail_msg is not empty if aa.failMsg != "" { - return "", aa.failMsg + return StdoutFailed, aa.failMsg, errors.New(aa.failMsg) } // condition is false and msg is not empty if aa.msg != "" { - return "", aa.msg + return StdoutFailed, aa.msg, errors.New(aa.msg) } - return StdoutFalse, "False" + return StdoutFailed, StdoutFailed, errors.New(StdoutFailed) } func init() { diff --git a/pkg/modules/assert_test.go b/pkg/modules/assert_test.go index 79296107..39907a40 100644 --- a/pkg/modules/assert_test.go +++ b/pkg/modules/assert_test.go @@ -30,7 +30,6 @@ func TestAssert(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "non-that", @@ -39,7 +38,7 @@ func TestAssert(t *testing.T) { Variable: newTestVariable(nil, nil), Args: runtime.RawExtension{}, }, - exceptStderr: "\"that\" should be []string or string", + exceptStdout: StdoutFailed, }, { name: "success with non-msg", @@ -52,7 +51,7 @@ func TestAssert(t *testing.T) { "testvalue": "a", }), }, - exceptStdout: StdoutTrue, + exceptStdout: StdoutSuccess, }, { name: "success with success_msg", @@ -80,7 +79,7 @@ func TestAssert(t *testing.T) { "k2": "v2", }), }, - exceptStderr: "False", + exceptStdout: StdoutFailed, }, { name: "failed with failed_msg", @@ -94,7 +93,7 @@ func TestAssert(t *testing.T) { "k2": "v2", }), }, - exceptStderr: "failed v2", + exceptStdout: StdoutFailed, }, } @@ -103,9 +102,8 @@ func TestAssert(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleAssert(ctx, tc.opt) + acStdout, _, _ := ModuleAssert(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } diff --git a/pkg/modules/command.go b/pkg/modules/command.go index 2cdd4ad4..efc2ae7e 100644 --- a/pkg/modules/command.go +++ b/pkg/modules/command.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -62,29 +61,26 @@ Return Values: */ // ModuleCommand handles the "command" module, executing shell commands on remote hosts -func ModuleCommand(ctx context.Context, options ExecOptions) (string, string) { +func ModuleCommand(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } // get connector conn, err := options.getConnector(ctx) if err != nil { - return "", fmt.Sprintf("failed to connector for %q error: %v", options.Host, err) + return StdoutFailed, StderrGetConnector, err } defer conn.Close(ctx) // command string command, err := variable.Extension2String(ha, options.Args) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } // execute command stdout, stderr, err := conn.ExecuteCommand(ctx, string(command)) - if err != nil { - return "", err.Error() - } - return string(stdout), string(stderr) + return string(stdout), string(stderr), err } func init() { diff --git a/pkg/modules/command_test.go b/pkg/modules/command_test.go index a9ab99a9..c8b980a0 100644 --- a/pkg/modules/command_test.go +++ b/pkg/modules/command_test.go @@ -18,6 +18,7 @@ package modules import ( "context" + "errors" "testing" "time" @@ -31,12 +32,11 @@ func TestCommand(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "exec command success", ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, opt: ExecOptions{ Host: "test", @@ -46,14 +46,16 @@ func TestCommand(t *testing.T) { exceptStdout: "success", }, { - name: "exec command failed", - ctxFunc: func() context.Context { return context.WithValue(context.Background(), ConnKey, failedConnector) }, + name: "exec command failed", + ctxFunc: func() context.Context { + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutFailed, StdoutFailed, errors.New(StdoutFailed))) + }, opt: ExecOptions{ Host: "test", Args: runtime.RawExtension{Raw: []byte("echo success")}, Variable: newTestVariable(nil, nil), }, - exceptStderr: "failed", + exceptStdout: "failed", }, } @@ -62,9 +64,8 @@ func TestCommand(t *testing.T) { ctx, cancel := context.WithTimeout(tc.ctxFunc(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleCommand(ctx, tc.opt) + acStdout, _, _ := ModuleCommand(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } diff --git a/pkg/modules/copy.go b/pkg/modules/copy.go index cc88e7c8..d2b77828 100644 --- a/pkg/modules/copy.go +++ b/pkg/modules/copy.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" "io/fs" "math" "os" @@ -118,22 +117,22 @@ func newCopyArgs(_ context.Context, raw runtime.RawExtension, vars map[string]an } // ModuleCopy handles the "copy" module, copying files or content to remote hosts -func ModuleCopy(ctx context.Context, options ExecOptions) (string, string) { +func ModuleCopy(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } ca, err := newCopyArgs(ctx, options.Args, ha) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } // get connector conn, err := options.getConnector(ctx) if err != nil { - return "", fmt.Sprintf("get connector error: %v", err) + return StdoutFailed, StderrGetConnector, err } defer conn.Close(ctx) @@ -143,12 +142,12 @@ func ModuleCopy(ctx context.Context, options ExecOptions) (string, string) { case ca.content != "": return ca.copyContent(ctx, os.ModePerm, conn) default: - return "", "either \"src\" or \"content\" must be provided." + return StdoutFailed, StderrUnsupportArgs, errors.New("either \"src\" or \"content\" must be provided") } } // copySrc copy src file to dest -func (ca copyArgs) copySrc(ctx context.Context, options ExecOptions, conn connector.Connector) (string, string) { +func (ca copyArgs) copySrc(ctx context.Context, options ExecOptions, conn connector.Connector) (string, string, error) { if filepath.IsAbs(ca.src) { // if src is absolute path. find it in local path return ca.handleAbsolutePath(ctx, conn) } @@ -156,62 +155,60 @@ func (ca copyArgs) copySrc(ctx context.Context, options ExecOptions, conn connec return ca.handleRelativePath(ctx, options, conn) } -func (ca copyArgs) handleAbsolutePath(ctx context.Context, conn connector.Connector) (string, string) { +func (ca copyArgs) handleAbsolutePath(ctx context.Context, conn connector.Connector) (string, string, error) { fileInfo, err := os.Stat(ca.src) if err != nil { - return "", fmt.Sprintf(" get src file %s in local path error: %v", ca.src, err) + return StdoutFailed, "failed to stat absolute path", err } if fileInfo.IsDir() { // src is dir if err := ca.absDir(ctx, conn); err != nil { - return "", fmt.Sprintf("sync copy absolute dir error %s", err) + return StdoutFailed, "failed to copy absolute dir", err } - - return StdoutSuccess, "" + return StdoutSuccess, "", nil } // src is file data, err := os.ReadFile(ca.src) if err != nil { - return "", fmt.Sprintf("read file error: %s", err) + return StdoutFailed, "failed to read absolute file", err } if err := ca.readFile(ctx, data, fileInfo.Mode(), conn); err != nil { - return "", fmt.Sprintf("sync copy absolute dir error %s", err) + return StdoutFailed, "failed to copy absolute file", err } - - return StdoutSuccess, "" + return StdoutSuccess, "", nil } -func (ca copyArgs) handleRelativePath(ctx context.Context, options ExecOptions, conn connector.Connector) (string, string) { +func (ca copyArgs) handleRelativePath(ctx context.Context, options ExecOptions, conn connector.Connector) (string, string, error) { pj, err := project.New(ctx, options.Playbook, false) if err != nil { - return "", fmt.Sprintf("get project error: %v", err) + return StdoutFailed, "failed to get playbook", err } relPath := filepath.Join(options.Task.Annotations[kkcorev1alpha1.TaskAnnotationRelativePath], _const.ProjectRolesFilesDir, ca.src) fileInfo, err := pj.Stat(relPath) if err != nil { - return "", fmt.Sprintf("get file %s from project error %v", ca.src, err) + return StdoutFailed, "failed to stat relative path", err } if fileInfo.IsDir() { if err := ca.handleRelativeDir(ctx, pj, relPath, conn); err != nil { - return "", fmt.Sprintf("sync copy relative dir error %s", err) + return StdoutFailed, "failed to copy relative dir", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } // Handle single file data, err := pj.ReadFile(relPath) if err != nil { - return "", fmt.Sprintf("read file error: %s", err) + return StdoutFailed, "failed to read relative file", err } if err := ca.readFile(ctx, data, fileInfo.Mode(), conn); err != nil { - return "", fmt.Sprintf("sync copy relative dir error %s", err) + return StdoutFailed, "failed to copy relative file", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func (ca copyArgs) handleRelativeDir(ctx context.Context, pj project.Project, relPath string, conn connector.Connector) error { @@ -252,9 +249,9 @@ func (ca copyArgs) handleRelativeDir(ctx context.Context, pj project.Project, re } // copyContent convert content param and copy to dest -func (ca copyArgs) copyContent(ctx context.Context, mode fs.FileMode, conn connector.Connector) (string, string) { +func (ca copyArgs) copyContent(ctx context.Context, mode fs.FileMode, conn connector.Connector) (string, string, error) { if strings.HasSuffix(ca.dest, "/") { - return "", "\"content\" should copy to a file" + return StdoutFailed, StderrUnsupportArgs, errors.New("\"content\" should copy to a file") } if ca.mode != nil { @@ -262,10 +259,10 @@ func (ca copyArgs) copyContent(ctx context.Context, mode fs.FileMode, conn conne } if err := conn.PutFile(ctx, []byte(ca.content), ca.dest, mode); err != nil { - return "", fmt.Sprintf("copy file error: %v", err) + return StdoutFailed, "failed to copy file", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } // absFile when copy.src is absolute file, get file from os, and copy to remote. diff --git a/pkg/modules/copy_test.go b/pkg/modules/copy_test.go index 9e48c85b..5d7ce95c 100644 --- a/pkg/modules/copy_test.go +++ b/pkg/modules/copy_test.go @@ -21,6 +21,7 @@ import ( "testing" "time" + "github.com/cockroachdb/errors" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/runtime" ) @@ -31,7 +32,6 @@ func TestCopy(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "src and content is empty", @@ -43,9 +43,9 @@ func TestCopy(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStderr: "either \"src\" or \"content\" must be provided.", + exceptStdout: StdoutFailed, }, { name: "dest is empty", @@ -57,9 +57,9 @@ func TestCopy(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStderr: "\"dest\" in args should be string", + exceptStdout: StdoutFailed, }, { name: "content not copy to file", @@ -71,9 +71,9 @@ func TestCopy(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStderr: "\"content\" should copy to a file", + exceptStdout: StdoutFailed, }, { name: "copy success", @@ -85,7 +85,7 @@ func TestCopy(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, exceptStdout: StdoutSuccess, }, @@ -99,9 +99,9 @@ func TestCopy(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, failedConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutFailed, StdoutFailed, errors.New(StdoutFailed))) }, - exceptStderr: "copy file error: failed", + exceptStdout: StdoutFailed, }, } @@ -110,9 +110,8 @@ func TestCopy(t *testing.T) { ctx, cancel := context.WithTimeout(tc.ctxFunc(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleCopy(ctx, tc.opt) + acStdout, _, _ := ModuleCopy(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } diff --git a/pkg/modules/debug.go b/pkg/modules/debug.go index 71c18c8a..9a96daa8 100644 --- a/pkg/modules/debug.go +++ b/pkg/modules/debug.go @@ -24,6 +24,7 @@ import ( "reflect" "strings" + "github.com/cockroachdb/errors" kkprojectv1 "github.com/kubesphere/kubekey/api/project/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -64,37 +65,37 @@ Return Values: */ // ModuleDebug handles the "debug" module, printing debug information -func ModuleDebug(_ context.Context, options ExecOptions) (string, string) { +func ModuleDebug(_ context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } args := variable.Extension2Variables(options.Args) v := reflect.ValueOf(args["msg"]) switch v.Kind() { case reflect.Invalid: - return "", "\"msg\" is not found" + return StdoutFailed, StderrUnsupportArgs, errors.New("\"msg\" is not found") case reflect.String: if !kkprojectv1.IsTmplSyntax(v.String()) { - return formatOutput([]byte(v.String()), options.LogOutput), "" + return formatOutput([]byte(v.String()), options.LogOutput), "", nil } val := kkprojectv1.TrimTmplSyntax(v.String()) if !strings.HasPrefix(val, ".") { - return "", "error tmpl value syntax" + return StdoutFailed, StderrUnsupportArgs, errors.New("error tmpl value syntax") } data, err := variable.PrintVar(ha, strings.Split(val, ".")[1:]...) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } - return formatOutput(data, options.LogOutput), "" + return formatOutput(data, options.LogOutput), "", nil default: // do not parse by ctx data, err := json.Marshal(v.Interface()) if err != nil { - return "", err.Error() + return StdoutFailed, "failed to marshal value to json", err } - return formatOutput(data, options.LogOutput), "" + return formatOutput(data, options.LogOutput), "", nil } } diff --git a/pkg/modules/debug_test.go b/pkg/modules/debug_test.go index 63e418f5..0854a0bc 100644 --- a/pkg/modules/debug_test.go +++ b/pkg/modules/debug_test.go @@ -30,7 +30,6 @@ func TestDebug(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "non-var and non-msg", @@ -39,7 +38,7 @@ func TestDebug(t *testing.T) { Host: "node1", Variable: newTestVariable(nil, nil), }, - exceptStderr: "\"msg\" is not found", + exceptStdout: StdoutFailed, }, { name: "string value", @@ -91,9 +90,8 @@ func TestDebug(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleDebug(ctx, tc.opt) + acStdout, _, _ := ModuleDebug(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } diff --git a/pkg/modules/fetch.go b/pkg/modules/fetch.go index 0df75c1c..1ea5cfdc 100644 --- a/pkg/modules/fetch.go +++ b/pkg/modules/fetch.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" "os" "path/filepath" @@ -63,48 +62,48 @@ Return Values: */ // ModuleFetch handles the "fetch" module, retrieving files from remote hosts -func ModuleFetch(ctx context.Context, options ExecOptions) (string, string) { +func ModuleFetch(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } // check args args := variable.Extension2Variables(options.Args) srcParam, err := variable.StringVar(ha, args, "src") if err != nil { - return "", "\"src\" in args should be string" + return StdoutFailed, "\"src\" in args should be string", err } destParam, err := variable.StringVar(ha, args, "dest") if err != nil { - return "", "\"dest\" in args should be string" + return StdoutFailed, "\"dest\" in args should be string", err } // get connector conn, err := options.getConnector(ctx) if err != nil { - return "", fmt.Sprintf("get connector error: %v", err) + return StdoutFailed, StderrGetConnector, err } defer conn.Close(ctx) // fetch file if _, err := os.Stat(filepath.Dir(destParam)); os.IsNotExist(err) { if err := os.MkdirAll(filepath.Dir(destParam), os.ModePerm); err != nil { - return "", fmt.Sprintf("failed to create dest dir: %v", err) + return StdoutFailed, "failed to create dest dir", err } } destFile, err := os.Create(destParam) if err != nil { - return "", err.Error() + return StdoutFailed, "failed to create dest file", err } defer destFile.Close() if err := conn.FetchFile(ctx, srcParam, destFile); err != nil { - return "", fmt.Sprintf("failed to fetch file: %v", err) + return StdoutFailed, "failed to fetch file", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func init() { diff --git a/pkg/modules/fetch_test.go b/pkg/modules/fetch_test.go index 09bedde4..71946e1f 100644 --- a/pkg/modules/fetch_test.go +++ b/pkg/modules/fetch_test.go @@ -31,7 +31,6 @@ func TestFetch(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "src is empty", @@ -41,9 +40,9 @@ func TestFetch(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStderr: "\"src\" in args should be string", + exceptStdout: StdoutFailed, }, { name: "dest is empty", @@ -55,9 +54,9 @@ func TestFetch(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStderr: "\"dest\" in args should be string", + exceptStdout: StdoutFailed, }, } @@ -66,9 +65,8 @@ func TestFetch(t *testing.T) { ctx, cancel := context.WithTimeout(tc.ctxFunc(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleFetch(ctx, tc.opt) + acStdout, _, _ := ModuleFetch(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } diff --git a/pkg/modules/gen_cert.go b/pkg/modules/gen_cert.go index 8ff01947..ceec479a 100644 --- a/pkg/modules/gen_cert.go +++ b/pkg/modules/gen_cert.go @@ -112,35 +112,35 @@ type genCertArgs struct { } // signedCertificate generates a certificate signed by the root certificate -func (gca genCertArgs) signedCertificate(cfg cgutilcert.Config) (string, string) { +func (gca genCertArgs) signedCertificate(cfg cgutilcert.Config) (string, string, error) { // Load CA private key caKey, err := TryLoadKeyFromDisk(gca.rootKey) if err != nil { - return "", fmt.Sprintf("failed to load root key: %v", err) + return StdoutFailed, "failed to load root key", err } // Load CA certificate caCert, _, err := TryLoadCertChainFromDisk(gca.rootCert) if err != nil { - return "", fmt.Sprintf("failed to load root certificate: %v", err) + return StdoutFailed, "failed to load root cert", err } // Function to generate and write new certificate and key - generateAndWrite := func() (string, string) { + generateAndWrite := func() (string, string, error) { newKey, err := rsa.GenerateKey(cryptorand.Reader, rsaKeySize) if err != nil { - return "", fmt.Sprintf("generate rsa key error: %v", err) + return StdoutFailed, "failed to generate rsa key", err } newCert, err := NewSignedCert(cfg, gca.date, newKey, caCert, caKey, ptr.Deref(gca.isCA, false)) if err != nil { - return "", fmt.Sprintf("failed to generate certificate: %v", err) + return StdoutFailed, "failed to generate signed cert", err } if err := WriteKey(gca.outKey, newKey, gca.policy); err != nil { - return "", fmt.Sprintf("failed to write key: %v", err) + return StdoutFailed, "failed to write out key", err } if err := WriteCert(gca.outCert, newCert, gca.policy); err != nil { - return "", fmt.Sprintf("failed to write certificate: %v", err) + return StdoutFailed, "failed to write out cert", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } switch gca.policy { @@ -158,18 +158,18 @@ func (gca genCertArgs) signedCertificate(cfg cgutilcert.Config) (string, string) } // Validate certificate period if err := ValidateCertPeriod(existCert, 0); err != nil { - return "", fmt.Sprintf("failed to ValidateCertPeriod: %v", err) + return StdoutFailed, "failed to validate cert period", err } // Validate certificate chain if err := VerifyCertChain(existCert, existIntermediates, caCert); err != nil { - return "", fmt.Sprintf("failed to VerifyCertChain: %v", err) + return StdoutFailed, "failed to validate cert chain", err } // Validate certificate SAN and other config if err := validateCertificateWithConfig(existCert, gca.outCert, cfg); err != nil { - return "", fmt.Sprintf("failed to validateCertificateWithConfig: %v", err) + return StdoutFailed, "failed to validate cert config", err } // Existing certificate and key are valid, skip generation - return StdoutSkip, "" + return StdoutSkip, "", nil default: // Otherwise, always generate new certificate and key return generateAndWrite() @@ -177,25 +177,25 @@ func (gca genCertArgs) signedCertificate(cfg cgutilcert.Config) (string, string) } // selfSignedCertificate generate Self-signed certificate -func (gca genCertArgs) selfSignedCertificate(cfg cgutilcert.Config) (string, string) { +func (gca genCertArgs) selfSignedCertificate(cfg cgutilcert.Config) (string, string, error) { newKey, err := rsa.GenerateKey(cryptorand.Reader, rsaKeySize) if err != nil { - return "", fmt.Sprintf("generate rsa key error: %v", err) + return StdoutFailed, "failed to generate rsa key", err } newCert, err := NewSelfSignedCACert(cfg, gca.date, newKey) if err != nil { - return "", fmt.Sprintf("failed to generate self-signed certificate: %v", err) + return StdoutFailed, "failed to generate ca cert", err } // write key and cert to file if err := WriteKey(gca.outKey, newKey, gca.policy); err != nil { - return "", fmt.Sprintf("failed to write key: %v", err) + return StdoutFailed, "failed to write out key", err } if err := WriteCert(gca.outCert, newCert, gca.policy); err != nil { - return "", fmt.Sprintf("failed to write certificate: %v", err) + return StdoutFailed, "failed to write out cert", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func newGenCertArgs(_ context.Context, raw runtime.RawExtension, vars map[string]any) (*genCertArgs, error) { @@ -226,16 +226,16 @@ func newGenCertArgs(_ context.Context, raw runtime.RawExtension, vars map[string } // ModuleGenCert handles the "gen_cert" module, generating SSL/TLS certificates -func ModuleGenCert(ctx context.Context, options ExecOptions) (string, string) { +func ModuleGenCert(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } gca, err := newGenCertArgs(ctx, options.Args, ha) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } cfg := &cgutilcert.Config{ diff --git a/pkg/modules/gen_cert_test.go b/pkg/modules/gen_cert_test.go index 4322169c..b826c835 100644 --- a/pkg/modules/gen_cert_test.go +++ b/pkg/modules/gen_cert_test.go @@ -30,7 +30,6 @@ func TestModuleGenCert(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "gen root cert", @@ -62,9 +61,8 @@ func TestModuleGenCert(t *testing.T) { for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { - stdout, stderr := ModuleGenCert(context.Background(), testcase.opt) + stdout, _, _ := ModuleGenCert(context.Background(), testcase.opt) assert.Equal(t, testcase.exceptStdout, stdout) - assert.Equal(t, testcase.exceptStderr, stderr) }) } } diff --git a/pkg/modules/image.go b/pkg/modules/image.go index 910e46ea..e9884b1d 100644 --- a/pkg/modules/image.go +++ b/pkg/modules/image.go @@ -21,7 +21,6 @@ import ( "context" "crypto/tls" "encoding/json" - "fmt" "io" "io/fs" "net/http" @@ -294,32 +293,32 @@ func newImageArgs(_ context.Context, raw runtime.RawExtension, vars map[string]a } // ModuleImage handles the "image" module, managing container image operations including pulling and pushing images -func ModuleImage(ctx context.Context, options ExecOptions) (string, string) { +func ModuleImage(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err } ia, err := newImageArgs(ctx, options.Args, ha) if err != nil { - return "", err.Error() + return StdoutFailed, StderrParseArgument, err } // pull image manifests to local dir if ia.pull != nil { if err := ia.pull.pull(ctx); err != nil { - return "", fmt.Sprintf("failed to pull image: %v", err) + return StdoutFailed, "failed to pull image", err } } // push image to private registry if ia.push != nil { if err := ia.push.push(ctx, ha); err != nil { - return "", fmt.Sprintf("failed to push image: %v", err) + return StdoutFailed, "failed to push image", err } } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } // findLocalImageManifests get image manifests with whole image's name. diff --git a/pkg/modules/image_test.go b/pkg/modules/image_test.go index 4886b510..66dc0796 100644 --- a/pkg/modules/image_test.go +++ b/pkg/modules/image_test.go @@ -13,7 +13,6 @@ func TestModuleImage(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "pull is not map", @@ -25,7 +24,7 @@ func TestModuleImage(t *testing.T) { }, Variable: newTestVariable(nil, nil), }, - exceptStderr: "\"pull\" should be map", + exceptStdout: StdoutFailed, }, { name: "pull.manifests is empty", @@ -37,7 +36,7 @@ func TestModuleImage(t *testing.T) { }, Variable: newTestVariable(nil, nil), }, - exceptStderr: "\"pull.manifests\" is required", + exceptStdout: StdoutFailed, }, { name: "push is not map", @@ -49,15 +48,14 @@ func TestModuleImage(t *testing.T) { }, Variable: newTestVariable(nil, nil), }, - exceptStderr: "\"push\" should be map", + exceptStdout: StdoutFailed, }, } for _, testcase := range testcases { t.Run(testcase.name, func(t *testing.T) { - stdout, stderr := ModuleImage(context.Background(), testcase.opt) + stdout, _, _ := ModuleImage(context.Background(), testcase.opt) assert.Equal(t, testcase.exceptStdout, stdout) - assert.Equal(t, testcase.exceptStderr, stderr) }) } } diff --git a/pkg/modules/module.go b/pkg/modules/module.go index ac4614e3..8d43dcb7 100644 --- a/pkg/modules/module.go +++ b/pkg/modules/module.go @@ -37,15 +37,20 @@ const ( StdoutFailed = "failed" // StdoutSkip is the standard message indicating a skipped module execution. StdoutSkip = "skip" - // StdoutTrue is the standard message indicating a boolean true result (used in bool/assert modules). - StdoutTrue = "True" - // StdoutFalse is the standard message indicating a boolean false result (used in bool/assert modules). - StdoutFalse = "False" + + // StderrGetConnector is returned when the connector cannot be obtained. + StderrGetConnector = "failed to get connector" + // StderrGetHostVariable is returned when host variables cannot be retrieved. + StderrGetHostVariable = "failed to get host variable" + // StderrParseArgument is returned when module arguments cannot be parsed. + StderrParseArgument = "failed to parse argument" + // StderrUnsupportArgs is returned when the provided arguments are not supported. + StderrUnsupportArgs = "unsupport args" ) // ModuleExecFunc defines the function signature for executing a module. // It takes a context and ExecOptions, and returns stdout and stderr strings. -type ModuleExecFunc func(ctx context.Context, options ExecOptions) (stdout string, stderr string) +type ModuleExecFunc func(ctx context.Context, options ExecOptions) (stdout string, stderr string, err error) // ExecOptions represents options for module execution. type ExecOptions struct { diff --git a/pkg/modules/module_test.go b/pkg/modules/module_test.go index 74aeaf22..d552ec9d 100644 --- a/pkg/modules/module_test.go +++ b/pkg/modules/module_test.go @@ -21,7 +21,6 @@ import ( "io" "io/fs" - "github.com/cockroachdb/errors" "k8s.io/klog/v2" "github.com/kubesphere/kubekey/v4/pkg/connector" @@ -30,48 +29,38 @@ import ( "github.com/kubesphere/kubekey/v4/pkg/variable/source" ) -var successConnector = &testConnector{stdout: []byte("success")} -var failedConnector = &testConnector{ - copyErr: errors.New("failed"), - fetchErr: errors.New("failed"), - commandErr: errors.New("failed"), +func newTestConnector(stdout, stderr string, err error) connector.Connector { + return &testConnector{ + stdout: stdout, + stderr: stderr, + err: err, + } } -var _ connector.Connector = &testConnector{} - type testConnector struct { - // return for init - initErr error - // return for close - closeErr error - // return for copy - copyErr error - // return for fetch - fetchErr error - // return for command - stdout []byte - stderr []byte - commandErr error + stdout string + stderr string + err error } func (t testConnector) Init(context.Context) error { - return t.initErr + return t.err } func (t testConnector) Close(context.Context) error { - return t.closeErr + return t.err } func (t testConnector) PutFile(context.Context, []byte, string, fs.FileMode) error { - return t.copyErr + return t.err } func (t testConnector) FetchFile(context.Context, string, io.Writer) error { - return t.fetchErr + return t.err } func (t testConnector) ExecuteCommand(context.Context, string) ([]byte, []byte, error) { - return t.stdout, t.stderr, t.commandErr + return []byte(t.stdout), []byte(t.stderr), t.err } // newTestVariable creates a new variable.Variable for testing purposes. diff --git a/pkg/modules/prometheus.go b/pkg/modules/prometheus.go index 8fb7e193..60ba370e 100644 --- a/pkg/modules/prometheus.go +++ b/pkg/modules/prometheus.go @@ -19,11 +19,9 @@ package modules import ( "context" "encoding/json" - "fmt" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "github.com/kubesphere/kubekey/v4/pkg/connector" "github.com/kubesphere/kubekey/v4/pkg/variable" ) @@ -87,66 +85,26 @@ Format Options: */ // ModulePrometheus handles the "prometheus" module, using prometheus connector to execute PromQL queries -func ModulePrometheus(ctx context.Context, options ExecOptions) (string, string) { - // Get the hostname to execute on - host := options.Host - if host == "" { - return "", "host name is empty, please specify a prometheus host" +func ModulePrometheus(ctx context.Context, options ExecOptions) (string, string, error) { + // get host variable + ha, err := options.getAllVariables() + if err != nil { + return StdoutFailed, StderrGetHostVariable, err } // Get or create Prometheus connector conn, err := options.getConnector(ctx) if err != nil { - return "", fmt.Sprintf("failed to get prometheus connector: %v", err) - } - - // Initialize connection - if err := conn.Init(ctx); err != nil { - return "", fmt.Sprintf("failed to initialize prometheus connector: %v", err) - } - defer func() { - if closeErr := conn.Close(ctx); closeErr != nil { - // Just log the error, don't return it as we've already executed the main command - fmt.Printf("Warning: failed to close prometheus connection: %v\n", closeErr) - } - }() - - // Get all variables - ha, err := options.getAllVariables() - if err != nil { - return "", err.Error() + return StdoutFailed, "failed to get prometheus connector", err } + defer conn.Close(ctx) args := variable.Extension2Variables(options.Args) - // Check if user wants server info instead of running a query - infoOnly, _ := variable.BoolVar(ha, args, "info") - if infoOnly != nil && *infoOnly { - // Try to cast connector to PrometheusConnector - pc, ok := conn.(*connector.PrometheusConnector) - if !ok { - return "", "connector is not a prometheus connector, cannot get server info" - } - - // Get server info - info, err := pc.GetServerInfo(ctx) - if err != nil { - return "", fmt.Sprintf("failed to get prometheus server info: %v", err) - } - - // Marshal the info to JSON - infoBytes, err := json.MarshalIndent(info, "", " ") - if err != nil { - return "", fmt.Sprintf("failed to marshal server info: %v", err) - } - - return string(infoBytes), "" - } - // Get query parameters query, err := variable.StringVar(ha, args, "query") if err != nil { - return "", "failed to get prometheus query. Please provide a query parameter." + return StdoutFailed, "failed to get prometheus query. Please provide a query parameter.", err } // Get optional parameters @@ -168,16 +126,16 @@ func ModulePrometheus(ctx context.Context, options ExecOptions) (string, string) cmdBytes, err := json.Marshal(cmdMap) if err != nil { - return "", fmt.Sprintf("failed to marshal query params: %v", err) + return StdoutFailed, "failed to marshal query params", err } // Execute query result, _, err := conn.ExecuteCommand(ctx, string(cmdBytes)) if err != nil { - return "", fmt.Sprintf("failed to execute prometheus query: %v", err) + return StdoutFailed, "failed to execute prometheus query", err } - return string(result), "" + return string(result), "", nil } func init() { diff --git a/pkg/modules/prometheus_test.go b/pkg/modules/prometheus_test.go index 22c0a717..9816dc35 100644 --- a/pkg/modules/prometheus_test.go +++ b/pkg/modules/prometheus_test.go @@ -22,6 +22,7 @@ import ( "testing" "time" + "github.com/cockroachdb/errors" "github.com/stretchr/testify/assert" "k8s.io/apimachinery/pkg/runtime" ) @@ -42,7 +43,6 @@ func TestPrometheus(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "empty host", @@ -54,7 +54,7 @@ func TestPrometheus(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: context.Background, // Add context background - exceptStderr: "host name is empty, please specify a prometheus host", + exceptStdout: StdoutFailed, }, { name: "successful query", @@ -66,9 +66,9 @@ func TestPrometheus(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "failed query", @@ -80,9 +80,9 @@ func TestPrometheus(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, failedConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutFailed, StdoutFailed, errors.New(StdoutFailed))) }, - exceptStderr: "failed to execute prometheus query: failed", + exceptStdout: StdoutFailed, }, } @@ -100,14 +100,8 @@ func TestPrometheus(t *testing.T) { defer cancel() } - acStdout, acStderr := ModulePrometheus(ctx, tc.opt) + acStdout, _, _ := ModulePrometheus(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } } - -func TestPrometheusModuleRegistration(t *testing.T) { - module := FindModule("prometheus") - assert.NotNil(t, module, "Prometheus module should be registered") -} diff --git a/pkg/modules/result.go b/pkg/modules/result.go index 1dd0476a..6fb8500f 100644 --- a/pkg/modules/result.go +++ b/pkg/modules/result.go @@ -2,7 +2,6 @@ package modules import ( "context" - "fmt" "gopkg.in/yaml.v3" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -46,24 +45,27 @@ Return Values: */ // ModuleResult handles the "result" module, setting result variables during playbook execution -func ModuleResult(ctx context.Context, options ExecOptions) (string, string) { +func ModuleResult(ctx context.Context, options ExecOptions) (string, string, error) { // get host variable ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err + } + arg, err := variable.Extension2String(ha, options.Args) + if err != nil { + return StdoutFailed, StderrParseArgument, err } - arg, _ := variable.Extension2String(ha, options.Args) var result any // Unmarshal the YAML document into a root node. if err := yaml.Unmarshal(arg, &result); err != nil { - return "", fmt.Sprintf("failed to unmarshal YAML error: %v", err) + return StdoutFailed, "failed to unmarshal YAML", err } if err := options.Variable.Merge(variable.MergeResultVariable(result)); err != nil { - return "", fmt.Sprintf("result error: %v", err) + return StdoutFailed, "failed to merge result variable", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func init() { diff --git a/pkg/modules/result_test.go b/pkg/modules/result_test.go index 26d7236f..6cdea678 100644 --- a/pkg/modules/result_test.go +++ b/pkg/modules/result_test.go @@ -33,7 +33,6 @@ func TestResult(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "string value", @@ -46,7 +45,7 @@ func TestResult(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "int value", @@ -59,7 +58,7 @@ func TestResult(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "float value", @@ -72,7 +71,7 @@ func TestResult(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "map value", @@ -85,7 +84,7 @@ func TestResult(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "array value", @@ -98,7 +97,7 @@ func TestResult(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, } @@ -107,9 +106,8 @@ func TestResult(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - stdout, stderr := ModuleResult(ctx, tc.opt) + stdout, _, _ := ModuleResult(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, stdout) - assert.Equal(t, tc.exceptStderr, stderr) }) } } diff --git a/pkg/modules/set_fact.go b/pkg/modules/set_fact.go index 39dfbb98..1b875982 100644 --- a/pkg/modules/set_fact.go +++ b/pkg/modules/set_fact.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" "gopkg.in/yaml.v3" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -61,17 +60,17 @@ Return Values: */ // ModuleSetFact handles the "set_fact" module, setting variables during playbook execution -func ModuleSetFact(_ context.Context, options ExecOptions) (string, string) { +func ModuleSetFact(_ context.Context, options ExecOptions) (string, string, error) { var node yaml.Node // Unmarshal the YAML document into a root node. if err := yaml.Unmarshal(options.Args.Raw, &node); err != nil { - return "", fmt.Sprintf("failed to unmarshal YAML error: %v", err) + return StdoutFailed, "failed to unmarshal YAML", err } if err := options.Variable.Merge(variable.MergeRuntimeVariable(node, options.Host)); err != nil { - return "", fmt.Sprintf("set_fact error: %v", err) + return StdoutFailed, "failed to merge set_fact variable", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func init() { diff --git a/pkg/modules/set_fact_test.go b/pkg/modules/set_fact_test.go index 462be82c..2f6e0652 100644 --- a/pkg/modules/set_fact_test.go +++ b/pkg/modules/set_fact_test.go @@ -33,7 +33,6 @@ func TestSetFact(t *testing.T) { name string opt ExecOptions exceptStdout string - exceptStderr string }{ { name: "string value", @@ -46,7 +45,7 @@ func TestSetFact(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "int value", @@ -59,7 +58,7 @@ func TestSetFact(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "float value", @@ -72,7 +71,7 @@ func TestSetFact(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "map value", @@ -85,7 +84,7 @@ func TestSetFact(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, { name: "array value", @@ -98,7 +97,7 @@ func TestSetFact(t *testing.T) { Task: kkcorev1alpha1.Task{}, Playbook: kkcorev1.Playbook{}, }, - exceptStdout: "success", + exceptStdout: StdoutSuccess, }, } @@ -107,9 +106,8 @@ func TestSetFact(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - stdout, stderr := ModuleSetFact(ctx, tc.opt) + stdout, _, _ := ModuleSetFact(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, stdout) - assert.Equal(t, tc.exceptStderr, stderr) }) } } diff --git a/pkg/modules/setup.go b/pkg/modules/setup.go index 6660a59c..8091c8b9 100644 --- a/pkg/modules/setup.go +++ b/pkg/modules/setup.go @@ -2,7 +2,6 @@ package modules import ( "context" - "fmt" utilruntime "k8s.io/apimachinery/pkg/util/runtime" @@ -28,25 +27,25 @@ Usage: // ModuleSetup establishes a connection to a remote host and gathers facts about it. // It returns StdoutSuccess if successful, or an error message if any step fails. -func ModuleSetup(ctx context.Context, options ExecOptions) (string, string) { +func ModuleSetup(ctx context.Context, options ExecOptions) (string, string, error) { // get connector conn, err := options.getConnector(ctx) if err != nil { - return StdoutFailed, fmt.Sprintf("failed to connector of %q error: %v", options.Host, err) + return StdoutFailed, StderrGetConnector, nil } defer conn.Close(ctx) if gf, ok := conn.(connector.GatherFacts); ok { remoteInfo, err := gf.HostInfo(ctx) if err != nil { - return StdoutFailed, err.Error() + return StdoutFailed, "failed to get host info", err } if err := options.Variable.Merge(variable.MergeRemoteVariable(remoteInfo, options.Host)); err != nil { - return StdoutFailed, err.Error() + return StdoutFailed, "failed to merge setup variable", err } } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func init() { diff --git a/pkg/modules/setup_test.go b/pkg/modules/setup_test.go index eb9459db..42c9f3ad 100644 --- a/pkg/modules/setup_test.go +++ b/pkg/modules/setup_test.go @@ -14,7 +14,6 @@ func TestModuleSetup(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "successful setup with fact gathering", @@ -23,10 +22,9 @@ func TestModuleSetup(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: func() context.Context { - return context.WithValue(context.Background(), ConnKey, successConnector) + return context.WithValue(context.Background(), ConnKey, newTestConnector(StdoutSuccess, "", nil)) }, exceptStdout: StdoutSuccess, - exceptStderr: "", }, { name: "failed connector setup", @@ -35,8 +33,7 @@ func TestModuleSetup(t *testing.T) { Variable: newTestVariable(nil, nil), }, ctxFunc: context.Background, - exceptStdout: "", - exceptStderr: "failed to connector of \"invalid-host\" error:", + exceptStdout: StdoutFailed, }, } @@ -45,13 +42,8 @@ func TestModuleSetup(t *testing.T) { ctx, cancel := context.WithTimeout(tc.ctxFunc(), time.Second*5) defer cancel() - stdout, stderr := ModuleSetup(ctx, tc.opt) - assert.Contains(t, stdout, tc.exceptStdout) - if tc.exceptStderr != "" { - assert.Contains(t, stderr, tc.exceptStderr) - } else { - assert.Empty(t, stderr) - } + stdout, _, _ := ModuleSetup(ctx, tc.opt) + assert.Equal(t, tc.exceptStdout, stdout) }) } } diff --git a/pkg/modules/template.go b/pkg/modules/template.go index 97d2e6e8..0c472e3e 100644 --- a/pkg/modules/template.go +++ b/pkg/modules/template.go @@ -18,7 +18,6 @@ package modules import ( "context" - "fmt" "io/fs" "math" "os" @@ -112,10 +111,20 @@ func newTemplateArgs(_ context.Context, raw runtime.RawExtension, vars map[strin } // ModuleTemplate handles the "template" module, processing files with Go templates -func ModuleTemplate(ctx context.Context, options ExecOptions) (string, string) { - ha, ta, conn, err := prepareTemplate(ctx, options) +func ModuleTemplate(ctx context.Context, options ExecOptions) (string, string, error) { + ha, err := options.getAllVariables() if err != nil { - return "", err.Error() + return StdoutFailed, StderrGetHostVariable, err + } + + ta, err := newTemplateArgs(ctx, options.Args, ha) + if err != nil { + return StdoutFailed, StderrParseArgument, err + } + + conn, err := options.getConnector(ctx) + if err != nil { + return StdoutFailed, StderrGetConnector, err } defer conn.Close(ctx) @@ -126,79 +135,60 @@ func ModuleTemplate(ctx context.Context, options ExecOptions) (string, string) { return handleRelativeTemplate(ctx, ta, conn, ha, options) } -func prepareTemplate(ctx context.Context, options ExecOptions) (map[string]any, *templateArgs, connector.Connector, error) { - ha, err := options.getAllVariables() - if err != nil { - return nil, nil, nil, err - } - - ta, err := newTemplateArgs(ctx, options.Args, ha) - if err != nil { - return nil, nil, nil, err - } - - conn, err := options.getConnector(ctx) - if err != nil { - return nil, nil, nil, err - } - - return ha, ta, conn, nil -} - -func handleAbsoluteTemplate(ctx context.Context, ta *templateArgs, conn connector.Connector, vars map[string]any) (string, string) { +func handleAbsoluteTemplate(ctx context.Context, ta *templateArgs, conn connector.Connector, vars map[string]any) (string, string, error) { fileInfo, err := os.Stat(ta.src) if err != nil { - return "", fmt.Sprintf(" get src file %s in local path error: %v", ta.src, err) + return StdoutFailed, "failed to get src file in local path", err } if fileInfo.IsDir() { if err := ta.absDir(ctx, conn, vars); err != nil { - return "", fmt.Sprintf("sync template absolute dir error %s", err) + return StdoutFailed, "failed to template absolute dir", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } data, err := os.ReadFile(ta.src) if err != nil { - return "", fmt.Sprintf("read file error: %s", err) + return StdoutFailed, "failed to read file", err } if err := ta.readFile(ctx, string(data), fileInfo.Mode(), conn, vars); err != nil { - return "", fmt.Sprintf("sync template absolute file error %s", err) + return StdoutFailed, "failed to template file", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } -func handleRelativeTemplate(ctx context.Context, ta *templateArgs, conn connector.Connector, vars map[string]any, options ExecOptions) (string, string) { +func handleRelativeTemplate(ctx context.Context, ta *templateArgs, conn connector.Connector, vars map[string]any, options ExecOptions) (string, string, error) { pj, err := project.New(ctx, options.Playbook, false) if err != nil { - return "", fmt.Sprintf("get project error: %v", err) + return StdoutFailed, "failed to get playbook", nil } relPath := filepath.Join(options.Task.Annotations[kkcorev1alpha1.TaskAnnotationRelativePath], _const.ProjectRolesTemplateDir, ta.src) fileInfo, err := pj.Stat(relPath) if err != nil { - return "", fmt.Sprintf("get file %s from project error: %v", ta.src, err) + return StdoutFailed, "failed to stat relative path", err } if fileInfo.IsDir() { if err := handleRelativeDir(ctx, pj, relPath, ta, conn, vars); err != nil { - return "", fmt.Sprintf("sync template relative dir error: %s", err) + return StdoutFailed, "failed to template relative dir", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } data, err := pj.ReadFile(relPath) if err != nil { - return "", fmt.Sprintf("read file error: %s", err) + return StdoutFailed, "failed to read relative file", err } if err := ta.readFile(ctx, string(data), fileInfo.Mode(), conn, vars); err != nil { - return "", fmt.Sprintf("sync template relative dir error: %s", err) + return StdoutFailed, "failed to template relative file", err } - return StdoutSuccess, "" + return StdoutSuccess, "", nil } func handleRelativeDir(ctx context.Context, pj project.Project, relPath string, ta *templateArgs, conn connector.Connector, vars map[string]any) error { diff --git a/pkg/modules/template_test.go b/pkg/modules/template_test.go index d1ed960f..d4713980 100644 --- a/pkg/modules/template_test.go +++ b/pkg/modules/template_test.go @@ -41,7 +41,6 @@ func TestTemplate(t *testing.T) { opt ExecOptions ctxFunc func() context.Context exceptStdout string - exceptStderr string }{ { name: "src is empty", @@ -51,7 +50,7 @@ func TestTemplate(t *testing.T) { Variable: newTestVariable([]string{"node1"}, nil), }, ctxFunc: context.Background, - exceptStderr: "\"src\" should be string", + exceptStdout: StdoutFailed, }, { name: "dest is empty", @@ -67,7 +66,7 @@ func TestTemplate(t *testing.T) { }), }, ctxFunc: context.Background, - exceptStderr: "\"dest\" should be string", + exceptStdout: StdoutFailed, }, } @@ -76,9 +75,8 @@ func TestTemplate(t *testing.T) { ctx, cancel := context.WithTimeout(tc.ctxFunc(), time.Second*5) defer cancel() - acStdout, acStderr := ModuleTemplate(ctx, tc.opt) + acStdout, _, _ := ModuleTemplate(ctx, tc.opt) assert.Equal(t, tc.exceptStdout, acStdout) - assert.Equal(t, tc.exceptStderr, acStderr) }) } }