Loading playbooks/ansible.cfg +2 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,8 @@ inventory = inventories/dev/hosts.ini roles_path = roles host_key_checking = False stdout_callback = yaml stdout_callback = default result_format = yaml bin_ansible_callbacks = True interpreter_python = auto Loading playbooks/inventories/dev/group_vars/all.yml +12 −9 Original line number Diff line number Diff line Loading @@ -18,12 +18,10 @@ apt_base_packages: disable_swap: true # Container runtime containerd_version: "1.7.27-1" docker_package_state: present containerd_config_path: /etc/containerd/config.toml # Docker docker_version: "5:20.10.22~3-0~ubuntu-{{ ansible_distribution_release }}" # Docker (latest from official repo, no version pin) docker_gpg_key_url: "https://download.docker.com/linux/ubuntu/gpg" docker_gpg_key_path: "/usr/share/keyrings/docker-archive-keyring.gpg" docker_repo_list_path: "/etc/apt/sources.list.d/docker.list" Loading @@ -35,16 +33,17 @@ docker_repo_codename: "{{ ansible_lsb.codename | default('jammy') }}" # Kubernetes kubernetes_version: "v1.33.1" kubernetes_repo_apt_key_url: "https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key" kubernetes_repo_apt_entry: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /" kubernetes_version: "v1.35.1" kubernetes_repo_apt_key_url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key" kubernetes_repo_apt_entry: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /" kubeadm_cluster_name: "mec-sandbox" pod_network_cidr: "192.168.0.0/16" pod_network_cidr: "92.68.0.0/16" service_cidr: "10.96.0.0/12" apiserver_advertise_address: "127.0.0.1" # CNI (Calico) calico_version: "v3.30.0" calico_version: "v3.31.4" calico_operator_crds_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/operator-crds.yaml" calico_operator_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/tigera-operator.yaml" calico_custom_resources_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/custom-resources.yaml" Loading @@ -55,13 +54,17 @@ helm_version: "v3.14.4" install_dev_env: true go_version: "1.17" go_tar: "go{{ go_version }}.linux-amd64.tar.gz" go_url: "https://dl.google.com/go/go{{ go_version }}.linux-amd64.tar.gz" go_url: "https://go.dev/dl/go{{ go_version }}.linux-amd64.tar.gz" node_major: 20 node_version: "12.19.0" npm_version: "6.14.8" eslint_version: "5.16.0" python_packages: [pyyaml] # MEC Sandbox paths (derived from target_home) mec_sandbox_dir: "{{ target_home }}/etsi-mec-sandbox" mec_frontend_dir: "{{ target_home }}/etsi-mec-sandbox-frontend" # Optional local registry & CA trust docker_registry_host: "meep-docker-registry" # e.g., "registry.local:5000" docker_insecure_registries: [] # e.g., ["registry.local:5000"] Loading playbooks/roles/cni_calico/tasks/main.yml +126 −10 Original line number Diff line number Diff line Loading @@ -6,23 +6,139 @@ failed_when: false changed_when: false - name: Install Calico operator # Step 1: Install Calico operator CRDs - name: Install Calico operator CRDs when: calico_ns.rc != 0 command: > kubectl apply -f {{ calico_operator_manifest }} kubectl create -f {{ calico_operator_crds_manifest }} --kubeconfig /etc/kubernetes/admin.conf register: calico_crds_result changed_when: "'created' in calico_crds_result.stdout" failed_when: calico_crds_result.rc != 0 and 'AlreadyExists' not in calico_crds_result.stderr # Step 2: Install Tigera operator - name: Install Tigera operator when: calico_ns.rc != 0 command: > kubectl create -f {{ calico_operator_manifest }} --kubeconfig /etc/kubernetes/admin.conf register: calico_operator_result changed_when: "'created' in calico_operator_result.stdout" failed_when: calico_operator_result.rc != 0 and 'AlreadyExists' not in calico_operator_result.stderr - name: Wait before applying Calico custom resources (allow operator to initialize) pause: seconds: 30 when: calico_ns.rc != 0 # Step 3: Download custom-resources.yaml - name: Download Calico custom resources manifest get_url: url: "{{ calico_custom_resources_manifest }}" dest: /tmp/calico-custom-resources.yaml mode: '0644' force: true - name: Install Calico custom resources when: calico_ns.rc != 0 # Step 4: Patch CIDR in custom-resources.yaml to match pod_network_cidr - name: Patch Calico custom resources CIDR to {{ pod_network_cidr }} replace: path: /tmp/calico-custom-resources.yaml regexp: 'cidr:\s*192\.168\.0\.0/16' replace: 'cidr: {{ pod_network_cidr }}' # Step 5: Wait for operator CRDs to be ready, then apply - name: Wait for Tigera operator CRDs to be registered command: > kubectl apply -f {{ calico_custom_resources_manifest }} kubectl get crd installations.operator.tigera.io --kubeconfig /etc/kubernetes/admin.conf register: tigera_crd_check until: tigera_crd_check.rc == 0 retries: 30 delay: 10 changed_when: false - name: Apply Calico custom resources command: > kubectl apply -f /tmp/calico-custom-resources.yaml --kubeconfig /etc/kubernetes/admin.conf register: calico_cr_result changed_when: "'created' in calico_cr_result.stdout" changed_when: "'created' in calico_cr_result.stdout or 'configured' in calico_cr_result.stdout" retries: 5 delay: 15 until: calico_cr_result.rc == 0 - name: Display CNI installation notice debug: msg: | CNI (Calico) is being installed — this involves downloading container images and may take several minutes. You can check the status in another terminal by running: kubectl get po -A Wait until every pod (especially coredns, calico-node, tigera-operator) shows Running/Ready. - name: Wait for control-plane node to be Ready command: > kubectl get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}' --kubeconfig /etc/kubernetes/admin.conf register: node_ready until: node_ready.stdout == "True" retries: 60 delay: 30 changed_when: false - name: Wait for all kube-system pods to be Ready shell: | set -o pipefail not_ready=$(kubectl get pods -A --kubeconfig /etc/kubernetes/admin.conf --no-headers | grep -v -E 'Running|Completed' | grep -v -c '^$' || true) echo "$not_ready" args: executable: /bin/bash register: pods_not_ready until: (pods_not_ready.stdout | trim | int) == 0 retries: 60 delay: 30 changed_when: false - name: Show cluster status shell: "kubectl get po -A --kubeconfig /etc/kubernetes/admin.conf" register: cluster_status changed_when: false - name: Display cluster pod status debug: msg: "{{ cluster_status.stdout }}" - name: Control plane is Ready debug: msg: "All pods are in Running/Ready state. Control plane is fully operational. Proceeding with MEC Sandbox setup." # --- Post-CNI setup --- - name: Add kubectl bash completion to .bashrc lineinfile: path: "{{ target_home }}/.bashrc" line: 'source <(kubectl completion bash)' state: present become: true become_user: "{{ target_user }}" - name: Add docker registry entry to /etc/hosts lineinfile: path: /etc/hosts line: "{{ mec_host_address }} meep-docker-registry" state: present - name: Copy Kubernetes CA cert to system trust store copy: src: /etc/kubernetes/pki/ca.crt dest: /usr/local/share/ca-certificates/kubernetes-ca.crt remote_src: true mode: "0644" - name: Update system CA certificates command: update-ca-certificates changed_when: true - name: Restart docker daemon systemd: name: docker state: restarted - name: Restart containerd daemon systemd: name: containerd state: restarted playbooks/roles/containerd/tasks/main.yml +23 −14 Original line number Diff line number Diff line Loading @@ -6,40 +6,49 @@ - name: Ensure containerd is installed apt: name: "containerd.io={{ containerd_version }}" name: containerd.io state: present update_cache: true become: true retries: 3 # try up to 3 times delay: 10 # wait 10 between retries retries: 3 delay: 10 - name: Generate default containerd config - name: Check if containerd config already exists stat: path: "{{ containerd_config_path }}" register: containerd_config_stat - name: Check if containerd config has CRI disabled (Docker default) shell: grep -q 'disabled_plugins.*cri' {{ containerd_config_path }} args: executable: /bin/bash register: cri_disabled_check failed_when: false changed_when: false - name: Generate default containerd config (new install or CRI disabled) shell: containerd config default > {{ containerd_config_path }} args: executable: /bin/bash become: true changed_when: true when: not containerd_config_stat.stat.exists or cri_disabled_check.rc == 0 notify: Restart containerd - name: Ensure SystemdCgroup is true replace: path: "{{ containerd_config_path }}" regexp: 'SystemdCgroup = false' regexp: 'SystemdCgroup\s*=\s*false' replace: 'SystemdCgroup = true' become: true notify: Restart containerd - name: Replace containerd sandbox image - name: Update containerd sandbox image to latest pause version replace: path: "{{ containerd_config_path }}" regexp: 'sandbox_image = "registry.k8s.io/pause:3.8' replace: 'sandbox_image = "registry.k8s.io/pause:3.10' regexp: 'sandbox_image = "registry.k8s.io/pause:3\.\d+"' replace: 'sandbox_image = "registry.k8s.io/pause:3.10"' become: true - name: Trigger containerd restart debug: msg: "Triggering handler restart" notify: Restart containerd changed_when: true - name: Debug - Containerd setup completed debug: Loading playbooks/roles/dev_env/golang/tasks/install.yml +44 −11 Original line number Diff line number Diff line --- # Step 1: Download Go tarball if not already installed at correct version - name: Check if Go binary exists stat: path: /usr/local/go/bin/go register: go_binary - name: Check Go version command: /usr/local/go/bin/go version register: go_version_output ignore_errors: true changed_when: false when: go_binary.stat.exists - name: Download Go tarball get_url: url: "https://go.dev/dl/go{{ go_version }}.linux-amd64.tar.gz" dest: "/tmp/go{{ go_version }}.linux-amd64.tar.gz" mode: "0644" when: not go_binary.stat.exists or go_version_output.stdout is not search("go{{ go_version }}") # Step 2: Extract to /usr/local - name: Extract Go tarball to /usr/local shell: "tar -C /usr/local -xzf /tmp/go{{ go_version }}.linux-amd64.tar.gz" args: executable: /bin/bash when: not go_binary.stat.exists or go_version_output.stdout is not search("go{{ go_version }}") - name: Install Go toolchain unarchive: src: "{{ go_url }}" dest: /usr/local remote_src: true when: go_version_output.stdout is not search("go{{ go_version }}") # Step 3: Create ~/gocode/bin directory - name: Create GOPATH bin directory file: path: "{{ target_home }}/gocode/bin" state: directory owner: "{{ target_user }}" mode: "0755" - name: Setup Go environment # Step 4: Add Go environment to .bashrc (idempotent via blockinfile) - name: Setup Go environment in .bashrc blockinfile: path: "{{ target_home }}/.bashrc" marker: "# {mark} ANSIBLE MANAGED - Go environment setup" block: | export GOPATH={{ target_home }}/gocode # Go environment setup export GOPATH=$HOME/gocode export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin become: true become_user: "{{ target_user }}" # Step 5: Install GolangCI-Lint - name: Install GolangCI-Lint shell: | /usr/local/go/bin/go env -w GOPATH={{ target_home }}/gocode Loading @@ -29,9 +56,15 @@ creates: "{{ target_home }}/gocode/bin/golangci-lint" environment: PATH: "/usr/local/go/bin:{{ target_home }}/gocode/bin:{{ ansible_env.PATH }}" GOPATH: "{{ target_home }}/gocode" become: true become_user: "{{ target_user }}" - name: Debug - name: Verify Go installation command: /usr/local/go/bin/go version register: go_final_version changed_when: false - name: Show Go version debug: msg: "✅ Go environment ready: Go {{ go_version }}, golangci-lint installed and configured" msg: "Go environment ready: {{ go_final_version.stdout }}, GOPATH={{ target_home }}/gocode" Loading
playbooks/ansible.cfg +2 −1 Original line number Diff line number Diff line Loading @@ -2,7 +2,8 @@ inventory = inventories/dev/hosts.ini roles_path = roles host_key_checking = False stdout_callback = yaml stdout_callback = default result_format = yaml bin_ansible_callbacks = True interpreter_python = auto Loading
playbooks/inventories/dev/group_vars/all.yml +12 −9 Original line number Diff line number Diff line Loading @@ -18,12 +18,10 @@ apt_base_packages: disable_swap: true # Container runtime containerd_version: "1.7.27-1" docker_package_state: present containerd_config_path: /etc/containerd/config.toml # Docker docker_version: "5:20.10.22~3-0~ubuntu-{{ ansible_distribution_release }}" # Docker (latest from official repo, no version pin) docker_gpg_key_url: "https://download.docker.com/linux/ubuntu/gpg" docker_gpg_key_path: "/usr/share/keyrings/docker-archive-keyring.gpg" docker_repo_list_path: "/etc/apt/sources.list.d/docker.list" Loading @@ -35,16 +33,17 @@ docker_repo_codename: "{{ ansible_lsb.codename | default('jammy') }}" # Kubernetes kubernetes_version: "v1.33.1" kubernetes_repo_apt_key_url: "https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key" kubernetes_repo_apt_entry: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /" kubernetes_version: "v1.35.1" kubernetes_repo_apt_key_url: "https://pkgs.k8s.io/core:/stable:/v1.35/deb/Release.key" kubernetes_repo_apt_entry: "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.35/deb/ /" kubeadm_cluster_name: "mec-sandbox" pod_network_cidr: "192.168.0.0/16" pod_network_cidr: "92.68.0.0/16" service_cidr: "10.96.0.0/12" apiserver_advertise_address: "127.0.0.1" # CNI (Calico) calico_version: "v3.30.0" calico_version: "v3.31.4" calico_operator_crds_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/operator-crds.yaml" calico_operator_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/tigera-operator.yaml" calico_custom_resources_manifest: "https://raw.githubusercontent.com/projectcalico/calico/{{ calico_version }}/manifests/custom-resources.yaml" Loading @@ -55,13 +54,17 @@ helm_version: "v3.14.4" install_dev_env: true go_version: "1.17" go_tar: "go{{ go_version }}.linux-amd64.tar.gz" go_url: "https://dl.google.com/go/go{{ go_version }}.linux-amd64.tar.gz" go_url: "https://go.dev/dl/go{{ go_version }}.linux-amd64.tar.gz" node_major: 20 node_version: "12.19.0" npm_version: "6.14.8" eslint_version: "5.16.0" python_packages: [pyyaml] # MEC Sandbox paths (derived from target_home) mec_sandbox_dir: "{{ target_home }}/etsi-mec-sandbox" mec_frontend_dir: "{{ target_home }}/etsi-mec-sandbox-frontend" # Optional local registry & CA trust docker_registry_host: "meep-docker-registry" # e.g., "registry.local:5000" docker_insecure_registries: [] # e.g., ["registry.local:5000"] Loading
playbooks/roles/cni_calico/tasks/main.yml +126 −10 Original line number Diff line number Diff line Loading @@ -6,23 +6,139 @@ failed_when: false changed_when: false - name: Install Calico operator # Step 1: Install Calico operator CRDs - name: Install Calico operator CRDs when: calico_ns.rc != 0 command: > kubectl apply -f {{ calico_operator_manifest }} kubectl create -f {{ calico_operator_crds_manifest }} --kubeconfig /etc/kubernetes/admin.conf register: calico_crds_result changed_when: "'created' in calico_crds_result.stdout" failed_when: calico_crds_result.rc != 0 and 'AlreadyExists' not in calico_crds_result.stderr # Step 2: Install Tigera operator - name: Install Tigera operator when: calico_ns.rc != 0 command: > kubectl create -f {{ calico_operator_manifest }} --kubeconfig /etc/kubernetes/admin.conf register: calico_operator_result changed_when: "'created' in calico_operator_result.stdout" failed_when: calico_operator_result.rc != 0 and 'AlreadyExists' not in calico_operator_result.stderr - name: Wait before applying Calico custom resources (allow operator to initialize) pause: seconds: 30 when: calico_ns.rc != 0 # Step 3: Download custom-resources.yaml - name: Download Calico custom resources manifest get_url: url: "{{ calico_custom_resources_manifest }}" dest: /tmp/calico-custom-resources.yaml mode: '0644' force: true - name: Install Calico custom resources when: calico_ns.rc != 0 # Step 4: Patch CIDR in custom-resources.yaml to match pod_network_cidr - name: Patch Calico custom resources CIDR to {{ pod_network_cidr }} replace: path: /tmp/calico-custom-resources.yaml regexp: 'cidr:\s*192\.168\.0\.0/16' replace: 'cidr: {{ pod_network_cidr }}' # Step 5: Wait for operator CRDs to be ready, then apply - name: Wait for Tigera operator CRDs to be registered command: > kubectl apply -f {{ calico_custom_resources_manifest }} kubectl get crd installations.operator.tigera.io --kubeconfig /etc/kubernetes/admin.conf register: tigera_crd_check until: tigera_crd_check.rc == 0 retries: 30 delay: 10 changed_when: false - name: Apply Calico custom resources command: > kubectl apply -f /tmp/calico-custom-resources.yaml --kubeconfig /etc/kubernetes/admin.conf register: calico_cr_result changed_when: "'created' in calico_cr_result.stdout" changed_when: "'created' in calico_cr_result.stdout or 'configured' in calico_cr_result.stdout" retries: 5 delay: 15 until: calico_cr_result.rc == 0 - name: Display CNI installation notice debug: msg: | CNI (Calico) is being installed — this involves downloading container images and may take several minutes. You can check the status in another terminal by running: kubectl get po -A Wait until every pod (especially coredns, calico-node, tigera-operator) shows Running/Ready. - name: Wait for control-plane node to be Ready command: > kubectl get nodes -o jsonpath='{.items[0].status.conditions[?(@.type=="Ready")].status}' --kubeconfig /etc/kubernetes/admin.conf register: node_ready until: node_ready.stdout == "True" retries: 60 delay: 30 changed_when: false - name: Wait for all kube-system pods to be Ready shell: | set -o pipefail not_ready=$(kubectl get pods -A --kubeconfig /etc/kubernetes/admin.conf --no-headers | grep -v -E 'Running|Completed' | grep -v -c '^$' || true) echo "$not_ready" args: executable: /bin/bash register: pods_not_ready until: (pods_not_ready.stdout | trim | int) == 0 retries: 60 delay: 30 changed_when: false - name: Show cluster status shell: "kubectl get po -A --kubeconfig /etc/kubernetes/admin.conf" register: cluster_status changed_when: false - name: Display cluster pod status debug: msg: "{{ cluster_status.stdout }}" - name: Control plane is Ready debug: msg: "All pods are in Running/Ready state. Control plane is fully operational. Proceeding with MEC Sandbox setup." # --- Post-CNI setup --- - name: Add kubectl bash completion to .bashrc lineinfile: path: "{{ target_home }}/.bashrc" line: 'source <(kubectl completion bash)' state: present become: true become_user: "{{ target_user }}" - name: Add docker registry entry to /etc/hosts lineinfile: path: /etc/hosts line: "{{ mec_host_address }} meep-docker-registry" state: present - name: Copy Kubernetes CA cert to system trust store copy: src: /etc/kubernetes/pki/ca.crt dest: /usr/local/share/ca-certificates/kubernetes-ca.crt remote_src: true mode: "0644" - name: Update system CA certificates command: update-ca-certificates changed_when: true - name: Restart docker daemon systemd: name: docker state: restarted - name: Restart containerd daemon systemd: name: containerd state: restarted
playbooks/roles/containerd/tasks/main.yml +23 −14 Original line number Diff line number Diff line Loading @@ -6,40 +6,49 @@ - name: Ensure containerd is installed apt: name: "containerd.io={{ containerd_version }}" name: containerd.io state: present update_cache: true become: true retries: 3 # try up to 3 times delay: 10 # wait 10 between retries retries: 3 delay: 10 - name: Generate default containerd config - name: Check if containerd config already exists stat: path: "{{ containerd_config_path }}" register: containerd_config_stat - name: Check if containerd config has CRI disabled (Docker default) shell: grep -q 'disabled_plugins.*cri' {{ containerd_config_path }} args: executable: /bin/bash register: cri_disabled_check failed_when: false changed_when: false - name: Generate default containerd config (new install or CRI disabled) shell: containerd config default > {{ containerd_config_path }} args: executable: /bin/bash become: true changed_when: true when: not containerd_config_stat.stat.exists or cri_disabled_check.rc == 0 notify: Restart containerd - name: Ensure SystemdCgroup is true replace: path: "{{ containerd_config_path }}" regexp: 'SystemdCgroup = false' regexp: 'SystemdCgroup\s*=\s*false' replace: 'SystemdCgroup = true' become: true notify: Restart containerd - name: Replace containerd sandbox image - name: Update containerd sandbox image to latest pause version replace: path: "{{ containerd_config_path }}" regexp: 'sandbox_image = "registry.k8s.io/pause:3.8' replace: 'sandbox_image = "registry.k8s.io/pause:3.10' regexp: 'sandbox_image = "registry.k8s.io/pause:3\.\d+"' replace: 'sandbox_image = "registry.k8s.io/pause:3.10"' become: true - name: Trigger containerd restart debug: msg: "Triggering handler restart" notify: Restart containerd changed_when: true - name: Debug - Containerd setup completed debug: Loading
playbooks/roles/dev_env/golang/tasks/install.yml +44 −11 Original line number Diff line number Diff line --- # Step 1: Download Go tarball if not already installed at correct version - name: Check if Go binary exists stat: path: /usr/local/go/bin/go register: go_binary - name: Check Go version command: /usr/local/go/bin/go version register: go_version_output ignore_errors: true changed_when: false when: go_binary.stat.exists - name: Download Go tarball get_url: url: "https://go.dev/dl/go{{ go_version }}.linux-amd64.tar.gz" dest: "/tmp/go{{ go_version }}.linux-amd64.tar.gz" mode: "0644" when: not go_binary.stat.exists or go_version_output.stdout is not search("go{{ go_version }}") # Step 2: Extract to /usr/local - name: Extract Go tarball to /usr/local shell: "tar -C /usr/local -xzf /tmp/go{{ go_version }}.linux-amd64.tar.gz" args: executable: /bin/bash when: not go_binary.stat.exists or go_version_output.stdout is not search("go{{ go_version }}") - name: Install Go toolchain unarchive: src: "{{ go_url }}" dest: /usr/local remote_src: true when: go_version_output.stdout is not search("go{{ go_version }}") # Step 3: Create ~/gocode/bin directory - name: Create GOPATH bin directory file: path: "{{ target_home }}/gocode/bin" state: directory owner: "{{ target_user }}" mode: "0755" - name: Setup Go environment # Step 4: Add Go environment to .bashrc (idempotent via blockinfile) - name: Setup Go environment in .bashrc blockinfile: path: "{{ target_home }}/.bashrc" marker: "# {mark} ANSIBLE MANAGED - Go environment setup" block: | export GOPATH={{ target_home }}/gocode # Go environment setup export GOPATH=$HOME/gocode export PATH=$PATH:$GOPATH/bin:/usr/local/go/bin become: true become_user: "{{ target_user }}" # Step 5: Install GolangCI-Lint - name: Install GolangCI-Lint shell: | /usr/local/go/bin/go env -w GOPATH={{ target_home }}/gocode Loading @@ -29,9 +56,15 @@ creates: "{{ target_home }}/gocode/bin/golangci-lint" environment: PATH: "/usr/local/go/bin:{{ target_home }}/gocode/bin:{{ ansible_env.PATH }}" GOPATH: "{{ target_home }}/gocode" become: true become_user: "{{ target_user }}" - name: Debug - name: Verify Go installation command: /usr/local/go/bin/go version register: go_final_version changed_when: false - name: Show Go version debug: msg: "✅ Go environment ready: Go {{ go_version }}, golangci-lint installed and configured" msg: "Go environment ready: {{ go_final_version.stdout }}, GOPATH={{ target_home }}/gocode"