diff --git a/ansible/roles/firstboot/files/ansible_payload/bootstrap/roles/metacluster/tasks/certauthority.yml b/ansible/roles/firstboot/files/ansible_payload/bootstrap/roles/metacluster/tasks/certauthority.yml index 9cdfca9..fe76be6 100644 --- a/ansible/roles/firstboot/files/ansible_payload/bootstrap/roles/metacluster/tasks/certauthority.yml +++ b/ansible/roles/firstboot/files/ansible_payload/bootstrap/roles/metacluster/tasks/certauthority.yml @@ -124,23 +124,16 @@ - name: Trigger handlers ansible.builtin.meta: flush_handlers - - name: Retrieve step-ca configuration - kubernetes.core.k8s_info: - kind: ConfigMap - name: step-certificates-config - namespace: step-ca - kubeconfig: "{{ kubeconfig.path }}" - register: stepca_cm_config - - - name: Install root CA in system truststore - ansible.builtin.shell: - cmd: >- - step ca bootstrap \ - --ca-url=https://ca.{{ vapp['metacluster.fqdn'] }} \ - --fingerprint={{ stepca_cm_config.resources[0].data['defaults.json'] | from_json | json_query('fingerprint') }} \ - --install \ - --force - update-ca-certificates + - name: Ensure step-ca API availability + ansible.builtin.uri: + url: https://ca.{{ vapp['metacluster.fqdn'] }}/health + method: GET + register: api_readycheck + until: + - api_readycheck.json.status is defined + - api_readycheck.json.status == 'ok' + retries: "{{ playbook.retries }}" + delay: "{{ playbook.delays.long }}" module_defaults: ansible.builtin.uri: diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/playbook.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/playbook.yml index 2bbf474..629a28e 100644 --- a/ansible/roles/firstboot/files/ansible_payload/upgrade/playbook.yml +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/playbook.yml @@ -13,7 +13,7 @@ - users - disks - metacluster - # - workloadcluster + - workloadcluster - tty - cleanup handlers: diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/metacluster/tasks/storage.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/metacluster/tasks/storage.yml index 2b3fbc7..14aea36 100644 --- a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/metacluster/tasks/storage.yml +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/metacluster/tasks/storage.yml @@ -40,9 +40,8 @@ release_namespace: longhorn-system create_namespace: yes wait: no - values: "{{ components.longhorn.chart_values }}" - # Workaround; module_defaults are not respected by this module kubeconfig: "{{ kubeconfig.path }}" + values: "{{ components.longhorn.chart_values }}" - name: Ensure longhorn API availability ansible.builtin.uri: @@ -59,5 +58,3 @@ validate_certs: no status_code: [200, 201] body_format: json - group/k8s: - kubeconfig: "{{ kubeconfig.path }}" diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/clusterapi.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/clusterapi.yml new file mode 100644 index 0000000..b194173 --- /dev/null +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/clusterapi.yml @@ -0,0 +1 @@ +# ... diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/hypervisor.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/hypervisor.yml new file mode 100644 index 0000000..a83da4c --- /dev/null +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/hypervisor.yml @@ -0,0 +1,57 @@ +- name: Gather hypervisor details + ansible.builtin.shell: + cmd: govc ls -L {{ item.moref }} | awk -F/ '{print ${{ item.part }}}' + environment: + GOVC_INSECURE: '1' + GOVC_URL: "{{ vapp['hv.fqdn'] }}" + GOVC_USERNAME: "{{ vapp['hv.username'] }}" + GOVC_PASSWORD: "{{ vapp['hv.password'] }}" + register: govc_inventory + loop: + - attribute: cluster + moref: >- + $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + jq -r '.[] | select(.Name == "runtime").Val.Host | .Type + ":" + .Value') + part: (NF-1) + - attribute: datacenter + moref: VirtualMachine:{{ moref_id }} + part: 2 + - attribute: datastore + moref: >- + $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + jq -r '.[] | select(.Name == "datastore").Val.ManagedObjectReference | .[].Type + ":" + .[].Value') + part: NF + - attribute: folder + moref: >- + $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + jq -r '.[] | select(.Name == "parent").Val | .Type + ":" + .Value') + part: 0 + # - attribute: host + # moref: >- + # $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + # jq -r '.[] | select(.Name == "runtime").Val.Host | .Type + ":" + .Value') + # part: NF + - attribute: network + moref: >- + $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + jq -r '.[] | select(.Name == "network").Val.ManagedObjectReference | .[].Type + ":" + .[].Value') + part: NF + - attribute: resourcepool + moref: >- + $(govc object.collect -json VirtualMachine:{{ moref_id }} | \ + jq -r '.[] | select(.Name == "resourcePool").Val | .Type + ":" + .Value') + part: 0 + loop_control: + label: "{{ item.attribute }}" + +- name: Retrieve hypervisor TLS thumbprint + ansible.builtin.shell: + cmd: openssl s_client -connect {{ vapp['hv.fqdn'] }}:443 < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin | awk -F'=' '{print $2}' + register: tls_thumbprint + +- name: Store hypervisor details in dictionary + ansible.builtin.set_fact: + vcenter_info: "{{ vcenter_info | default({}) | combine({ item.item.attribute : item.stdout }) }}" + loop: "{{ govc_inventory.results }}" + loop_control: + label: "{{ item.item.attribute }}" diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/main.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/main.yml new file mode 100644 index 0000000..08b94ca --- /dev/null +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/main.yml @@ -0,0 +1,4 @@ +- import_tasks: hypervisor.yml +- import_tasks: registry.yml +- import_tasks: nodetemplates.yml +# - import_tasks: clusterapi.yml diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/nodetemplates.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/nodetemplates.yml new file mode 100644 index 0000000..2060474 --- /dev/null +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/nodetemplates.yml @@ -0,0 +1,85 @@ +- block: + + - name: Check for existing templates on hypervisor + community.vmware.vmware_guest_info: + name: "{{ (item | basename | split('.'))[:-1] | join('.') }}" + register: existing_ova + loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}" + ignore_errors: yes + + - name: Parse OVA files for network mappings + ansible.builtin.shell: + cmd: govc import.spec -json {{ item }} + environment: + GOVC_INSECURE: '1' + GOVC_URL: "{{ vapp['hv.fqdn'] }}" + GOVC_USERNAME: "{{ vapp['hv.username'] }}" + GOVC_PASSWORD: "{{ vapp['hv.password'] }}" + register: ova_spec + when: existing_ova.results[index] is failed + loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}" + loop_control: + index_var: index + + - name: Deploy OVA templates on hypervisor + community.vmware.vmware_deploy_ovf: + cluster: "{{ vcenter_info.cluster }}" + datastore: "{{ vcenter_info.datastore }}" + folder: "{{ vcenter_info.folder }}" + name: "{{ (item | basename | split('.'))[:-1] | join('.') }}" + networks: "{u'{{ ova_spec.results[index].stdout | from_json | json_query('NetworkMapping[0].Name') }}':u'{{ vcenter_info.network }}'}" + allow_duplicates: no + power_on: false + ovf: "{{ item }}" + register: ova_deploy + when: existing_ova.results[index] is failed + loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}" + loop_control: + index_var: index + + - name: Add vApp properties on deployed VM's + ansible.builtin.shell: + cmd: >- + npp-prepper \ + --server "{{ vapp['hv.fqdn'] }}" \ + --username "{{ vapp['hv.username'] }}" \ + --password "{{ vapp['hv.password'] }}" \ + vm \ + --datacenter "{{ vcenter_info.datacenter }}" \ + --portgroup "{{ vcenter_info.network }}" \ + --name "{{ item.instance.hw_name }}" + when: existing_ova.results[index] is failed + loop: "{{ ova_deploy.results }}" + loop_control: + index_var: index + label: "{{ item.item }}" + + - name: Create snapshot on deployed VM's + community.vmware.vmware_guest_snapshot: + folder: "{{ vcenter_info.folder }}" + name: "{{ item.instance.hw_name }}" + state: present + snapshot_name: "{{ ansible_date_time.iso8601_basic_short }}-base" + when: ova_deploy.results[index] is not skipped + loop: "{{ ova_deploy.results }}" + loop_control: + index_var: index + label: "{{ item.item }}" + + - name: Mark deployed VM's as templates + community.vmware.vmware_guest: + name: "{{ item.instance.hw_name }}" + is_template: yes + when: ova_deploy.results[index] is not skipped + loop: "{{ ova_deploy.results }}" + loop_control: + index_var: index + label: "{{ item.item }}" + + module_defaults: + group/vmware: + hostname: "{{ vapp['hv.fqdn'] }}" + validate_certs: no + username: "{{ vapp['hv.username'] }}" + password: "{{ vapp['hv.password'] }}" + datacenter: "{{ vcenter_info.datacenter }}" diff --git a/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/registry.yml b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/registry.yml new file mode 100644 index 0000000..60b1b2b --- /dev/null +++ b/ansible/roles/firstboot/files/ansible_payload/upgrade/roles/workloadcluster/tasks/registry.yml @@ -0,0 +1,21 @@ +- block: + + - name: Lookup kubeadm container images + ansible.builtin.set_fact: + kubeadm_images: "{{ lookup('ansible.builtin.file', '/opt/metacluster/cluster-api/imagelist').splitlines() }}" + + - name: Copy kubeadm container images to dedicated project + ansible.builtin.uri: + url: https://registry.{{ vapp['metacluster.fqdn'] }}/api/v2.0/projects/kubeadm/repositories/{{ ( item | regex_findall('([^:/]+)') )[-2] }}/artifacts?from=library/{{ item | replace('/', '%2F') | replace(':', '%3A') }} + method: POST + headers: + Authorization: "Basic {{ ('admin:' ~ vapp['metacluster.password']) | b64encode }}" + body: + from: "{{ item }}" + loop: "{{ kubeadm_images }}" + + module_defaults: + ansible.builtin.uri: + validate_certs: no + status_code: [200, 201, 409] + body_format: json diff --git a/ansible/vars/metacluster.yml b/ansible/vars/metacluster.yml index 722e303..b07c119 100644 --- a/ansible/vars/metacluster.yml +++ b/ansible/vars/metacluster.yml @@ -64,7 +64,6 @@ components: argo-cd: helm: - # version: 4.9.7 # (= ArgoCD v2.4.2) version: 5.14.1 # (= ArgoCD v2.5.2) chart: argo/argo-cd parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /' diff --git a/scripts/Update-OvfConfiguration.bootstrap.yml b/scripts/Update-OvfConfiguration.bootstrap.yml index 7f9d1dc..d0b5fd4 100644 --- a/scripts/Update-OvfConfiguration.bootstrap.yml +++ b/scripts/Update-OvfConfiguration.bootstrap.yml @@ -41,8 +41,8 @@ PropertyCategories: - key: metacluster.vip Type: ip - Label: Meta-cluster virtual IP* - Description: Meta-cluster control plane endpoint virtual IP + Label: Meta-cluster virtual IP address* + Description: Meta-cluster control plane endpoint virtual IP address DefaultValue: '' Configurations: '*' UserConfigurable: true @@ -127,15 +127,15 @@ PropertyCategories: - Key: workloadcluster.vip Type: ip - Label: Workload-cluster virtual IP* - Description: Workload-cluster control plane endpoint virtual IP + Label: Workload-cluster virtual IP address* + Description: Workload-cluster control plane endpoint virtual IP address DefaultValue: '' Configurations: '*' UserConfigurable: true - Key: ippool.startip Type: ip - Label: Workload-cluster IP-pool start IP* + Label: Workload-cluster IP-pool start IP address* Description: All nodes for the workload-cluster will be provisioned within this IP pool DefaultValue: '' Configurations: '*' @@ -143,7 +143,7 @@ PropertyCategories: - Key: ippool.endip Type: ip - Label: Workload-cluster IP-pool end IP* + Label: Workload-cluster IP-pool end IP address* Description: All nodes for the workload-cluster will be provisioned within this IP pool DefaultValue: '' Configurations: '*' diff --git a/scripts/Update-OvfConfiguration.upgrade.yml b/scripts/Update-OvfConfiguration.upgrade.yml index 9200c1f..effb263 100644 --- a/scripts/Update-OvfConfiguration.upgrade.yml +++ b/scripts/Update-OvfConfiguration.upgrade.yml @@ -22,8 +22,8 @@ PropertyCategories: - key: metacluster.vip Type: ip - Label: Meta-cluster virtual IP* - Description: Meta-cluster control plane endpoint virtual IP + Label: Meta-cluster virtual IP address* + Description: Meta-cluster control plane endpoint virtual IP address DefaultValue: '' Configurations: '*' UserConfigurable: true @@ -31,7 +31,7 @@ PropertyCategories: - Key: metacluster.password Type: password(7..) Label: Meta-cluster administrator password* - Description: 'Needed to authenticate with target meta-cluster' + Description: Needed to authenticate with target meta-cluster DefaultValue: '' Configurations: '*' UserConfigurable: true