Compare commits
	
		
			2 Commits
		
	
	
		
			88e37bb706
			...
			Windows10
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b4f62b465d | |||
| 060ac37dc0 | 
							
								
								
									
										185
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										185
									
								
								.drone.yml
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| kind: pipeline | kind: pipeline | ||||||
| type: kubernetes | type: kubernetes | ||||||
| name: 'Packer Build' | name: 'Packer Build' | ||||||
|  |      | ||||||
| volumes: | volumes: | ||||||
| - name: output | - name: output | ||||||
|   claim: |   claim: | ||||||
| @@ -10,201 +10,62 @@ volumes: | |||||||
|   claim: |   claim: | ||||||
|     name: flexvolsmb-drone-scratch |     name: flexvolsmb-drone-scratch | ||||||
|  |  | ||||||
| trigger: |  | ||||||
|   event: |  | ||||||
|     exclude: |  | ||||||
|     - tag |  | ||||||
|  |  | ||||||
| steps: | steps: | ||||||
| - name: Debugging information | - name: Debugging information | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |   image: bv11-cr01.bessems.eu/library/packer-extended | ||||||
|   pull: always |  | ||||||
|   commands: |   commands: | ||||||
|   - ansible --version |  | ||||||
|   - ovftool --version |  | ||||||
|   - packer --version |  | ||||||
|   - yamllint --version |   - yamllint --version | ||||||
|  |   - packer --version | ||||||
| - name: Linting |   - pwsh --version | ||||||
|  |   - ovftool --version | ||||||
|  | - name: Windows 10 | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |   image: bv11-cr01.bessems.eu/library/packer-extended | ||||||
|   pull: always |   pull: always | ||||||
|   commands: |   commands: | ||||||
|  |   - sed -i -e "s/<<img-productkey>>/$${PRODUCTKEY}/" packer/preseed/Windows10/Autounattend.xml | ||||||
|   - | |   - | | ||||||
|     yamllint -d "{extends: relaxed, rules: {line-length: disable}}" \ |     sed -i -e "s/<<img-password>>/$${WINRM_PASSWORD}/g" \ | ||||||
|       ansible \ |       packer/preseed/Windows10/Autounattend.xml \ | ||||||
|       packer/preseed/UbuntuServer22.04/user-data \ |       packer/preseed/Windows10/Sysprep_Unattend.xml | ||||||
|       scripts |  | ||||||
|  |  | ||||||
| - name: Semantic Release (Dry-run) |  | ||||||
|   image: bv11-cr01.bessems.eu/proxy/library/node:20-slim |  | ||||||
|   pull: always |  | ||||||
|   commands: |  | ||||||
|   - | |   - | | ||||||
|     apt-get update |     yamllint -d "{extends: relaxed, rules: {line-length: disable}}" scripts | ||||||
|   - | |  | ||||||
|     apt-get install -y --no-install-recommends \ |  | ||||||
|       curl \ |  | ||||||
|       git-core \ |  | ||||||
|       jq \ |  | ||||||
|       ca-certificates |  | ||||||
|   - | |  | ||||||
|     curl -L https://api.github.com/repos/mikefarah/yq/releases/latest | \ |  | ||||||
|       jq -r '.assets[] | select(.name | endswith("yq_linux_amd64")) | .browser_download_url' | \ |  | ||||||
|       xargs -I {} curl -L -o /bin/yq {} && \ |  | ||||||
|     chmod +x /bin/yq |  | ||||||
|   - | |  | ||||||
|     npm install \ |  | ||||||
|       semantic-release \ |  | ||||||
|       @semantic-release/commit-analyzer \ |  | ||||||
|       @semantic-release/exec \ |  | ||||||
|   - | |  | ||||||
|     export K8S_VERSION=$(yq '.components.clusterapi.workload.version.k8s' < ./ansible/vars/metacluster.yml) |  | ||||||
|     export GIT_CREDENTIALS=$${GIT_USERNAME}:$${GIT_APIKEY} |  | ||||||
|   - | |  | ||||||
|     npx semantic-release \ |  | ||||||
|       --package @semantic-release/exec \ |  | ||||||
|       --package semantic-release \ |  | ||||||
|       --branches ${DRONE_BRANCH} \ |  | ||||||
|       --tag-format "K8s_$${K8S_VERSION}-v\$${version}" \ |  | ||||||
|       --dry-run \ |  | ||||||
|       --plugins @semantic-release/commit-analyzer,@semantic-release/exec \ |  | ||||||
|       --analyzeCommits @semantic-release/commit-analyzer \ |  | ||||||
|       --verifyRelease @semantic-release/exec \ |  | ||||||
|       --verifyReleaseCmd 'echo "$${nextRelease.version}" > .version' |  | ||||||
|   environment: |  | ||||||
|     GIT_APIKEY: |  | ||||||
|       from_secret: git_apikey |  | ||||||
|     GIT_USERNAME: djpbessems |  | ||||||
|  |  | ||||||
| - name: Install Ansible Galaxy collections |  | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |  | ||||||
|   pull: always |  | ||||||
|   commands: |  | ||||||
|   - | |  | ||||||
|     ansible-galaxy collection install \ |  | ||||||
|       -r ansible/requirements.yml \ |  | ||||||
|       -p ./ansible/collections |  | ||||||
|  |  | ||||||
| - name: Kubernetes Bootstrap Appliance |  | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |  | ||||||
|   pull: always |  | ||||||
|   commands: |  | ||||||
|   - | |  | ||||||
|     sed -i -e "s/<<img-password>>/$${SSH_PASSWORD}/g" \ |  | ||||||
|       packer/preseed/UbuntuServer22.04/user-data |  | ||||||
|   - | |  | ||||||
|     export K8S_VERSION=$(yq '.components.clusterapi.workload.version.k8s' < ./ansible/vars/metacluster.yml) |  | ||||||
|     export APPLIANCE_VERSION=$(cat .version) |  | ||||||
|   - | |   - | | ||||||
|     packer init -upgrade \ |     packer init -upgrade \ | ||||||
|       ./packer |       ./packer | ||||||
|   - | |   - | | ||||||
|     packer validate \ |     packer validate \ | ||||||
|       -only=vsphere-iso.bootstrap \ |       -var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \ | ||||||
|       -var vm_name=${DRONE_BUILD_NUMBER}-${DRONE_COMMIT_SHA:0:10}-$(openssl rand -hex 3) \ |       -var vm_guestos=win10 \ | ||||||
|       -var docker_username=$${DOCKER_USERNAME} \ |  | ||||||
|       -var docker_password=$${DOCKER_PASSWORD} \ |  | ||||||
|       -var repo_username=$${REPO_USERNAME} \ |       -var repo_username=$${REPO_USERNAME} \ | ||||||
|       -var repo_password=$${REPO_PASSWORD} \ |       -var repo_password=$${REPO_PASSWORD} \ | ||||||
|       -var ssh_password=$${SSH_PASSWORD} \ |  | ||||||
|       -var vsphere_password=$${VSPHERE_PASSWORD} \ |       -var vsphere_password=$${VSPHERE_PASSWORD} \ | ||||||
|       -var k8s_version=$K8S_VERSION \ |       -var winrm_password=$${WINRM_PASSWORD} \ | ||||||
|       -var appliance_version=$APPLIANCE_VERSION \ |  | ||||||
|       ./packer |       ./packer | ||||||
|   - | |   - | | ||||||
|     packer build \ |     packer build \ | ||||||
|       -on-error=cleanup -timestamp-ui \ |       -on-error=cleanup \ | ||||||
|       -only=vsphere-iso.bootstrap \ |       -var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \ | ||||||
|       -var vm_name=${DRONE_BUILD_NUMBER}-${DRONE_COMMIT_SHA:0:10}-$(openssl rand -hex 3) \ |       -var vm_guestos=win10 \ | ||||||
|       -var docker_username=$${DOCKER_USERNAME} \ |  | ||||||
|       -var docker_password=$${DOCKER_PASSWORD} \ |  | ||||||
|       -var repo_username=$${REPO_USERNAME} \ |       -var repo_username=$${REPO_USERNAME} \ | ||||||
|       -var repo_password=$${REPO_PASSWORD} \ |       -var repo_password=$${REPO_PASSWORD} \ | ||||||
|       -var ssh_password=$${SSH_PASSWORD} \ |  | ||||||
|       -var vsphere_password=$${VSPHERE_PASSWORD} \ |       -var vsphere_password=$${VSPHERE_PASSWORD} \ | ||||||
|       -var k8s_version=$K8S_VERSION \ |       -var winrm_password=$${WINRM_PASSWORD} \ | ||||||
|       -var appliance_version=$APPLIANCE_VERSION \ |  | ||||||
|       ./packer |       ./packer | ||||||
|   environment: |   environment: | ||||||
|     DOCKER_USERNAME: |     VSPHERE_PASSWORD: | ||||||
|       from_secret: docker_username |       from_secret: vsphere_password | ||||||
|     DOCKER_PASSWORD: |     WINRM_PASSWORD: | ||||||
|       from_secret: docker_password |       from_secret: winrm_password | ||||||
|     # PACKER_LOG: 1 |  | ||||||
|     REPO_USERNAME: |     REPO_USERNAME: | ||||||
|       from_secret: repo_username |       from_secret: repo_username | ||||||
|     REPO_PASSWORD: |     REPO_PASSWORD: | ||||||
|       from_secret: repo_password |       from_secret: repo_password | ||||||
|     SSH_PASSWORD: |     PRODUCTKEY: | ||||||
|       from_secret: ssh_password |       from_secret: prodkey_win10 | ||||||
|     VSPHERE_PASSWORD: |  | ||||||
|       from_secret: vsphere_password |  | ||||||
|   volumes: |  | ||||||
|   - name: output |  | ||||||
|     path: /output |  | ||||||
|   - name: scratch |  | ||||||
|     path: /scratch |  | ||||||
|  |  | ||||||
| - name: Kubernetes Upgrade Appliance |  | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |  | ||||||
|   pull: alwaysquery( |  | ||||||
|   commands: |  | ||||||
|   - | |  | ||||||
|     sed -i -e "s/<<img-password>>/$${SSH_PASSWORD}/g" \ |  | ||||||
|       packer/preseed/UbuntuServer22.04/user-data |  | ||||||
|   - | |  | ||||||
|     export K8S_VERSION=$(yq '.components.clusterapi.workload.version.k8s' < ./ansible/vars/metacluster.yml) |  | ||||||
|     export APPLIANCE_VERSION=$(cat .version) |  | ||||||
|   - | |  | ||||||
|     packer init -upgrade \ |  | ||||||
|       ./packer |  | ||||||
|   - | |  | ||||||
|     packer validate \ |  | ||||||
|       -only=vsphere-iso.upgrade \ |  | ||||||
|       -var vm_name=${DRONE_BUILD_NUMBER}-${DRONE_COMMIT_SHA:0:10}-$(openssl rand -hex 3) \ |  | ||||||
|       -var docker_username=$${DOCKER_USERNAME} \ |  | ||||||
|       -var docker_password=$${DOCKER_PASSWORD} \ |  | ||||||
|       -var repo_username=$${REPO_USERNAME} \ |  | ||||||
|       -var repo_password=$${REPO_PASSWORD} \ |  | ||||||
|       -var ssh_password=$${SSH_PASSWORD} \ |  | ||||||
|       -var vsphere_password=$${VSPHERE_PASSWORD} \ |  | ||||||
|       -var k8s_version=$K8S_VERSION \ |  | ||||||
|       -var appliance_version=$APPLIANCE_VERSION \ |  | ||||||
|       ./packer |  | ||||||
|   - | |  | ||||||
|     packer build \ |  | ||||||
|       -on-error=cleanup -timestamp-ui \ |  | ||||||
|       -only=vsphere-iso.upgrade \ |  | ||||||
|       -var vm_name=${DRONE_BUILD_NUMBER}-${DRONE_COMMIT_SHA:0:10}-$(openssl rand -hex 3) \ |  | ||||||
|       -var docker_username=$${DOCKER_USERNAME} \ |  | ||||||
|       -var docker_password=$${DOCKER_PASSWORD} \ |  | ||||||
|       -var repo_username=$${REPO_USERNAME} \ |  | ||||||
|       -var repo_password=$${REPO_PASSWORD} \ |  | ||||||
|       -var ssh_password=$${SSH_PASSWORD} \ |  | ||||||
|       -var vsphere_password=$${VSPHERE_PASSWORD} \ |  | ||||||
|       -var k8s_version=$K8S_VERSION \ |  | ||||||
|       -var appliance_version=$APPLIANCE_VERSION \ |  | ||||||
|       ./packer |  | ||||||
|   environment: |  | ||||||
|     DOCKER_USERNAME: |  | ||||||
|       from_secret: docker_username |  | ||||||
|     DOCKER_PASSWORD: |  | ||||||
|       from_secret: docker_password |  | ||||||
|     # PACKER_LOG: 1 |     # PACKER_LOG: 1 | ||||||
|     REPO_USERNAME: |  | ||||||
|       from_secret: repo_username |  | ||||||
|     REPO_PASSWORD: |  | ||||||
|       from_secret: repo_password |  | ||||||
|     SSH_PASSWORD: |  | ||||||
|       from_secret: ssh_password |  | ||||||
|     VSPHERE_PASSWORD: |  | ||||||
|       from_secret: vsphere_password |  | ||||||
|   volumes: |   volumes: | ||||||
|   - name: output |   - name: output | ||||||
|     path: /output |     path: /output | ||||||
|   - name: scratch |  | ||||||
|     path: /scratch |  | ||||||
|  |  | ||||||
| - name: Remove temporary resources | - name: Remove temporary resources | ||||||
|   image: bv11-cr01.bessems.eu/library/packer-extended |   image: bv11-cr01.bessems.eu/library/packer-extended | ||||||
|   commands: |   commands: | ||||||
|   | |||||||
| @@ -1,151 +0,0 @@ | |||||||
| name: Container & Helm chart |  | ||||||
| on: [push] |  | ||||||
|  |  | ||||||
| jobs: |  | ||||||
|   linting: |  | ||||||
|     name: Linting |  | ||||||
|     runs-on: dind-rootless |  | ||||||
|     steps: |  | ||||||
|       - name: Check out repository code |  | ||||||
|         uses: actions/checkout@v4 |  | ||||||
|       - name: yamllint |  | ||||||
|         uses: bewuethr/yamllint-action@v1 |  | ||||||
|         with: |  | ||||||
|           config-file: .yamllint.yaml |  | ||||||
|  |  | ||||||
|   semrel_dryrun: |  | ||||||
|     name: Semantic Release (Dry-run) |  | ||||||
|     runs-on: dind-rootless |  | ||||||
|     outputs: |  | ||||||
|       version: ${{ steps.sem_rel.outputs.version }} |  | ||||||
|     steps: |  | ||||||
|       - name: Check out repository code |  | ||||||
|         uses: actions/checkout@v4 |  | ||||||
|       - name: Setup Node |  | ||||||
|         uses: actions/setup-node@v3 |  | ||||||
|         with: |  | ||||||
|           node-version: 20 |  | ||||||
|       - name: Install dependencies |  | ||||||
|         run: | |  | ||||||
|           npm install \ |  | ||||||
|             semantic-release \ |  | ||||||
|             @semantic-release/commit-analyzer \ |  | ||||||
|             @semantic-release/exec |  | ||||||
|       - name: Semantic Release (dry-run) |  | ||||||
|         id: sem_rel |  | ||||||
|         run: | |  | ||||||
|           npx semantic-release \ |  | ||||||
|             --package @semantic-release/exec \ |  | ||||||
|             --package semantic-release \ |  | ||||||
|             --branches ${{ gitea.refname }} \ |  | ||||||
|             --tag-format 'v${version}' \ |  | ||||||
|             --dry-run \ |  | ||||||
|             --plugins @semantic-release/commit-analyzer,@semantic-release/exec \ |  | ||||||
|             --analyzeCommits @semantic-release/commit-analyzer \ |  | ||||||
|             --verifyRelease @semantic-release/exec \ |  | ||||||
|             --verifyReleaseCmd 'echo "version=${nextRelease.version}" >> $GITHUB_OUTPUT' |  | ||||||
|         env: |  | ||||||
|           GIT_CREDENTIALS: ${{ secrets.GIT_USERNAME }}:${{ secrets.GIT_APIKEY }} |  | ||||||
|       - name: Assert semantic release output |  | ||||||
|         run: | |  | ||||||
|           [[ -z "${{ steps.sem_rel.outputs.version }}" ]] && { |  | ||||||
|             echo 'No release tag - exiting'; exit 1 |  | ||||||
|           } || { |  | ||||||
|             echo 'Release tag set correctly: ${{ steps.sem_rel.outputs.version }}'; exit 0 |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|   build_image: |  | ||||||
|     name: Kubernetes Bootstrap Appliance |  | ||||||
|     container: code.spamasaurus.com/djpbessems/packer-extended:1.3.0 |  | ||||||
|     runs-on: dind-rootless |  | ||||||
|     needs: [semrel_dryrun, linting] |  | ||||||
|     steps: |  | ||||||
|       - name: Checkout |  | ||||||
|         uses: actions/checkout@v4 |  | ||||||
|       - name: Parse Kubernetes version |  | ||||||
|         uses: mikefarah/yq@master |  | ||||||
|         id: get_k8sversion |  | ||||||
|         with: |  | ||||||
|           cmd: yq '.components.clusterapi.workload.version.k8s' ansible/vars/metacluster.yml |  | ||||||
|       - name: Set up packer |  | ||||||
|         uses: hashicorp/setup-packer@main |  | ||||||
|         id: setup |  | ||||||
|         with: |  | ||||||
|           version: "latest" |  | ||||||
|       - name: Prepare build environment |  | ||||||
|         id: init |  | ||||||
|         run: | |  | ||||||
|           packer init -upgrade ./packer |  | ||||||
|  |  | ||||||
|           ansible-galaxy collection install \ |  | ||||||
|             -r ansible/requirements.yml \ |  | ||||||
|             -p ./ansible/collections |  | ||||||
|  |  | ||||||
|           echo "BUILD_COMMIT=$(echo ${{ gitea.sha }} | cut -c 1-10)" >> $GITHUB_ENV |  | ||||||
|           echo "BUILD_SUFFIX=$(openssl rand -hex 3)" >> $GITHUB_ENV |  | ||||||
|       - name: Run `packer validate` |  | ||||||
|         id: validate |  | ||||||
|         run: | |  | ||||||
|           # BUILD_COMMIT=$(echo "${{ gitea.sha }}" | cut -c 1-10) |  | ||||||
|           # BUILD_SUFFIX=$(openssl rand -hex 3) |  | ||||||
|  |  | ||||||
|           packer validate \ |  | ||||||
|             -only=vsphere-iso.bootstrap \ |  | ||||||
|             -var vm_name=${{ gitea.run_number }}-${BUILD_COMMIT}-${BUILD_SUFFIX} \ |  | ||||||
|             -var docker_username=${{ secrets.DOCKER_USERNAME }} \ |  | ||||||
|             -var docker_password=${{ secrets.DOCKER_PASSWORD }} \ |  | ||||||
|             -var repo_username=${{ secrets.REPO_USERNAME }} \ |  | ||||||
|             -var repo_password=${{ secrets.REPO_PASSWORD }} \ |  | ||||||
|             -var ssh_password=${{ secrets.SSH_PASSWORD }} \ |  | ||||||
|             -var hv_password=${{ secrets.HV_PASSWORD }} \ |  | ||||||
|             -var k8s_version=${{ steps.get_k8sversion.outputs.result }} \ |  | ||||||
|             -var appliance_version=${{ needs.semrel_dryrun.outputs.version }} \ |  | ||||||
|             ./packer |  | ||||||
|       - name: Run `packer build` |  | ||||||
|         run: | |  | ||||||
|           # BUILD_COMMIT=$(echo "${{ gitea.sha }}" | cut -c 1-10) |  | ||||||
|           # BUILD_SUFFIX=$(openssl rand -hex 3) |  | ||||||
|  |  | ||||||
|           packer build \ |  | ||||||
|             -only=vsphere-iso.bootstrap \ |  | ||||||
|             -var vm_name=${{ gitea.run_number }}-${BUILD_COMMIT}-${BUILD_SUFFIX} \ |  | ||||||
|             -var docker_username=${{ secrets.DOCKER_USERNAME }} \ |  | ||||||
|             -var docker_password=${{ secrets.DOCKER_PASSWORD }} \ |  | ||||||
|             -var repo_username=${{ secrets.REPO_USERNAME }} \ |  | ||||||
|             -var repo_password=${{ secrets.REPO_PASSWORD }} \ |  | ||||||
|             -var ssh_password=${{ secrets.SSH_PASSWORD }} \ |  | ||||||
|             -var hv_password=${{ secrets.HV_PASSWORD }} \ |  | ||||||
|             -var k8s_version=${{ steps.get_k8sversion.outputs.result }} \ |  | ||||||
|             -var appliance_version=${{ needs.semrel_dryrun.outputs.version }} \ |  | ||||||
|             ./packer |  | ||||||
|         # env: |  | ||||||
|         #   PACKER_LOG: 1 |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   # semrel: |  | ||||||
|   #   name: Semantic Release |  | ||||||
|   #   runs-on: dind-rootless |  | ||||||
|   #   needs: [build_container, build_chart] |  | ||||||
|   #   steps: |  | ||||||
|   #     - name: Check out repository code |  | ||||||
|   #       uses: actions/checkout@v3 |  | ||||||
|   #     - name: Setup Node |  | ||||||
|   #       uses: actions/setup-node@v3 |  | ||||||
|   #       with: |  | ||||||
|   #         node-version: 20 |  | ||||||
|   #     - name: Install dependencies |  | ||||||
|   #       run: | |  | ||||||
|   #         npm install \ |  | ||||||
|   #           semantic-release \ |  | ||||||
|   #           @semantic-release/changelog \ |  | ||||||
|   #           @semantic-release/commit-analyzer \ |  | ||||||
|   #           @semantic-release/git \ |  | ||||||
|   #           @semantic-release/release-notes-generator |  | ||||||
|   #     - name: Semantic Release |  | ||||||
|   #       run: | |  | ||||||
|   #         npx semantic-release \ |  | ||||||
|   #           --branches ${{ gitea.refname }} \ |  | ||||||
|   #           --tag-format 'v${version}' \ |  | ||||||
|   #           --plugins @semantic-release/commit-analyzer,@semantic-release/release-notes-generator,@semantic-release/changelog,@semantic-release/git |  | ||||||
|   #       env: |  | ||||||
|   #         GIT_CREDENTIALS: ${{ secrets.GIT_USERNAME }}:${{ secrets.GIT_APIKEY }} |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| extends: relaxed |  | ||||||
|  |  | ||||||
| rules: |  | ||||||
|   line-length: disable |  | ||||||
| @@ -1 +1 @@ | |||||||
| # Packer.Images [](https://ci.spamasaurus.com/djpbessems/Packer.Images) | # Packer.Images [](https://ci.spamasaurus.com/djpbessems/Packer.Images) | ||||||
|   | |||||||
| @@ -1,3 +0,0 @@ | |||||||
| [defaults] |  | ||||||
| deprecation_warnings = False |  | ||||||
| remote_tmp           = /tmp/.ansible-${USER}/tmp |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| --- |  | ||||||
| - hosts: all |  | ||||||
|   gather_facts: false |  | ||||||
|   vars_files: |  | ||||||
|     - metacluster.yml |  | ||||||
|     - workloadcluster.yml |  | ||||||
|   become: true |  | ||||||
|   roles: |  | ||||||
|     - os |  | ||||||
|     - firstboot |  | ||||||
|     - assets |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| collections: |  | ||||||
|   - name: https://github.com/ansible-collections/ansible.posix |  | ||||||
|     type: git |  | ||||||
|   - name: https://github.com/ansible-collections/ansible.utils |  | ||||||
|     type: git |  | ||||||
|   - name: https://github.com/ansible-collections/community.general |  | ||||||
|     type: git |  | ||||||
|   - name: https://github.com/ansible-collections/kubernetes.core |  | ||||||
|     type: git |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| - name: Parse Cluster-API manifests for container images |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     # This set of commands is necessary to deal with multi-line scalar values |  | ||||||
|     # eg.: |  | ||||||
|     #      key: | |  | ||||||
|     #        multi-line |  | ||||||
|     #        value |  | ||||||
|     cmd: >- |  | ||||||
|       cat {{ item.dest }} | yq --no-doc eval '.. | .image? | select(.)' | awk '!/ /'; |  | ||||||
|       cat {{ item.dest }} | yq eval '.data.data' | yq --no-doc eval '.. | .image? | select(.)'; |  | ||||||
|       cat {{ item.dest }} | yq --no-doc eval '.. | .files? | with_entries(select(.value.path == "*.yaml")).[0].content' | awk '!/null/' | yq eval '.. | .image? | select(.)' |  | ||||||
|   register: clusterapi_parsedmanifests |  | ||||||
|   loop: "{{ clusterapi_manifests.results }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.dest | basename }}" |  | ||||||
|  |  | ||||||
| - name: Parse pinniped manifest for container images |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       cat {{ pinniped_manifest.dest }} | yq --no-doc eval '.. | .image? | select(.)' | awk '!/ /'; |  | ||||||
|   register: pinniped_parsedmanifest |  | ||||||
|  |  | ||||||
| - name: Parse metacluster helm charts for container images |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: "{{ item.value.helm.parse_logic }}" |  | ||||||
|     chdir: /opt/metacluster/helm-charts/{{ item.key }} |  | ||||||
|   register: chartimages_metacluster |  | ||||||
|   when: item.value.helm is defined |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', components) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
| - name: Parse workloadcluster helm charts for container images |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: "{{ item.value.parse_logic }}" |  | ||||||
|     chdir: /opt/workloadcluster/helm-charts/{{ item.value.namespace }}/{{ item.key }} |  | ||||||
|   register: chartimages_workloadcluster |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', downstream.helm_charts) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
| - name: Store container images in dicts |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     containerimages_{{ item.source }}: "{{ item.results }}" |  | ||||||
|   loop: |  | ||||||
|     - source: charts |  | ||||||
|       results: "{{ (chartimages_metacluster | json_query('results[*].stdout_lines')) + (chartimages_workloadcluster | json_query('results[*].stdout_lines')) | select() | flatten | list }}" |  | ||||||
|     - source: kubeadm |  | ||||||
|       results: "{{ kubeadmimages.stdout_lines }}" |  | ||||||
|     - source: clusterapi |  | ||||||
|       results: "{{ clusterapi_parsedmanifests | json_query('results[*].stdout_lines') | select() | flatten | list }}" |  | ||||||
|     - source: pinniped |  | ||||||
|       results: "{{ pinniped_parsedmanifest.stdout_lines }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.source }}" |  | ||||||
|  |  | ||||||
| - name: Log in to container registry |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       skopeo login \ |  | ||||||
|         docker.io \ |  | ||||||
|         --username={{ docker_username }} \ |  | ||||||
|         --password={{ docker_password }} |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Pull and store containerimages |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       skopeo copy \ |  | ||||||
|         --insecure-policy \ |  | ||||||
|         --retry-times=5 \ |  | ||||||
|         docker://{{ item }} \ |  | ||||||
|         docker-archive:./{{ ( item | regex_findall('[^/:]+'))[-2] }}_{{ lookup('ansible.builtin.password', '/dev/null length=5 chars=ascii_lowercase,digits seed={{ item }}') }}.tar:{{ item }} |  | ||||||
|     chdir: /opt/metacluster/container-images |  | ||||||
|   loop: "{{ (containerimages_charts + containerimages_kubeadm + containerimages_clusterapi + containerimages_pinniped + dependencies.container_images) | flatten | unique | sort }}" |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| --- |  | ||||||
| - name: Initialize tempfolder |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: directory |  | ||||||
|   register: archive |  | ||||||
|  |  | ||||||
| - name: Download & extract archived static binary |  | ||||||
|   ansible.builtin.unarchive: |  | ||||||
|     src: "{{ item.url }}" |  | ||||||
|     dest: "{{ archive.path }}" |  | ||||||
|     remote_src: yes |  | ||||||
|     extra_opts: "{{ item.extra_opts | default(omit) }}" |  | ||||||
|   register: staticbinary_download |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: staticbinary_download is not failed |  | ||||||
|  |  | ||||||
| - name: Install extracted binary |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     src: "{{ archive.path }}/{{ item.filename }}" |  | ||||||
|     dest: /usr/local/bin/{{ item.filename }} |  | ||||||
|     remote_src: yes |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0755 |  | ||||||
|  |  | ||||||
| - name: Cleanup tempfolder |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ archive.path }}" |  | ||||||
|     state: absent |  | ||||||
|   when: archive.path is defined |  | ||||||
| @@ -1,54 +0,0 @@ | |||||||
| - name: Download & install static binaries |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: "{{ item.url }}" |  | ||||||
|     url_username: "{{ item.username | default(omit) }}" |  | ||||||
|     url_password: "{{ item.password | default(omit) }}" |  | ||||||
|     dest: /usr/local/bin/{{ item.filename }} |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0755 |  | ||||||
|   register: staticbinary_download |  | ||||||
|   loop: "{{ dependencies.static_binaries | selectattr('archive', 'undefined') }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.filename }}" |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: staticbinary_download is not failed |  | ||||||
|  |  | ||||||
| - name: Download, extract & install archived static binaries |  | ||||||
|   include_tasks: dependencies.archive_compressed.yml |  | ||||||
|   loop: "{{ dependencies.static_binaries | rejectattr('archive', 'undefined') | selectattr('archive', 'equalto', 'compressed') }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.filename }}" |  | ||||||
|  |  | ||||||
| - name: Install ansible-galaxy collections |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: ansible-galaxy collection install {{ item }} |  | ||||||
|   register: collections |  | ||||||
|   loop: "{{ dependencies.ansible_galaxy_collections }}" |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: collections is not failed |  | ||||||
|  |  | ||||||
| - name: Install distro packages |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     pkg: "{{ dependencies.packages.apt }}" |  | ||||||
|     state: latest |  | ||||||
|     update_cache: yes |  | ||||||
|     install_recommends: no |  | ||||||
|  |  | ||||||
| - name: Upgrade all packages |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: '*' |  | ||||||
|     state: latest |  | ||||||
|     update_cache: yes |  | ||||||
|  |  | ||||||
| - name: Install additional python packages |  | ||||||
|   ansible.builtin.pip: |  | ||||||
|     name: "{{ dependencies.packages.pip }}" |  | ||||||
|     state: latest |  | ||||||
|  |  | ||||||
| - name: Cleanup apt cache |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     autoremove: yes |  | ||||||
|     purge: yes |  | ||||||
| @@ -1,31 +0,0 @@ | |||||||
| - name: Add helm repositories |  | ||||||
|   kubernetes.core.helm_repository: |  | ||||||
|     name: "{{ item.name }}" |  | ||||||
|     repo_url: "{{ item.url }}" |  | ||||||
|     state: present |  | ||||||
|   loop: "{{ platform.helm_repositories + downstream.helm_repositories }}" |  | ||||||
|  |  | ||||||
| - name: Fetch helm charts for metacluster |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: helm fetch {{ item.value.helm.chart }} --untar --version {{ item.value.helm.version }} |  | ||||||
|     chdir: /opt/metacluster/helm-charts |  | ||||||
|   when: item.value.helm is defined |  | ||||||
|   register: helmcharts_metacluster |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', components) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: helmcharts_metacluster is not failed |  | ||||||
|  |  | ||||||
| - name: Fetch helm charts for workloadcluster |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: helm fetch {{ item.value.chart }} --untardir ./{{ item.value.namespace }} --untar --version {{ item.value.version }} |  | ||||||
|     chdir: /opt/workloadcluster/helm-charts |  | ||||||
|   register: helmcharts_workloadcluster |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', downstream.helm_charts) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: helmcharts_workloadcluster is not failed |  | ||||||
| @@ -1,43 +0,0 @@ | |||||||
| - name: Download & install K3s binary |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://github.com/k3s-io/k3s/releases/download/{{ platform.k3s.version }}/k3s |  | ||||||
|     dest: /usr/local/bin/k3s |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0755 |  | ||||||
|   register: download |  | ||||||
|   until: download is not failed |  | ||||||
|   retries: 3 |  | ||||||
|   delay: 10 |  | ||||||
|  |  | ||||||
| - name: Download K3s images tarball |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://github.com/k3s-io/k3s/releases/download/{{ platform.k3s.version }}/k3s-airgap-images-amd64.tar.gz |  | ||||||
|     dest: /var/lib/rancher/k3s/agent/images |  | ||||||
|   register: download |  | ||||||
|   until: download is not failed |  | ||||||
|   retries: 3 |  | ||||||
|   delay: 10 |  | ||||||
|  |  | ||||||
| - name: Download K3s install script |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://raw.githubusercontent.com/k3s-io/k3s/{{ platform.k3s.version | urlencode }}/install.sh |  | ||||||
|     dest: /opt/metacluster/k3s/install.sh |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0755 |  | ||||||
|   register: download |  | ||||||
|   until: download is not failed |  | ||||||
|   retries: 3 |  | ||||||
|   delay: 10 |  | ||||||
|  |  | ||||||
| - name: Inject manifests |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: helmchartconfig.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ item.name }}-config.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   loop: "{{ platform.packaged_components }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.name }}" |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| - name: Initialize tempfile |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: directory |  | ||||||
|   register: kubeadm |  | ||||||
|  |  | ||||||
| - name: Download kubeadm binary |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://dl.k8s.io/release/{{ components.clusterapi.workload.version.k8s }}/bin/linux/amd64/kubeadm |  | ||||||
|     dest: "{{ kubeadm.path }}/kubeadm" |  | ||||||
|     mode: u+x |  | ||||||
|  |  | ||||||
| - name: Retrieve container images list |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: "{{ kubeadm.path }}/kubeadm config images list --kubernetes-version {{ components.clusterapi.workload.version.k8s }}" |  | ||||||
|   register: kubeadmimages |  | ||||||
|  |  | ||||||
| - name: Store list of container images for reference |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /opt/metacluster/cluster-api/imagelist |  | ||||||
|     content: "{{ kubeadmimages.stdout }}" |  | ||||||
|  |  | ||||||
| - name: Cleanup tempfile |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ kubeadm.path }}" |  | ||||||
|     state: absent |  | ||||||
|   when: kubeadm.path is defined |  | ||||||
| @@ -1,32 +0,0 @@ | |||||||
| - name: Create folder structure(s) |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item }}" |  | ||||||
|     state: directory |  | ||||||
|   loop: |  | ||||||
|     - /etc/rancher/k3s |  | ||||||
|     - /opt/metacluster/cluster-api/bootstrap-kubeadm/{{ components.clusterapi.management.version.base }} |  | ||||||
|     - /opt/metacluster/cluster-api/cert-manager/{{ components.clusterapi.management.version.cert_manager }} |  | ||||||
|     - /opt/metacluster/cluster-api/cluster-api/{{ components.clusterapi.management.version.base }} |  | ||||||
|     - /opt/metacluster/cluster-api/cni-calico/{{ components.clusterapi.workload.version.calico }} |  | ||||||
|     - /opt/metacluster/cluster-api/control-plane-kubeadm/{{ components.clusterapi.management.version.base }} |  | ||||||
|     - /opt/metacluster/cluster-api/infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }} |  | ||||||
|     - /opt/metacluster/cluster-api/ipam-in-cluster/{{ components.clusterapi.management.version.ipam_incluster }} |  | ||||||
|     - /opt/metacluster/container-images |  | ||||||
|     - /opt/metacluster/git-repositories |  | ||||||
|     - /opt/metacluster/helm-charts |  | ||||||
|     - /opt/metacluster/k3s |  | ||||||
|     - /opt/metacluster/kube-vip |  | ||||||
|     - /opt/metacluster/pinniped |  | ||||||
|     - /opt/workloadcluster/helm-charts |  | ||||||
|     - /opt/workloadcluster/node-templates |  | ||||||
|     - /var/lib/rancher/k3s/agent/images |  | ||||||
|     - /var/lib/rancher/k3s/server/manifests |  | ||||||
|  |  | ||||||
| - import_tasks: dependencies.yml |  | ||||||
| - import_tasks: k3s.yml |  | ||||||
| - import_tasks: helm.yml |  | ||||||
| # - import_tasks: git.yml |  | ||||||
| - import_tasks: manifests.yml |  | ||||||
| - import_tasks: kubeadm.yml |  | ||||||
| - import_tasks: containerimages.yml |  | ||||||
| - import_tasks: nodetemplates.yml |  | ||||||
| @@ -1,137 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Aggregate meta-cluster chart_values into dict |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         metacluster_chartvalues: "{{ metacluster_chartvalues | default({}) | combine({ item.key: { 'chart_values': (item.value.helm.chart_values | from_yaml) } }) }}" |  | ||||||
|       when: item.value.helm.chart_values is defined |  | ||||||
|       loop: "{{ query('ansible.builtin.dict', components) }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
|     - name: Combine and write dict to vars_file |  | ||||||
|       ansible.builtin.copy: |  | ||||||
|         dest: /opt/firstboot/ansible/vars/metacluster.yml |  | ||||||
|         content: >- |  | ||||||
|           {{ |  | ||||||
|             { 'components': ( |  | ||||||
|               metacluster_chartvalues | |  | ||||||
|               combine({ 'clusterapi'            : components['clusterapi'] }) | |  | ||||||
|               combine({ 'kubevip'               : components['kubevip'] }) | |  | ||||||
|               combine({ 'localuserauthenticator': components['pinniped']['local-user-authenticator'] })), |  | ||||||
|               'appliance': { |  | ||||||
|                 'version': (applianceversion) |  | ||||||
|               } |  | ||||||
|             } | to_nice_yaml(indent=2, width=4096) |  | ||||||
|           }} |  | ||||||
|  |  | ||||||
|     - name: Aggregate workload-cluster chart_values into dict |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         workloadcluster_chartvalues: | |  | ||||||
|           {{ |  | ||||||
|             workloadcluster_chartvalues | default({}) | combine({ |  | ||||||
|               item.key: { |  | ||||||
|                 'chart_values': (item.value.chart_values | default('') | from_yaml), |  | ||||||
|                 'extra_manifests': (item.value.extra_manifests | default([])), |  | ||||||
|                 'namespace': (item.value.namespace) |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           }} |  | ||||||
|       loop: "{{ query('ansible.builtin.dict', downstream.helm_charts) }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
|     - name: Write dict to vars_file |  | ||||||
|       ansible.builtin.copy: |  | ||||||
|         dest: /opt/firstboot/ansible/vars/workloadcluster.yml |  | ||||||
|         content: >- |  | ||||||
|           {{ |  | ||||||
|             { 'downstream_components': ( workloadcluster_chartvalues ) |  | ||||||
|             } | to_nice_yaml(indent=2, width=4096) |  | ||||||
|           }} |  | ||||||
|  |  | ||||||
| - name: Download Cluster-API manifests |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: "{{ item.url }}" |  | ||||||
|     dest: /opt/metacluster/cluster-api/{{ item.dest }} |  | ||||||
|   register: clusterapi_manifests |  | ||||||
|   loop: |  | ||||||
|     # This list is based on `clusterctl config repositories` |  | ||||||
|     # Note: Each manifest also needs a `metadata.yaml` file stored in the respective folder |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/bootstrap-components.yaml |  | ||||||
|       dest: bootstrap-kubeadm/{{ components.clusterapi.management.version.base }}/bootstrap-components.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/core-components.yaml |  | ||||||
|       dest: cluster-api/{{ components.clusterapi.management.version.base }}/core-components.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/control-plane-components.yaml |  | ||||||
|       dest: control-plane-kubeadm/{{ components.clusterapi.management.version.base }}/control-plane-components.yaml |  | ||||||
|     # This downloads the same `metadata.yaml` file to three separate folders |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|       dest: bootstrap-kubeadm/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|       dest: cluster-api/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api/releases/download/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|       dest: control-plane-kubeadm/{{ components.clusterapi.management.version.base }}/metadata.yaml |  | ||||||
|     # The vsphere infrastructure provider requires multiple files (`cluster-template.yaml` and `metadata.yaml` on top of default files) |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/download/{{ components.clusterapi.management.version.infrastructure_vsphere }}/infrastructure-components.yaml |  | ||||||
|       dest: infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }}/infrastructure-components.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/download/{{ components.clusterapi.management.version.infrastructure_vsphere }}/cluster-template.yaml |  | ||||||
|       dest: infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }}/cluster-template.yaml |  | ||||||
|     - url: https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/download/{{ components.clusterapi.management.version.infrastructure_vsphere }}/metadata.yaml |  | ||||||
|       dest: infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }}/metadata.yaml |  | ||||||
|     # Additionally, cert-manager is a prerequisite |  | ||||||
|     - url: https://github.com/cert-manager/cert-manager/releases/download/{{ components.clusterapi.management.version.cert_manager }}/cert-manager.yaml |  | ||||||
|       dest: cert-manager/{{ components.clusterapi.management.version.cert_manager }}/cert-manager.yaml |  | ||||||
|     # Finally, workload clusters will need a CNI plugin |  | ||||||
|     - url: https://raw.githubusercontent.com/projectcalico/calico/{{ components.clusterapi.workload.version.calico }}/manifests/calico.yaml |  | ||||||
|       dest: cni-calico/{{ components.clusterapi.workload.version.calico }}/calico.yaml |  | ||||||
|     # IPAM in-cluster provider (w/ metadata.yaml) |  | ||||||
|     - url: https://github.com/telekom/cluster-api-ipam-provider-in-cluster/releases/download/{{ components.clusterapi.management.version.ipam_incluster }}/ipam-components.yaml |  | ||||||
|       dest: ipam-in-cluster/{{ components.clusterapi.management.version.ipam_incluster }}/ipam-components.yaml |  | ||||||
|     - url: https://github.com/telekom/cluster-api-ipam-provider-in-cluster/releases/download/{{ components.clusterapi.management.version.ipam_incluster }}/metadata.yaml |  | ||||||
|       dest: ipam-in-cluster/{{ components.clusterapi.management.version.ipam_incluster }}/metadata.yaml |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.url | basename }}" |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: clusterapi_manifests is not failed |  | ||||||
|  |  | ||||||
| - name: Update cluster-template with image tags |  | ||||||
|   ansible.builtin.replace: |  | ||||||
|     dest: /opt/metacluster/cluster-api/infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }}/cluster-template.yaml |  | ||||||
|     regexp: ':\${CPI_IMAGE_K8S_VERSION}' |  | ||||||
|     replace: ":{{ components.clusterapi.management.version.cpi_vsphere }}" |  | ||||||
|  |  | ||||||
| - name: Download kube-vip RBAC manifest |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://kube-vip.io/manifests/rbac.yaml |  | ||||||
|     dest: /opt/metacluster/kube-vip/rbac.yaml |  | ||||||
|   register: kubevip_manifest |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: kubevip_manifest is not failed |  | ||||||
|  |  | ||||||
| - name: Download pinniped local-user-authenticator manifest |  | ||||||
|   ansible.builtin.get_url: |  | ||||||
|     url: https://get.pinniped.dev/{{ components.pinniped['local-user-authenticator'].version }}/install-local-user-authenticator.yaml |  | ||||||
|     dest: /opt/metacluster/pinniped/local-user-authenticator.yaml |  | ||||||
|   register: pinniped_manifest |  | ||||||
|   retries: 5 |  | ||||||
|   delay: 5 |  | ||||||
|   until: pinniped_manifest is not failed |  | ||||||
|  |  | ||||||
| - name: Trim image hash from manifest |  | ||||||
|   ansible.builtin.replace: |  | ||||||
|     path: /opt/metacluster/pinniped/local-user-authenticator.yaml |  | ||||||
|     regexp: '([ ]*image: .*)@.*' |  | ||||||
|     replace: '\1' |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| # - name: Inject manifests |  | ||||||
| #   ansible.builtin.template: |  | ||||||
| #     src: "{{ item.type }}.j2" |  | ||||||
| #     dest: /var/lib/rancher/k3s/server/manifests/{{ item.name }}-manifest.yaml |  | ||||||
| #     owner: root |  | ||||||
| #     group: root |  | ||||||
| #     mode: 0600 |  | ||||||
| #   loop: "{{ query('ansible.builtin.dict', components) | map(attribute='value.manifests') | list | select('defined') | flatten }}" |  | ||||||
| #   loop_control: |  | ||||||
| #     label: "{{ item.type ~ '/' ~ item.name }}" |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| - name: Download node-template image |  | ||||||
|   ansible.builtin.uri: |  | ||||||
|     url: "{{ components.clusterapi.workload.node_template.url }}" |  | ||||||
|     dest: /opt/workloadcluster/node-templates/{{ components.clusterapi.workload.node_template.url | basename}} |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| apiVersion: helm.cattle.io/v1 |  | ||||||
| kind: HelmChartConfig |  | ||||||
| metadata: |  | ||||||
|   name: {{ item.name }} |  | ||||||
|   namespace: {{ item.namespace }} |  | ||||||
| spec: |  | ||||||
|   valuesContent: |- |  | ||||||
| {{ item.config }} |  | ||||||
| @@ -1,30 +0,0 @@ | |||||||
| --- |  | ||||||
| - hosts: 127.0.0.1 |  | ||||||
|   connection: local |  | ||||||
|   gather_facts: true |  | ||||||
|   vars: |  | ||||||
|     # Needed by some templating in various tasks |  | ||||||
|     _newline: "\n" |  | ||||||
|   vars_files: |  | ||||||
|     - defaults.yml |  | ||||||
|     - metacluster.yml |  | ||||||
|     - workloadcluster.yml |  | ||||||
|   # become: true |  | ||||||
|   roles: |  | ||||||
|     - vapp |  | ||||||
|     - network |  | ||||||
|     - preflight |  | ||||||
|     - users |  | ||||||
|     - disks |  | ||||||
|     - metacluster |  | ||||||
|     - workloadcluster |  | ||||||
|     - tty |  | ||||||
|     - cleanup |  | ||||||
|   handlers: |  | ||||||
|     - name: Apply manifests |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         src: "{{ item }}" |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       loop: "{{ query('ansible.builtin.fileglob', '/var/lib/rancher/k3s/server/manifests/*.yaml') | sort }}" |  | ||||||
|       ignore_errors: yes |  | ||||||
| @@ -1,176 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install dex |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: dex |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/dex |  | ||||||
|         release_namespace: dex |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['dex'].chart_values }}" |  | ||||||
|  |  | ||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install pinniped local-user-authenticator |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         src: /opt/metacluster/pinniped/local-user-authenticator.yaml |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|  |  | ||||||
|     - name: Create local-user-authenticator accounts |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         template: secret.j2 |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: "{{ item.username }}" |  | ||||||
|           namespace: local-user-authenticator |  | ||||||
|           type: '' |  | ||||||
|           data: |  | ||||||
|             - key: groups |  | ||||||
|               value: "{{ 'group1,group2' | b64encode }}" |  | ||||||
|             - key: passwordHash |  | ||||||
|               value: "{{ item.password | b64encode }}" |  | ||||||
|       loop: "{{ components['localuserauthenticator'].users }}" |  | ||||||
|  |  | ||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install pinniped chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: pinniped |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/pinniped |  | ||||||
|         release_namespace: pinniped-supervisor |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['pinniped'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Add ingress for supervisor |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         template: "{{ item.kind }}.j2" |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: "{{ item.name }}" |  | ||||||
|           namespace: "{{ item.namespace }}" |  | ||||||
|           spec: "{{ item.spec }}" |  | ||||||
|       loop: |  | ||||||
|         - kind: ingressroute |  | ||||||
|           name: pinniped-supervisor |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           spec: |2 |  | ||||||
|               entryPoints: |  | ||||||
|               - web |  | ||||||
|               - websecure |  | ||||||
|               routes: |  | ||||||
|               - kind: Rule |  | ||||||
|                 match: Host(`auth.{{ vapp['metacluster.fqdn'] }}`) |  | ||||||
|                 services: |  | ||||||
|                 - kind: Service |  | ||||||
|                   name: pinniped-supervisor |  | ||||||
|                   namespace: pinniped-supervisor |  | ||||||
|                   port: 443 |  | ||||||
|                   scheme: https |  | ||||||
|                   serversTransport: pinniped-supervisor |  | ||||||
|         - kind: serverstransport |  | ||||||
|           name: pinniped-supervisor |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           spec: |2 |  | ||||||
|               insecureSkipVerify: true |  | ||||||
|               serverName: auth.{{ vapp['metacluster.fqdn'] }} |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.kind ~ '/' ~ item.name ~ ' (' ~ item.namespace ~ ')' }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure pinniped API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://auth.{{ vapp['metacluster.fqdn'] }}/healthz |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.status == 200 |  | ||||||
|         - api_readycheck.msg is search("OK") |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|  |  | ||||||
|     # TODO: Migrate to step-ca |  | ||||||
|     - name: Initialize tempfile |  | ||||||
|       ansible.builtin.tempfile: |  | ||||||
|         state: directory |  | ||||||
|       register: certificate |  | ||||||
|  |  | ||||||
|     - name: Create private key (RSA, 4096 bits) |  | ||||||
|       community.crypto.openssl_privatekey: |  | ||||||
|         path: "{{ certificate.path }}/certificate.key" |  | ||||||
|  |  | ||||||
|     - name: Create self-signed certificate |  | ||||||
|       community.crypto.x509_certificate: |  | ||||||
|         path: "{{ certificate.path }}/certificate.crt" |  | ||||||
|         privatekey_path: "{{ certificate.path }}/certificate.key" |  | ||||||
|         provider: selfsigned |  | ||||||
|  |  | ||||||
|     - name: Store self-signed certificate for use by pinniped supervisor |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         template: secret.j2 |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: pinniped-supervisor-tls |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           type: kubernetes.io/tls |  | ||||||
|           data: |  | ||||||
|             - key: tls.crt |  | ||||||
|               value: "{{ lookup('ansible.builtin.file', certificate.path ~ '/certificate.crt') | b64encode }}" |  | ||||||
|             - key: tls.key |  | ||||||
|               value: "{{ lookup('ansible.builtin.file', certificate.path ~ '/certificate.key') | b64encode }}" |  | ||||||
|     # TODO: Migrate to step-ca |  | ||||||
|  |  | ||||||
|     - name: Create pinniped resources |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         template: "{{ item.kind }}.j2" |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: "{{ item.name }}" |  | ||||||
|           namespace: "{{ item.namespace }}" |  | ||||||
|           type: "{{ item.type | default('') }}" |  | ||||||
|           data: "{{ item.data | default(omit) }}" |  | ||||||
|           spec: "{{ item.spec | default(omit) }}" |  | ||||||
|       loop: |  | ||||||
|         - kind: oidcidentityprovider |  | ||||||
|           name: dex-staticpasswords |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           spec: |2 |  | ||||||
|               issuer: https://idps.{{ vapp['metacluster.fqdn'] }} |  | ||||||
|               tls: |  | ||||||
|                 certificateAuthorityData: "{{ (stepca_cm_certs.resources[0].data['intermediate_ca.crt'] ~ _newline ~ stepca_cm_certs.resources[0].data['root_ca.crt']) | b64encode }}" |  | ||||||
|               authorizationConfig: |  | ||||||
|                 additionalScopes: [offline_access, groups, email] |  | ||||||
|                 allowPasswordGrant: false |  | ||||||
|               claims: |  | ||||||
|                 username: email |  | ||||||
|                 groups: groups |  | ||||||
|               client: |  | ||||||
|                 secretName: dex-clientcredentials |  | ||||||
|         - kind: secret |  | ||||||
|           name: dex-clientcredentials |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           type: secrets.pinniped.dev/oidc-client |  | ||||||
|           data: |  | ||||||
|             - key: clientID |  | ||||||
|               value: "{{ 'pinniped-supervisor' | b64encode }}" |  | ||||||
|             - key: clientSecret |  | ||||||
|               value: "{{ lookup('ansible.builtin.password', '/dev/null length=64 chars=ascii_lowercase,digits seed=' ~ vapp['metacluster.fqdn']) | b64encode }}" |  | ||||||
|         - kind: federationdomain |  | ||||||
|           name: metacluster-sso |  | ||||||
|           namespace: pinniped-supervisor |  | ||||||
|           spec: |2 |  | ||||||
|               issuer: https://auth.{{ vapp['metacluster.fqdn'] }}/sso |  | ||||||
|               tls: |  | ||||||
|                 secretName: pinniped-supervisor-tls |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.kind ~ '/' ~ item.name }}" |  | ||||||
| @@ -1,139 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Inject password into values file |  | ||||||
|       ansible.builtin.copy: |  | ||||||
|         dest: "{{ stepconfig.path }}" |  | ||||||
|         content: "{{ lookup('ansible.builtin.file', stepconfig.path) | regex_replace('(ca_password|provisioner_password):[ ]?\n', '\\1: ' ~ (vapp['metacluster.password'] | b64encode) ~ '\n') }}" |  | ||||||
|       no_log: true |  | ||||||
|  |  | ||||||
|     - name: Install step-ca chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: step-certificates |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/step-certificates |  | ||||||
|         release_namespace: step-ca |  | ||||||
|         create_namespace: true |  | ||||||
|         # Unable to use REST api based readycheck due to lack of ingress |  | ||||||
|         wait: true |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values_files: |  | ||||||
|           - "{{ stepconfig.path }}" |  | ||||||
|  |  | ||||||
|     - name: Retrieve configmap w/ root certificate |  | ||||||
|       kubernetes.core.k8s_info: |  | ||||||
|         kind: ConfigMap |  | ||||||
|         name: step-certificates-certs |  | ||||||
|         namespace: step-ca |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       register: stepca_cm_certs |  | ||||||
|  |  | ||||||
|     - name: Create target namespaces |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         kind: Namespace |  | ||||||
|         name: "{{ item }}" |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       loop: |  | ||||||
|         - argo-cd |  | ||||||
|         - gitea |  | ||||||
|         # - kube-system |  | ||||||
|  |  | ||||||
|     - name: Store root certificate in namespaced configmaps/secrets |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         state: present |  | ||||||
|         template: "{{ item.kind }}.j2" |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: "{{ item.name }}" |  | ||||||
|           namespace: "{{ item.namespace }}" |  | ||||||
|           annotations: "{{ item.annotations | default('{}') | indent(width=4, first=True) }}" |  | ||||||
|           labels: "{{ item.labels | default('{}') | indent(width=4, first=True) }}" |  | ||||||
|           type: "{{ item.type | default('') }}" |  | ||||||
|           data: "{{ item.data }}" |  | ||||||
|       loop: |  | ||||||
|         - name: argocd-tls-certs-cm |  | ||||||
|           namespace: argo-cd |  | ||||||
|           kind: configmap |  | ||||||
|           annotations: | |  | ||||||
|             meta.helm.sh/release-name: argo-cd |  | ||||||
|             meta.helm.sh/release-namespace: argo-cd |  | ||||||
|           labels: | |  | ||||||
|             app.kubernetes.io/managed-by: Helm |  | ||||||
|             app.kubernetes.io/name: argocd-cm |  | ||||||
|             app.kubernetes.io/part-of: argocd |  | ||||||
|           data: |  | ||||||
|             - key: git.{{ vapp['metacluster.fqdn'] }} |  | ||||||
|               value: "{{ stepca_cm_certs.resources[0].data['root_ca.crt'] }}" |  | ||||||
|         - name: step-certificates-certs |  | ||||||
|           namespace: gitea |  | ||||||
|           kind: secret |  | ||||||
|           data: |  | ||||||
|             - key: ca_chain.crt |  | ||||||
|               value: "{{ (stepca_cm_certs.resources[0].data['intermediate_ca.crt'] ~ _newline ~ stepca_cm_certs.resources[0].data['root_ca.crt']) | b64encode }}" |  | ||||||
|         - name: step-certificates-certs |  | ||||||
|           namespace: kube-system |  | ||||||
|           kind: secret |  | ||||||
|           data: |  | ||||||
|             - key: root_ca.crt |  | ||||||
|               value: "{{ stepca_cm_certs.resources[0].data['root_ca.crt'] | b64encode }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.kind ~ '/' ~ item.name ~ ' (' ~ item.namespace ~ ')' }}" |  | ||||||
|  |  | ||||||
|     - name: Configure step-ca passthrough ingress |  | ||||||
|       ansible.builtin.template: |  | ||||||
|         src: ingressroutetcp.j2 |  | ||||||
|         dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|         owner: root |  | ||||||
|         group: root |  | ||||||
|         mode: 0600 |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: step-ca |  | ||||||
|           namespace: step-ca |  | ||||||
|           spec: |2 |  | ||||||
|               entryPoints: |  | ||||||
|                 - websecure |  | ||||||
|               routes: |  | ||||||
|               - match: HostSNI(`ca.{{ vapp['metacluster.fqdn'] }}`) |  | ||||||
|                 services: |  | ||||||
|                 - name: step-certificates |  | ||||||
|                   port: 443 |  | ||||||
|               tls: |  | ||||||
|                 passthrough: true |  | ||||||
|       notify: |  | ||||||
|         - Apply manifests |  | ||||||
|  |  | ||||||
|     - name: Inject step-ca certificate into traefik container |  | ||||||
|       ansible.builtin.blockinfile: |  | ||||||
|         path: /var/lib/rancher/k3s/server/manifests/traefik-config.yaml |  | ||||||
|         block: |2 |  | ||||||
|               volumes: |  | ||||||
|                 - name: step-certificates-certs |  | ||||||
|                   mountPath: /step-ca |  | ||||||
|                   type: secret |  | ||||||
|               env: |  | ||||||
|                 - name: LEGO_CA_CERTIFICATES |  | ||||||
|                   value: /step-ca/root_ca.crt |  | ||||||
|         marker: '    # {mark} ANSIBLE MANAGED BLOCK [rootca]' |  | ||||||
|       notify: |  | ||||||
|         - Apply manifests |  | ||||||
|  |  | ||||||
|     - name: Trigger handlers |  | ||||||
|       ansible.builtin.meta: flush_handlers |  | ||||||
|  |  | ||||||
|     - 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: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,152 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install gitea chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: gitea |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/gitea |  | ||||||
|         release_namespace: gitea |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['gitea'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure gitea API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/api/healthz |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.status is defined |  | ||||||
|         - api_readycheck.json.status == 'pass' |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|     - name: Configure additional SSH ingress |  | ||||||
|       ansible.builtin.template: |  | ||||||
|         src: ingressroutetcp.j2 |  | ||||||
|         dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|         owner: root |  | ||||||
|         group: root |  | ||||||
|         mode: 0600 |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: gitea-ssh |  | ||||||
|           namespace: gitea |  | ||||||
|           spec: |2 |  | ||||||
|               entryPoints: |  | ||||||
|                 - ssh |  | ||||||
|               routes: |  | ||||||
|               - match: HostSNI(`*`) |  | ||||||
|                 services: |  | ||||||
|                 - name: gitea-ssh |  | ||||||
|                   port: 22 |  | ||||||
|       notify: |  | ||||||
|         - Apply manifests |  | ||||||
|  |  | ||||||
|     - name: Trigger handlers |  | ||||||
|       ansible.builtin.meta: flush_handlers |  | ||||||
|  |  | ||||||
|     - name: Generate gitea API token |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/api/v1/users/administrator/tokens |  | ||||||
|         method: POST |  | ||||||
|         user: administrator |  | ||||||
|         password: "{{ vapp['metacluster.password'] }}" |  | ||||||
|         force_basic_auth: yes |  | ||||||
|         body: |  | ||||||
|           name: token_init_{{ lookup('password', '/dev/null length=5 chars=ascii_letters,digits') }} |  | ||||||
|           scopes: ["write:user","write:organization"] |  | ||||||
|       register: gitea_api_token |  | ||||||
|  |  | ||||||
|     - name: Retrieve existing gitea configuration |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/api/v1/repos/search |  | ||||||
|         method: GET |  | ||||||
|       register: gitea_existing_config |  | ||||||
|  |  | ||||||
|     - block: |  | ||||||
|  |  | ||||||
|         - name: Register SSH public key |  | ||||||
|           ansible.builtin.uri: |  | ||||||
|             url: https://git.{{ vapp['metacluster.fqdn'] }}/api/v1/user/keys |  | ||||||
|             method: POST |  | ||||||
|             headers: |  | ||||||
|               Authorization: token {{ gitea_api_token.json.sha1 }} |  | ||||||
|             body: |  | ||||||
|               key: "{{ gitops_sshkey.public_key }}" |  | ||||||
|               read_only: false |  | ||||||
|               title: GitOps |  | ||||||
|  |  | ||||||
|         - name: Create organization(s) |  | ||||||
|           ansible.builtin.uri: |  | ||||||
|             url: https://git.{{ vapp['metacluster.fqdn'] }}/api/v1/orgs |  | ||||||
|             method: POST |  | ||||||
|             headers: |  | ||||||
|               Authorization: token {{ gitea_api_token.json.sha1 }} |  | ||||||
|             body: "{{ item }}" |  | ||||||
|           loop: |  | ||||||
|             - full_name: Meta-cluster |  | ||||||
|               description: Meta-cluster configuration items |  | ||||||
|               username: mc |  | ||||||
|               website: https://git.{{ vapp['metacluster.fqdn'] }}/mc |  | ||||||
|               location: '[...]' |  | ||||||
|               visibility: public |  | ||||||
|             - full_name: Workload-cluster |  | ||||||
|               description: Workload-cluster configuration items |  | ||||||
|               username: wl |  | ||||||
|               website: https://git.{{ vapp['metacluster.fqdn'] }}/wl |  | ||||||
|               location: '[...]' |  | ||||||
|               visibility: public |  | ||||||
|           loop_control: |  | ||||||
|             label: "{{ item.full_name }}" |  | ||||||
|  |  | ||||||
|         - name: Create repositories |  | ||||||
|           ansible.builtin.uri: |  | ||||||
|             url: https://git.{{ vapp['metacluster.fqdn'] }}/api/v1/orgs/{{ item.organization }}/repos |  | ||||||
|             method: POST |  | ||||||
|             headers: |  | ||||||
|               Authorization: token {{ gitea_api_token.json.sha1 }} |  | ||||||
|             body: "{{ item.body }}" |  | ||||||
|           loop: |  | ||||||
|             - organization: mc |  | ||||||
|               body: |  | ||||||
|                 name: GitOps.ClusterAPI |  | ||||||
|                 auto_init: true |  | ||||||
|                 default_branch: main |  | ||||||
|                 description: ClusterAPI manifests |  | ||||||
|             - organization: mc |  | ||||||
|               body: |  | ||||||
|                 name: GitOps.Config |  | ||||||
|                 # auto_init: true |  | ||||||
|                 # default_branch: main |  | ||||||
|                 description: GitOps manifests |  | ||||||
|             - organization: wl |  | ||||||
|               body: |  | ||||||
|                 name: GitOps.Config |  | ||||||
|                 auto_init: true |  | ||||||
|                 default_branch: main |  | ||||||
|                 description: GitOps manifests |  | ||||||
|             - organization: wl |  | ||||||
|               body: |  | ||||||
|                 name: ClusterAccess.Store |  | ||||||
|                 auto_init: true |  | ||||||
|                 default_branch: main |  | ||||||
|                 description: Kubeconfig files |  | ||||||
|           loop_control: |  | ||||||
|             label: "{{ item.organization ~ '/' ~ item.body.name }}" |  | ||||||
|  |  | ||||||
|         # - name: Rebase/Push source gitops repository |  | ||||||
|         #   ansible.builtin.shell: |  | ||||||
|         #     cmd: | |  | ||||||
|         #       git config --local http.sslVerify false |  | ||||||
|         #       git remote set-url origin https://administrator:{{ vapp['metacluster.password'] | urlencode }}@git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.Config.git |  | ||||||
|         #       git push |  | ||||||
|         #     chdir: /opt/metacluster/git-repositories/gitops |  | ||||||
|  |  | ||||||
|       when: (gitea_existing_config.json is undefined) or (gitea_existing_config.json.data | length == 0) |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,75 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install argo-cd chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: argo-cd |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/argo-cd |  | ||||||
|         release_namespace: argo-cd |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['argo-cd'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure argo-cd API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://gitops.{{ vapp['metacluster.fqdn'] }}/api/version |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.Version is defined |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|     - name: Generate argo-cd API token |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://gitops.{{ vapp['metacluster.fqdn'] }}/api/v1/session |  | ||||||
|         method: POST |  | ||||||
|         force_basic_auth: yes |  | ||||||
|         body: |  | ||||||
|           username: admin |  | ||||||
|           password: "{{ vapp['metacluster.password'] }}" |  | ||||||
|       register: argocd_api_token |  | ||||||
|  |  | ||||||
|     - name: Configure metacluster-gitops repository |  | ||||||
|       ansible.builtin.template: |  | ||||||
|         src: gitrepo.j2 |  | ||||||
|         dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|         owner: root |  | ||||||
|         group: root |  | ||||||
|         mode: 0600 |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           name: gitrepo-mc-gitopsconfig |  | ||||||
|           namespace: argo-cd |  | ||||||
|           url: https://git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.Config.git |  | ||||||
|       notify: |  | ||||||
|         - Apply manifests |  | ||||||
|  |  | ||||||
|     - name: Create applicationset |  | ||||||
|       ansible.builtin.template: |  | ||||||
|         src: applicationset.j2 |  | ||||||
|         dest: /var/lib/rancher/k3s/server/manifests/{{ _template.application.name }}-manifest.yaml |  | ||||||
|         owner: root |  | ||||||
|         group: root |  | ||||||
|         mode: 0600 |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           application: |  | ||||||
|             name: applicationset-metacluster |  | ||||||
|             namespace: argo-cd |  | ||||||
|           cluster: |  | ||||||
|             url: https://kubernetes.default.svc |  | ||||||
|           repository: |  | ||||||
|             url: https://git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.Config.git |  | ||||||
|             revision: main |  | ||||||
|       notify: |  | ||||||
|         - Apply manifests |  | ||||||
|  |  | ||||||
|     - name: Trigger handlers |  | ||||||
|       ansible.builtin.meta: flush_handlers |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| - name: Reconfigure traefik container for persistence |  | ||||||
|   ansible.builtin.blockinfile: |  | ||||||
|     path: /var/lib/rancher/k3s/server/manifests/traefik-config.yaml |  | ||||||
|     block: |2 |  | ||||||
|           deployment: |  | ||||||
|             initContainers: |  | ||||||
|               - name: volume-permissions |  | ||||||
|                 image: busybox:1 |  | ||||||
|                 command: ["sh", "-c", "touch /data/acme.json && chmod -Rv 600 /data/* && chown 65532:65532 /data/acme.json"] |  | ||||||
|                 volumeMounts: |  | ||||||
|                   - name: data |  | ||||||
|                     mountPath: /data |  | ||||||
|           persistence: |  | ||||||
|             enabled: true |  | ||||||
|     marker: '    # {mark} ANSIBLE MANAGED BLOCK [persistence]' |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Configure traefik dashboard ingress |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: ingressroute.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       name: traefik-dashboard |  | ||||||
|       namespace: kube-system |  | ||||||
|       spec: |2 |  | ||||||
|           entryPoints: |  | ||||||
|           - web |  | ||||||
|           - websecure |  | ||||||
|           routes: |  | ||||||
|           - kind: Rule |  | ||||||
|             match: Host(`ingress.{{ vapp['metacluster.fqdn'] }}`) |  | ||||||
|             services: |  | ||||||
|             - kind: TraefikService |  | ||||||
|               name: api@internal |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Trigger handlers |  | ||||||
|   ansible.builtin.meta: flush_handlers |  | ||||||
| @@ -1,100 +0,0 @@ | |||||||
| - name: Configure fallback name resolution |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /etc/hosts |  | ||||||
|     line: "{{ vapp['guestinfo.ipaddress'] }}  {{ item ~ '.' ~ vapp['metacluster.fqdn'] }}" |  | ||||||
|     state: present |  | ||||||
|   loop: |  | ||||||
|     # TODO: Make this list dynamic |  | ||||||
|     - ca |  | ||||||
|     - git |  | ||||||
|     - gitops |  | ||||||
|     - ingress |  | ||||||
|     - registry |  | ||||||
|     - storage |  | ||||||
|  |  | ||||||
| - name: Create step-ca config dictionary |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     stepconfig: "{{ { 'path': ansible_env.HOME ~ '/.step/config/values.yaml' } }}" |  | ||||||
|  |  | ||||||
| - name: Create step-ca target folder |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ stepconfig.path | dirname }}" |  | ||||||
|     state: directory |  | ||||||
|  |  | ||||||
| - name: Initialize tempfile |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: file |  | ||||||
|   register: stepca_password |  | ||||||
|  |  | ||||||
| - name: Store password in tempfile |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ stepca_password.path }}" |  | ||||||
|     content: "{{ vapp['metacluster.password'] }}" |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Generate step-ca helm chart values (including root CA certificate) |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       step ca init \ |  | ||||||
|         --helm \ |  | ||||||
|         --deployment-type=standalone \ |  | ||||||
|         --name=ca.{{ vapp['metacluster.fqdn'] }} \ |  | ||||||
|         --dns=ca.{{ vapp['metacluster.fqdn'] }} \ |  | ||||||
|         --dns=step-certificates.step-ca.svc.cluster.local \ |  | ||||||
|         --dns=127.0.0.1 \ |  | ||||||
|         --address=:9000 \ |  | ||||||
|         --provisioner=admin \ |  | ||||||
|         --acme \ |  | ||||||
|         --password-file={{ stepca_password.path }} | tee {{ stepconfig.path }} |  | ||||||
|     creates: "{{ stepconfig.path }}" |  | ||||||
|  |  | ||||||
| - name: Cleanup tempfile |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ stepca_password.path }}" |  | ||||||
|     state: absent |  | ||||||
|   when: stepca_password.path is defined |  | ||||||
|  |  | ||||||
| - name: Store root CA certificate |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /usr/local/share/ca-certificates/root_ca.crt |  | ||||||
|     content: "{{ (lookup('ansible.builtin.file', stepconfig.path) | from_yaml).inject.certificates.root_ca }}" |  | ||||||
|  |  | ||||||
| - name: Update certificate truststore |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: update-ca-certificates |  | ||||||
|  |  | ||||||
| - name: Extract container images (for idempotency purposes) |  | ||||||
|   ansible.builtin.unarchive: |  | ||||||
|     src: /opt/metacluster/container-images/image-tarballs.tgz |  | ||||||
|     dest: /opt/metacluster/container-images |  | ||||||
|     remote_src: no |  | ||||||
|   when: |  | ||||||
|     - lookup('ansible.builtin.fileglob', '/opt/metacluster/container-images/*.tgz') is match('.*image-tarballs.tgz') |  | ||||||
|  |  | ||||||
| - name: Get all stored fully qualified container image names |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       skopeo list-tags \ |  | ||||||
|         --insecure-policy \ |  | ||||||
|         docker-archive:./{{ item | basename }} | \ |  | ||||||
|       jq -r '.Tags[0]' |  | ||||||
|     chdir: /opt/metacluster/container-images |  | ||||||
|   register: registry_artifacts |  | ||||||
|   loop: "{{ query('ansible.builtin.fileglob', '/opt/metacluster/container-images/*.tar') | sort }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item | basename }}" |  | ||||||
|  |  | ||||||
| - name: Get source registries of all artifacts |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     source_registries: "{{ (source_registries | default([]) + [(item | split('/'))[0]]) | unique | sort }}" |  | ||||||
|   loop: "{{ registry_artifacts | json_query('results[*].stdout') | select | sort }}" |  | ||||||
|  |  | ||||||
| - name: Configure K3s node for private registry |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     dest: /etc/rancher/k3s/registries.yaml |  | ||||||
|     src: registries.j2 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       registries: "{{ source_registries }}" |  | ||||||
|       hv: |  | ||||||
|         fqdn: "{{ vapp['metacluster.fqdn'] }}" |  | ||||||
| @@ -1,91 +0,0 @@ | |||||||
| - name: Store custom configuration files |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ item.filename }}" |  | ||||||
|     content: "{{ item.content }}" |  | ||||||
|   loop: |  | ||||||
|     - filename: /etc/rancher/k3s/config.yaml |  | ||||||
|       content: | |  | ||||||
|         kubelet-arg: |  | ||||||
|           - "config=/etc/rancher/k3s/kubelet.config" |  | ||||||
|           - "image-gc-high-threshold=95" |  | ||||||
|     - filename: /etc/rancher/k3s/kubelet.config |  | ||||||
|       content: | |  | ||||||
|         apiVersion: kubelet.config.k8s.io/v1beta1 |  | ||||||
|         kind: KubeletConfiguration |  | ||||||
|  |  | ||||||
|         shutdownGracePeriod: 180s |  | ||||||
|         shtudownGracePeriodCriticalPods: 60s |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.filename }}" |  | ||||||
|  |  | ||||||
| - name: Gather service facts |  | ||||||
|   ansible.builtin.service_facts: |  | ||||||
|     # Module requires no attributes |  | ||||||
|  |  | ||||||
| - name: Install K3s |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: ./install.sh |  | ||||||
|     chdir: /opt/metacluster/k3s |  | ||||||
|   environment: |  | ||||||
|     INSTALL_K3S_SKIP_DOWNLOAD: 'true' |  | ||||||
|     INSTALL_K3S_EXEC: "server --cluster-init --token {{ vapp['metacluster.token'] | trim }} --tls-san {{ vapp['metacluster.vip'] }} --disable local-storage --config /etc/rancher/k3s/config.yaml" |  | ||||||
|   when: ansible_facts.services['k3s.service'] is undefined |  | ||||||
|  |  | ||||||
| - name: Ensure API availability |  | ||||||
|   ansible.builtin.uri: |  | ||||||
|     url: https://{{ vapp['guestinfo.ipaddress'] }}:6443/livez?verbose |  | ||||||
|     method: GET |  | ||||||
|     validate_certs: no |  | ||||||
|     status_code: [200, 401] |  | ||||||
|   register: api_readycheck |  | ||||||
|   until: api_readycheck.json.apiVersion is defined |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
|  |  | ||||||
| - name: Install tab-completion |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: |- |  | ||||||
|       {{ item }} completion bash > /etc/bash_completion.d/{{ item }} |  | ||||||
|     creates: /etc/bash_completion.d/{{ item }} |  | ||||||
|   loop: |  | ||||||
|     - kubectl |  | ||||||
|     - helm |  | ||||||
|     - step |  | ||||||
|  |  | ||||||
| - name: Create kubeconfig dictionary |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     kubeconfig: "{{ { 'path': ansible_env.HOME ~ '/.kube/config' } }}" |  | ||||||
|  |  | ||||||
| - name: Create kubeconfig target folder |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ kubeconfig.path | dirname }}" |  | ||||||
|     state: directory |  | ||||||
|  |  | ||||||
| - name: Retrieve kubeconfig |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: kubectl config view --raw |  | ||||||
|   register: kubectl_config |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Store kubeconfig in tempfile |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ kubeconfig.path }}" |  | ||||||
|     content: "{{ kubectl_config.stdout }}" |  | ||||||
|     mode: 0600 |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Add label to node object |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     name: "{{ ansible_facts.nodename | lower }}" |  | ||||||
|     kind: Node |  | ||||||
|     state: patched |  | ||||||
|     definition: |  | ||||||
|       metadata: |  | ||||||
|         labels: |  | ||||||
|           ova.airgappedk8s/moref_id: "{{ moref_id }}" |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   register: k8snode_patch |  | ||||||
|   until: |  | ||||||
|     - k8snode_patch.result.metadata.labels['ova.airgappedk8s/moref_id'] is defined |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| - import_tasks: init.yml |  | ||||||
| - import_tasks: k3s.yml |  | ||||||
| - import_tasks: assets.yml |  | ||||||
| - import_tasks: virtualip.yml |  | ||||||
| - import_tasks: metadata.yml |  | ||||||
| - import_tasks: storage.yml |  | ||||||
| - import_tasks: ingress.yml |  | ||||||
| - import_tasks: certauthority.yml |  | ||||||
| - import_tasks: registry.yml |  | ||||||
| - import_tasks: git.yml |  | ||||||
| - import_tasks: gitops.yml |  | ||||||
| - import_tasks: authentication.yml |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| - block: |  | ||||||
|     - name: Aggregate manifest-component versions into dictionary |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         manifest_versions: "{{ manifest_versions | default([]) + [ item | combine( {'type': 'manifest', 'id': index } ) ] }}" |  | ||||||
|       loop: |  | ||||||
|         - name: cluster-api |  | ||||||
|           versions: |  | ||||||
|             management: |  | ||||||
|               base: "{{ components.clusterapi.management.version.base }}" |  | ||||||
|               cert_manager: "{{ components.clusterapi.management.version.cert_manager }}" |  | ||||||
|               infrastructure_vsphere: "{{ components.clusterapi.management.version.infrastructure_vsphere }}" |  | ||||||
|               ipam_incluster: "{{ components.clusterapi.management.version.ipam_incluster }}" |  | ||||||
|               cpi_vsphere: "{{ components.clusterapi.management.version.cpi_vsphere }}" |  | ||||||
|             workload: |  | ||||||
|               calico: "{{ components.clusterapi.workload.version.calico }}" |  | ||||||
|               k8s: "{{ components.clusterapi.workload.version.k8s }}" |  | ||||||
|         - name: kube-vip |  | ||||||
|           version: "{{ components.kubevip.version }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.name }}" |  | ||||||
|         index_var: index |  | ||||||
|  |  | ||||||
|     - name: Install json-server chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: json-server |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/json-server |  | ||||||
|         release_namespace: json-server |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: | |  | ||||||
|           {{ |  | ||||||
|             components['json-server'].chart_values | |  | ||||||
|             combine( |  | ||||||
|               { 'jsonServer': { 'seedData': { 'configInline': ( |  | ||||||
|                 { 'appliance': { "version": appliance.version }, 'components': manifest_versions, 'healthz': { 'status': 'running' } } |  | ||||||
|               ) | to_json } } } |  | ||||||
|             ) |  | ||||||
|           }} |  | ||||||
|  |  | ||||||
|     - name: Ensure json-server API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://version.{{ vapp['metacluster.fqdn'] }}/healthz |  | ||||||
|         method: GET |  | ||||||
|         # This mock REST API -ironically- does not support json encoded body argument |  | ||||||
|         body_format: raw |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.status is defined |  | ||||||
|         - api_readycheck.json.status == 'running' |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Install harbor chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: harbor |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/harbor |  | ||||||
|         release_namespace: harbor |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['harbor'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure harbor API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://registry.{{ vapp['metacluster.fqdn'] }}/api/v2.0/health |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.status is defined |  | ||||||
|         - api_readycheck.json.status == 'healthy' |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|     - name: Push images to registry |  | ||||||
|       ansible.builtin.shell: |  | ||||||
|         cmd: >- |  | ||||||
|           skopeo copy \ |  | ||||||
|             --insecure-policy \ |  | ||||||
|             --dest-tls-verify=false \ |  | ||||||
|             --dest-creds admin:{{ vapp['metacluster.password'] }} \ |  | ||||||
|             docker-archive:./{{ item | basename }} \ |  | ||||||
|             docker://registry.{{ vapp['metacluster.fqdn'] }}/library/$( \ |  | ||||||
|               skopeo list-tags \ |  | ||||||
|                 --insecure-policy \ |  | ||||||
|                 docker-archive:./{{ item | basename }} | \ |  | ||||||
|               jq -r '.Tags[0]') |  | ||||||
|         chdir: /opt/metacluster/container-images/ |  | ||||||
|       register: push_result |  | ||||||
|       loop: "{{ query('ansible.builtin.fileglob', '/opt/metacluster/container-images/*.tar') | sort }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item | basename }}" |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|       until: push_result is not failed |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201, 401] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| - block: |  | ||||||
|     - name: Install longhorn chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: longhorn |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/longhorn |  | ||||||
|         release_namespace: longhorn-system |  | ||||||
|         create_namespace: true |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['longhorn'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure longhorn API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://storage.{{ vapp['metacluster.fqdn'] }}/v1 |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck is not failed |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| - name: Generate kube-vip manifest |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       ctr run --rm --net-host ghcr.io/kube-vip/kube-vip:{{ components.kubevip.version }} vip \ |  | ||||||
|         /kube-vip manifest daemonset \ |  | ||||||
|           --interface eth0 \ |  | ||||||
|           --address {{ vapp['metacluster.vip'] }} \ |  | ||||||
|           --inCluster \ |  | ||||||
|           --taint \ |  | ||||||
|           --controlplane \ |  | ||||||
|           --services \ |  | ||||||
|           --arp \ |  | ||||||
|           --leaderElection |  | ||||||
|   register: kubevip_manifest |  | ||||||
|  |  | ||||||
| - name: Inject manifests |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/kubevip-manifest.yaml |  | ||||||
|     content: | |  | ||||||
|       {{ lookup('ansible.builtin.file', '/opt/metacluster/kube-vip/rbac.yaml') }} |  | ||||||
|       --- |  | ||||||
|       {{ kubevip_manifest.stdout | replace('imagePullPolicy: Always', 'imagePullPolicy: IfNotPresent') }} |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Trigger handlers |  | ||||||
|   ansible.builtin.meta: flush_handlers |  | ||||||
| @@ -1,25 +0,0 @@ | |||||||
| - name: Check for expected vApp properties |  | ||||||
|   ansible.builtin.assert: |  | ||||||
|     that: |  | ||||||
|       - vapp[item] is defined |  | ||||||
|       - (vapp[item] | length) > 0 |  | ||||||
|     quiet: true |  | ||||||
|   loop: |  | ||||||
|     - deployment.type |  | ||||||
|     - guestinfo.dnsserver |  | ||||||
|     - guestinfo.gateway |  | ||||||
|     - guestinfo.hostname |  | ||||||
|     - guestinfo.ipaddress |  | ||||||
|     - guestinfo.prefixlength |  | ||||||
|     - guestinfo.rootsshkey |  | ||||||
|     - hv.fqdn |  | ||||||
|     - hv.password |  | ||||||
|     - hv.username |  | ||||||
|     - ippool.endip |  | ||||||
|     - ippool.startip |  | ||||||
|     - metacluster.fqdn |  | ||||||
|     - metacluster.password |  | ||||||
|     - metacluster.token |  | ||||||
|     - metacluster.vip |  | ||||||
|     - workloadcluster.name |  | ||||||
|     - workloadcluster.vip |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| - name: Initialize tempfolder |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: directory |  | ||||||
|   register: pinniped_kubeconfig |  | ||||||
|  |  | ||||||
| - name: Pull existing repository |  | ||||||
|   ansible.builtin.git: |  | ||||||
|     repo: https://git.{{ vapp['metacluster.fqdn'] }}/wl/ClusterAccess.Store.git |  | ||||||
|     dest: "{{ pinniped_kubeconfig.path }}" |  | ||||||
|     version: main |  | ||||||
|  |  | ||||||
| - name: Generate kubeconfig |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: pinniped get kubeconfig --kubeconfig {{ capi_kubeconfig.path }} |  | ||||||
|   register: pinniped_config |  | ||||||
|   until: |  | ||||||
|     - pinniped_config is not failed |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|  |  | ||||||
| - name: Store kubeconfig in tempfile |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ pinniped_kubeconfig.path }}/kubeconfig" |  | ||||||
|     content: "{{ pinniped_config.stdout }}" |  | ||||||
|     mode: 0600 |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Push git repository |  | ||||||
|   lvrfrc87.git_acp.git_acp: |  | ||||||
|     path: "{{ pinniped_kubeconfig.path }}" |  | ||||||
|     branch: main |  | ||||||
|     comment: "Upload kubeconfig files" |  | ||||||
|     add: |  | ||||||
|       - . |  | ||||||
|     url: https://administrator:{{ vapp['metacluster.password'] | urlencode }}@git.{{ vapp['metacluster.fqdn'] }}/wl/ClusterAccess.Store.git |  | ||||||
|   environment: |  | ||||||
|     GIT_AUTHOR_NAME: administrator |  | ||||||
|     GIT_AUTHOR_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
|     GIT_COMMITTER_NAME: administrator |  | ||||||
|     GIT_COMMITTER_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
| @@ -1,328 +0,0 @@ | |||||||
| - block: |  | ||||||
|   # Below tasks circumvent usernames with `<domain>\<username>` format, which causes CAPV to |  | ||||||
|   # incorrectly interpret the backslash (despite automatic escaping) as an escape sequence. |  | ||||||
|   # `vcenter_session.user` will instead contain the username in `<username>@<domain>` format. |  | ||||||
|  |  | ||||||
|     - name: Generate vCenter API token |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://{{ vapp['hv.fqdn'] }}/api/session |  | ||||||
|         method: POST |  | ||||||
|         headers: |  | ||||||
|           Authorization: Basic {{ ( vapp['hv.username'] ~ ':' ~ vapp['hv.password'] ) | b64encode }} |  | ||||||
|       register: vcenterapi_token |  | ||||||
|  |  | ||||||
|     - name: Retrieve vCenter API session details |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://{{ vapp['hv.fqdn'] }}/api/session |  | ||||||
|         method: GET |  | ||||||
|         headers: |  | ||||||
|           vmware-api-session-id: "{{ vcenterapi_token.json }}" |  | ||||||
|       register: vcenter_session |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
|  |  | ||||||
| - name: Configure clusterctl |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: clusterctl.j2 |  | ||||||
|     dest: /opt/metacluster/cluster-api/clusterctl.yaml |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       version: |  | ||||||
|         base: "{{ components.clusterapi.management.version.base }}" |  | ||||||
|         cert_manager: "{{ components.clusterapi.management.version.cert_manager }}" |  | ||||||
|         infrastructure_vsphere: "{{ components.clusterapi.management.version.infrastructure_vsphere }}" |  | ||||||
|         ipam_incluster: "{{ components.clusterapi.management.version.ipam_incluster }}" |  | ||||||
|       hv: |  | ||||||
|         fqdn: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|         tlsthumbprint: "{{ tls_thumbprint.stdout }}" |  | ||||||
|         username: "{{ vcenter_session.json.user }}" |  | ||||||
|         password: "{{ vapp['hv.password'] }}" |  | ||||||
|         datacenter: "{{ vcenter_info.datacenter }}" |  | ||||||
|         datastore: "{{ vcenter_info.datastore }}" |  | ||||||
|         network: "{{ vcenter_info.network }}" |  | ||||||
|         resourcepool: "{{ vcenter_info.resourcepool }}" |  | ||||||
|         folder: "{{ vcenter_info.folder }}" |  | ||||||
|       cluster: |  | ||||||
|         nodetemplate: "{{ nodetemplate_inventorypath }}" |  | ||||||
|         publickey: "{{ vapp['guestinfo.rootsshkey'] }}" |  | ||||||
|         version: "{{ components.clusterapi.workload.version.k8s }}" |  | ||||||
|         vip: "{{ vapp['workloadcluster.vip'] }}" |  | ||||||
|  |  | ||||||
| - name: Generate cluster-template kustomization manifest |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: kustomization.cluster-template.j2 |  | ||||||
|     dest: /opt/metacluster/cluster-api/infrastructure-vsphere/{{ components.clusterapi.management.version.infrastructure_vsphere }}/kustomization.yaml |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       network: |  | ||||||
|         fqdn: "{{ vapp['metacluster.fqdn'] }}" |  | ||||||
|         dnsserver: "{{ vapp['guestinfo.dnsserver'] }}" |  | ||||||
|       nodesize: |  | ||||||
|         cpu: "{{ config.clusterapi.size_matrix[ vapp['workloadcluster.nodesize'] ].cpu }}" |  | ||||||
|         memory: "{{ config.clusterapi.size_matrix[ vapp['workloadcluster.nodesize'] ].memory }}" |  | ||||||
|       rootca: "{{ stepca_cm_certs.resources[0].data['root_ca.crt'] }}" |  | ||||||
|       runcmds: |  | ||||||
|         - update-ca-certificates |  | ||||||
|       registries: "{{ source_registries }}" |  | ||||||
|  |  | ||||||
| - name: Store custom cluster-template |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /opt/metacluster/cluster-api/custom-cluster-template.yaml |  | ||||||
|     content: "{{ lookup('kubernetes.core.kustomize', dir='/opt/metacluster/cluster-api/infrastructure-vsphere/' ~ components.clusterapi.management.version.infrastructure_vsphere ) }}" |  | ||||||
|  |  | ||||||
| - name: Initialize Cluster API management cluster |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       clusterctl init \ |  | ||||||
|         -v5 \ |  | ||||||
|         --infrastructure vsphere:{{ components.clusterapi.management.version.infrastructure_vsphere }} \ |  | ||||||
|         --ipam in-cluster:{{ components.clusterapi.management.version.ipam_incluster }} \ |  | ||||||
|         --config ./clusterctl.yaml \ |  | ||||||
|         --kubeconfig {{ kubeconfig.path }} |  | ||||||
|     chdir: /opt/metacluster/cluster-api |  | ||||||
|  |  | ||||||
| - name: Initialize tempfolder |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: directory |  | ||||||
|   register: capi_clustermanifest |  | ||||||
|  |  | ||||||
| - name: Pull existing repository |  | ||||||
|   ansible.builtin.git: |  | ||||||
|     repo: https://git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.ClusterAPI.git |  | ||||||
|     dest: "{{ capi_clustermanifest.path }}" |  | ||||||
|     version: main |  | ||||||
|  |  | ||||||
| - name: Generate Cluster API provider manifests |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       clusterctl generate provider \ |  | ||||||
|         -v5 \ |  | ||||||
|         --{{ item.type }} {{ item.name }}:{{ item.version }} \ |  | ||||||
|         --config ./clusterctl.yaml > {{ capi_clustermanifest.path }}/provider-{{ item.name }}.yaml |  | ||||||
|     chdir: /opt/metacluster/cluster-api |  | ||||||
|   loop: |  | ||||||
|     - type: infrastructure |  | ||||||
|       name: vsphere |  | ||||||
|       version: "{{ components.clusterapi.management.version.infrastructure_vsphere }}" |  | ||||||
|     - type: ipam |  | ||||||
|       name: in-cluster |  | ||||||
|       version: "{{ components.clusterapi.management.version.ipam_incluster }}" |  | ||||||
|  |  | ||||||
| - name: Split cluster API provider manifests into separate files |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       awk 'BEGINFILE {print "---"}{print}' {{ capi_clustermanifest.path }}/provider-*.yaml | |  | ||||||
|       kubectl slice \ |  | ||||||
|         -o {{ capi_clustermanifest.path }}/providers |  | ||||||
|  |  | ||||||
| - name: Ensure controller availability |  | ||||||
|   kubernetes.core.k8s_info: |  | ||||||
|     kind: Deployment |  | ||||||
|     name: "{{ item.name }}" |  | ||||||
|     namespace: "{{ item.namespace }}" |  | ||||||
|     wait: true |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   loop: |  | ||||||
|     - name: caip-in-cluster-controller-manager |  | ||||||
|       namespace: caip-in-cluster-system |  | ||||||
|     - name: capi-controller-manager |  | ||||||
|       namespace: capi-system |  | ||||||
|     - name: capv-controller-manager |  | ||||||
|       namespace: capv-system |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.name }}" |  | ||||||
|  |  | ||||||
| - name: Parse vApp for workload cluster sizing |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     clustersize: >- |  | ||||||
|       {{ { |  | ||||||
|         'controlplane': vapp['deployment.type'] | regex_findall('^cp(\d)+') | first, |  | ||||||
|         'worker': vapp['deployment.type'] | regex_findall('w(\d)+') | first, |  | ||||||
|         'workerstorage': vapp['deployment.type'] | regex_findall('ws(\d)+$') | first |  | ||||||
|       } }} |  | ||||||
|  |  | ||||||
| - name: Generate workload cluster manifest |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       clusterctl generate cluster \ |  | ||||||
|         {{ vapp['workloadcluster.name'] | lower }} \ |  | ||||||
|         --control-plane-machine-count {{ clustersize.controlplane }} \ |  | ||||||
|         --worker-machine-count {{ clustersize.worker }} \ |  | ||||||
|         --from ./custom-cluster-template.yaml \ |  | ||||||
|         --config ./clusterctl.yaml \ |  | ||||||
|         --kubeconfig {{ kubeconfig.path }} |  | ||||||
|     chdir: /opt/metacluster/cluster-api |  | ||||||
|   register: clusterctl_newcluster |  | ||||||
|  |  | ||||||
| - name: Save workload cluster manifest |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ capi_clustermanifest.path }}/new-cluster.yaml" |  | ||||||
|     content: "{{ clusterctl_newcluster.stdout }}" |  | ||||||
|  |  | ||||||
| - name: Split workload cluster manifest into separate files |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       kubectl slice \ |  | ||||||
|         -f {{ capi_clustermanifest.path }}/new-cluster.yaml \ |  | ||||||
|         -o {{ capi_clustermanifest.path }}/downstream-cluster |  | ||||||
|  |  | ||||||
| - name: Generate nodepool kustomization manifest |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: kustomization.nodepool.j2 |  | ||||||
|     dest: "{{ capi_clustermanifest.path }}/kustomization.yaml" |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       cluster: |  | ||||||
|         name: "{{ vapp['workloadcluster.name'] }}" |  | ||||||
|       nodepool: |  | ||||||
|         size: "{{ clustersize.workerstorage }}" |  | ||||||
|         additionaldisk: "{{ vapp['workloadcluster.additionaldisk'] }}" |  | ||||||
|  |  | ||||||
| - name: Store nodepool manifest |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ capi_clustermanifest.path }}/nodepool-worker-storage.yaml" |  | ||||||
|     content: "{{ lookup('kubernetes.core.kustomize', dir=capi_clustermanifest.path) }}" |  | ||||||
|  |  | ||||||
| - name: Split nodepool manifest into separate files |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       kubectl slice \ |  | ||||||
|         -f {{ capi_clustermanifest.path }}/nodepool-worker-storage.yaml \ |  | ||||||
|         -o {{ capi_clustermanifest.path }}/downstream-cluster |  | ||||||
|  |  | ||||||
| - name: Create in-cluster IpPool |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: ippool.j2 |  | ||||||
|     dest: "{{ capi_clustermanifest.path }}/downstream-cluster/inclusterippool-{{ _template.cluster.name }}.yml" |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       cluster: |  | ||||||
|         name: "{{ vapp['workloadcluster.name'] | lower }}" |  | ||||||
|         namespace: default |  | ||||||
|         network: |  | ||||||
|           startip: "{{ vapp['ippool.startip'] }}" |  | ||||||
|           endip: "{{ vapp['ippool.endip'] }}" |  | ||||||
|           prefix: "{{ vapp['guestinfo.prefixlength'] }}" |  | ||||||
|           gateway: "{{ vapp['guestinfo.gateway'] }}" |  | ||||||
|  |  | ||||||
| - name: Push git repository |  | ||||||
|   lvrfrc87.git_acp.git_acp: |  | ||||||
|     path: "{{ capi_clustermanifest.path }}" |  | ||||||
|     branch: main |  | ||||||
|     comment: "Upload manifests" |  | ||||||
|     add: |  | ||||||
|       - ./downstream-cluster |  | ||||||
|       - ./providers |  | ||||||
|     clean: untracked |  | ||||||
|     url: https://administrator:{{ vapp['metacluster.password'] | urlencode }}@git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.ClusterAPI.git |  | ||||||
|   environment: |  | ||||||
|     GIT_AUTHOR_NAME: administrator |  | ||||||
|     GIT_AUTHOR_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
|     GIT_COMMITTER_NAME: administrator |  | ||||||
|     GIT_COMMITTER_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
|  |  | ||||||
| # - name: Cleanup tempfolder |  | ||||||
| #   ansible.builtin.file: |  | ||||||
| #     path: "{{ capi_clustermanifest.path }}" |  | ||||||
| #     state: absent |  | ||||||
| #   when: capi_clustermanifest.path is defined |  | ||||||
|  |  | ||||||
| - name: Configure Cluster API repository |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: gitrepo.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       name: gitrepo-mc-gitopsclusterapi |  | ||||||
|       namespace: argo-cd |  | ||||||
|       url: https://git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.ClusterAPI.git |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: WORKAROUND - Wait for ingress ACME requests to complete |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       openssl s_client -connect registry.{{ vapp['metacluster.fqdn'] }}:443 -servername registry.{{ vapp['metacluster.fqdn'] }} 2>/dev/null </dev/null | \ |  | ||||||
|         openssl x509 -noout -subject | \ |  | ||||||
|       grep 'subject=CN = registry.{{ vapp['metacluster.fqdn'] }}' |  | ||||||
|   register: certificate_subject |  | ||||||
|   until: certificate_subject is not failed |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
|  |  | ||||||
| - name: Create application |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: application.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ _template.application.name }}-manifest.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       application: |  | ||||||
|         name: application-clusterapi-workloadcluster |  | ||||||
|         namespace: argo-cd |  | ||||||
|       cluster: |  | ||||||
|         name: https://kubernetes.default.svc |  | ||||||
|         namespace: default |  | ||||||
|       repository: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/mc/GitOps.ClusterAPI.git |  | ||||||
|         path: downstream-cluster |  | ||||||
|         revision: main |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Trigger handlers |  | ||||||
|   ansible.builtin.meta: flush_handlers |  | ||||||
|  |  | ||||||
| - name: Wait for cluster to be available |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       kubectl wait clusters.cluster.x-k8s.io/{{ vapp['workloadcluster.name'] | lower }} \ |  | ||||||
|         --for=condition=Ready \ |  | ||||||
|         --timeout 0s |  | ||||||
|   register: cluster_readycheck |  | ||||||
|   until: cluster_readycheck is succeeded |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
| - name: Initialize tempfile |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: file |  | ||||||
|   register: capi_kubeconfig |  | ||||||
|  |  | ||||||
| - name: Retrieve kubeconfig |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       clusterctl get kubeconfig \ |  | ||||||
|         {{ vapp['workloadcluster.name'] | lower }} \ |  | ||||||
|         --kubeconfig {{ kubeconfig.path }} |  | ||||||
|   register: capi_kubectl_config |  | ||||||
|  |  | ||||||
| - name: Store kubeconfig in tempfile |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ capi_kubeconfig.path }}" |  | ||||||
|     content: "{{ capi_kubectl_config.stdout }}" |  | ||||||
|     mode: 0600 |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| # TODO: move to git repo |  | ||||||
| - name: Apply cni plugin manifest |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     definition: | |  | ||||||
|       {{ |  | ||||||
|         lookup('ansible.builtin.file', '/opt/metacluster/cluster-api/cni-calico/' ~ components.clusterapi.workload.version.calico ~ '/calico.yaml') | |  | ||||||
|           regex_replace('# - name: CALICO_IPV4POOL_CIDR', '- name: CALICO_IPV4POOL_CIDR') | |  | ||||||
|           regex_replace('#   value: "192.168.0.0/16"',    '  value: "172.30.0.0/16"') |  | ||||||
|       }} |  | ||||||
|     state: present |  | ||||||
|     wait: true |  | ||||||
|     kubeconfig: "{{ capi_kubeconfig.path }}" |  | ||||||
| # TODO: move to git repo |  | ||||||
| @@ -1,132 +0,0 @@ | |||||||
| - name: Aggregate helm charts from filesystem |  | ||||||
|   ansible.builtin.find: |  | ||||||
|     path: /opt/workloadcluster/helm-charts |  | ||||||
|     file_type: directory |  | ||||||
|     recurse: false |  | ||||||
|   register: helm_charts |  | ||||||
|  |  | ||||||
| - name: Pull existing repository |  | ||||||
|   ansible.builtin.git: |  | ||||||
|     repo: https://git.{{ vapp['metacluster.fqdn'] }}/wl/GitOps.Config.git |  | ||||||
|     dest: /opt/workloadcluster/git-repositories/gitops |  | ||||||
|     version: main |  | ||||||
|  |  | ||||||
| - name: Create folder structure within new git-repository |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item }}" |  | ||||||
|     state: directory |  | ||||||
|   loop: |  | ||||||
|     - /opt/workloadcluster/git-repositories/gitops/charts |  | ||||||
|     - /opt/workloadcluster/git-repositories/gitops/values |  | ||||||
|  |  | ||||||
| - name: Create hard-links to populate new git-repository |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       cp -lr {{ item.path }}/ /opt/workloadcluster/git-repositories/gitops/charts |  | ||||||
|   loop: "{{ helm_charts.files }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.path | basename }}" |  | ||||||
|  |  | ||||||
| - name: Write custom manifests to respective chart templates store |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: "{{ src }}" |  | ||||||
|     dest: /opt/workloadcluster/git-repositories/gitops/charts/{{ manifest.value.namespace }}/{{ manifest.key }}/templates/{{ (src | split('.'))[0] ~ '-' ~ _template.name ~ '.yaml' }} |  | ||||||
|   vars: |  | ||||||
|     manifest: "{{ item.0 }}" |  | ||||||
|     src: "{{ item.1.src }}" |  | ||||||
|     _template: "{{ item.1._template }}" |  | ||||||
|   loop: "{{ query('ansible.builtin.subelements', query('ansible.builtin.dict', downstream_components), 'value.extra_manifests') }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ (src | split('.'))[0] ~ '-' ~ _template.name }}" |  | ||||||
|  |  | ||||||
| - name: Create subfolders |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /opt/workloadcluster/git-repositories/gitops/values/{{ item.key }} |  | ||||||
|     state: directory |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', downstream_components) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
| - name: Write chart values to file |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /opt/workloadcluster/git-repositories/gitops/values/{{ item.key }}/values.yaml |  | ||||||
|     content: "{{ item.value.chart_values | default('# Empty') | to_nice_yaml(indent=2, width=4096) }}" |  | ||||||
|   loop: "{{ query('ansible.builtin.dict', downstream_components) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.key }}" |  | ||||||
|  |  | ||||||
| - name: Push git repository |  | ||||||
|   lvrfrc87.git_acp.git_acp: |  | ||||||
|     path: /opt/workloadcluster/git-repositories/gitops |  | ||||||
|     branch: main |  | ||||||
|     comment: "Upload charts" |  | ||||||
|     add: |  | ||||||
|       - . |  | ||||||
|     url: https://administrator:{{ vapp['metacluster.password'] | urlencode }}@git.{{ vapp['metacluster.fqdn'] }}/wl/GitOps.Config.git |  | ||||||
|   environment: |  | ||||||
|     GIT_AUTHOR_NAME: administrator |  | ||||||
|     GIT_AUTHOR_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
|     GIT_COMMITTER_NAME: administrator |  | ||||||
|     GIT_COMMITTER_EMAIL: administrator@{{ vapp['metacluster.fqdn'] }} |  | ||||||
|  |  | ||||||
| - name: Retrieve workload-cluster kubeconfig |  | ||||||
|   kubernetes.core.k8s_info: |  | ||||||
|     kind: Secret |  | ||||||
|     name: "{{ vapp['workloadcluster.name'] }}-kubeconfig" |  | ||||||
|     namespace: default |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   register: secret_workloadcluster_kubeconfig |  | ||||||
|  |  | ||||||
| - name: Register workload-cluster in argo-cd |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     template: cluster.j2 |  | ||||||
|     state: present |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       cluster: |  | ||||||
|         name: "{{ vapp['workloadcluster.name'] | lower }}" |  | ||||||
|         secret: argocd-cluster-{{ vapp['workloadcluster.name'] | lower }} |  | ||||||
|         url: https://{{ vapp['workloadcluster.vip'] }}:6443 |  | ||||||
|       kubeconfig: |  | ||||||
|         ca: "{{ (secret_workloadcluster_kubeconfig.resources[0].data.value | b64decode | from_yaml).clusters[0].cluster['certificate-authority-data'] }}" |  | ||||||
|         certificate: "{{ (secret_workloadcluster_kubeconfig.resources[0].data.value | b64decode | from_yaml).users[0].user['client-certificate-data'] }}" |  | ||||||
|         key: "{{ (secret_workloadcluster_kubeconfig.resources[0].data.value | b64decode | from_yaml).users[0].user['client-key-data'] }}" |  | ||||||
|  |  | ||||||
| - name: Configure workload-cluster GitOps repository |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: gitrepo.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       name: gitrepo-wl-gitopsconfig |  | ||||||
|       namespace: argo-cd |  | ||||||
|       url: https://git.{{ vapp['metacluster.fqdn'] }}/wl/GitOps.Config.git |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Create applicationset |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: applicationset.j2 |  | ||||||
|     dest: /var/lib/rancher/k3s/server/manifests/{{ _template.application.name }}-manifest.yaml |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: 0600 |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       application: |  | ||||||
|         name: applicationset-workloadcluster |  | ||||||
|         namespace: argo-cd |  | ||||||
|       cluster: |  | ||||||
|         url: https://{{ vapp['workloadcluster.vip'] }}:6443 |  | ||||||
|       repository: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/wl/GitOps.Config.git |  | ||||||
|         revision: main |  | ||||||
|   notify: |  | ||||||
|     - Apply manifests |  | ||||||
|  |  | ||||||
| - name: Trigger handlers |  | ||||||
|   ansible.builtin.meta: flush_handlers |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| - 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 }}" |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| - import_tasks: hypervisor.yml |  | ||||||
| - import_tasks: registry.yml |  | ||||||
| - import_tasks: nodetemplates.yml |  | ||||||
|  |  | ||||||
| - block: |  | ||||||
|  |  | ||||||
|     - import_tasks: clusterapi.yml |  | ||||||
|     - import_tasks: gitops.yml |  | ||||||
|     - import_tasks: authentication.yml |  | ||||||
|  |  | ||||||
|   when: |  | ||||||
|     - vapp['deployment.type'] != 'core' |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Check for existing template on hypervisor |  | ||||||
|       community.vmware.vmware_guest_info: |  | ||||||
|         name: "{{ (filename | basename | split('.'))[:-1] | join('.') }}" |  | ||||||
|       register: existing_ova |  | ||||||
|       ignore_errors: yes |  | ||||||
|  |  | ||||||
|     - name: Store inventory path of existing template |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         nodetemplate_inventorypath: "{{ existing_ova.instance.hw_folder ~ '/' ~ existing_ova.instance.hw_name }}" |  | ||||||
|       when: existing_ova is not failed |  | ||||||
|  |  | ||||||
|     - block: |  | ||||||
|  |  | ||||||
|         - name: Parse OVA file for network mappings |  | ||||||
|           ansible.builtin.shell: |  | ||||||
|             cmd: govc import.spec -json {{ filename }} |  | ||||||
|           environment: |  | ||||||
|             GOVC_INSECURE: '1' |  | ||||||
|             GOVC_URL: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|             GOVC_USERNAME: "{{ vapp['hv.username'] }}" |  | ||||||
|             GOVC_PASSWORD: "{{ vapp['hv.password'] }}" |  | ||||||
|           register: ova_spec |  | ||||||
|  |  | ||||||
|         - name: Deploy OVA template on hypervisor |  | ||||||
|           community.vmware.vmware_deploy_ovf: |  | ||||||
|             cluster: "{{ vcenter_info.cluster }}" |  | ||||||
|             datastore: "{{ vcenter_info.datastore }}" |  | ||||||
|             name: "{{ (filename | basename | split('.'))[:-1] | join('.') }}" |  | ||||||
|             networks: "{u'{{ ova_spec.stdout | from_json | json_query('NetworkMapping[0].Name') }}':u'{{ vcenter_info.network }}'}" |  | ||||||
|             allow_duplicates: no |  | ||||||
|             power_on: false |  | ||||||
|             ovf: "{{ filename }}" |  | ||||||
|           register: ova_deploy |  | ||||||
|  |  | ||||||
|         - name: Add additional placeholder disk |  | ||||||
|           community.vmware.vmware_guest_disk: |  | ||||||
|             name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|             disk: |  | ||||||
|               - size: 1Mb |  | ||||||
|                 scsi_controller: 1 |  | ||||||
|                 scsi_type: paravirtual |  | ||||||
|                 unit_number: 0 |  | ||||||
|  |  | ||||||
|         # Disabled to allow disks to be resized; at the cost of cloning speed |  | ||||||
|         # - name: Create snapshot on deployed VM |  | ||||||
|         #   community.vmware.vmware_guest_snapshot: |  | ||||||
|         #     name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|         #     state: present |  | ||||||
|         #     snapshot_name: "{{ ansible_date_time.iso8601_basic_short }}-base" |  | ||||||
|  |  | ||||||
|         - name: Mark deployed VM as templates |  | ||||||
|           community.vmware.vmware_guest: |  | ||||||
|             name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|             is_template: yes |  | ||||||
|  |  | ||||||
|         - name: Store inventory path of deployed template |  | ||||||
|           ansible.builtin.set_fact: |  | ||||||
|             nodetemplate_inventorypath: "{{ ova_deploy.instance.hw_folder ~ '/' ~ ova_deploy.instance.hw_name }}" |  | ||||||
|  |  | ||||||
|       when: existing_ova is failed |  | ||||||
|  |  | ||||||
|   vars: |  | ||||||
|     filename: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | first }}" |  | ||||||
|   module_defaults: |  | ||||||
|     group/vmware: |  | ||||||
|       hostname: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|       validate_certs: no |  | ||||||
|       username: "{{ vapp['hv.username'] }}" |  | ||||||
|       password: "{{ vapp['hv.password'] }}" |  | ||||||
|       datacenter: "{{ vcenter_info.datacenter }}" |  | ||||||
|       folder: "{{ vcenter_info.folder }}" |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|   - name: Create dedicated kubeadm project within container registry |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       url: https://registry.{{ vapp['metacluster.fqdn'] }}/api/v2.0/projects |  | ||||||
|       method: POST |  | ||||||
|       headers: |  | ||||||
|         Authorization: "Basic {{ ('admin:' ~ vapp['metacluster.password']) | b64encode }}" |  | ||||||
|       body: |  | ||||||
|         project_name: kubeadm |  | ||||||
|         public: true |  | ||||||
|         storage_limit: 0 |  | ||||||
|         metadata: |  | ||||||
|           enable_content_trust: 'false' |  | ||||||
|           enable_content_trust_cosign: 'false' |  | ||||||
|           auto_scan: 'true' |  | ||||||
|           severity: none |  | ||||||
|           prevent_vul: 'false' |  | ||||||
|           public: 'true' |  | ||||||
|           reuse_sys_cve_allowlist: 'true' |  | ||||||
|  |  | ||||||
|   - 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 |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| apiVersion: argoproj.io/v1alpha1 |  | ||||||
| kind: Application |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.application.name }} |  | ||||||
|   namespace: {{ _template.application.namespace }} |  | ||||||
| spec: |  | ||||||
|   destination: |  | ||||||
|     namespace: {{ _template.cluster.namespace }} |  | ||||||
|     server: {{ _template.cluster.name }} |  | ||||||
|   project: default |  | ||||||
|   source: |  | ||||||
|     repoURL: {{ _template.repository.url }} |  | ||||||
|     path: {{ _template.repository.path }} |  | ||||||
|     targetRevision: {{ _template.repository.revision }} |  | ||||||
|   syncPolicy: |  | ||||||
|     automated: {} |  | ||||||
| @@ -1,33 +0,0 @@ | |||||||
| apiVersion: argoproj.io/v1alpha1 |  | ||||||
| kind: ApplicationSet |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.application.name }} |  | ||||||
|   namespace: {{ _template.application.namespace }} |  | ||||||
| spec: |  | ||||||
|   generators: |  | ||||||
|   - git: |  | ||||||
|       repoURL: {{ _template.repository.url }} |  | ||||||
|       revision: {{ _template.repository.revision }} |  | ||||||
|       directories: |  | ||||||
|       - path: charts/*/* |  | ||||||
|   template: |  | ||||||
|     metadata: |  | ||||||
|       name: application-{% raw %}{{ path.basename }}{% endraw +%} |  | ||||||
|     spec: |  | ||||||
|       project: default |  | ||||||
|       syncPolicy: |  | ||||||
|         automated: |  | ||||||
|           prune: true |  | ||||||
|           selfHeal: true |  | ||||||
|         syncOptions: |  | ||||||
|         - CreateNamespace=true |  | ||||||
|       sources: |  | ||||||
|       - repoURL: {{ _template.repository.url }} |  | ||||||
|         targetRevision: {{ _template.repository.revision }} |  | ||||||
|         path: {% raw %}'{{ path }}'{% endraw +%} |  | ||||||
|         helm: |  | ||||||
|           valueFiles: |  | ||||||
|           - /values/{% raw %}{{ path.basename }}{% endraw %}/values.yaml |  | ||||||
|       destination: |  | ||||||
|         server: {{ _template.cluster.url }} |  | ||||||
|         namespace: {% raw %}'{{ path[1] }}'{% endraw +%} |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| apiVersion: v1 |  | ||||||
| kind: Secret |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.cluster.secret }} |  | ||||||
|   namespace: argo-cd |  | ||||||
|   labels: |  | ||||||
|     argocd.argoproj.io/secret-type: cluster |  | ||||||
| type: Opaque |  | ||||||
| stringData: |  | ||||||
|   name: {{ _template.cluster.name }} |  | ||||||
|   server: {{ _template.cluster.url }} |  | ||||||
|   config: | |  | ||||||
|     { |  | ||||||
|       "tlsClientConfig": { |  | ||||||
|         "insecure": false, |  | ||||||
|         "caData": "{{ _template.kubeconfig.ca }}", |  | ||||||
|         "certData": "{{ _template.kubeconfig.certificate }}", |  | ||||||
|         "keyData": "{{ _template.kubeconfig.key }}" |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| @@ -1,42 +0,0 @@ | |||||||
| providers: |  | ||||||
|   - name: "kubeadm" |  | ||||||
|     url: "/opt/metacluster/cluster-api/bootstrap-kubeadm/{{ _template.version.base }}/bootstrap-components.yaml" |  | ||||||
|     type: "BootstrapProvider" |  | ||||||
|   - name: "cluster-api" |  | ||||||
|     url: "/opt/metacluster/cluster-api/cluster-api/{{ _template.version.base }}/core-components.yaml" |  | ||||||
|     type: "CoreProvider" |  | ||||||
|   - name: "kubeadm" |  | ||||||
|     url: "/opt/metacluster/cluster-api/control-plane-kubeadm/{{ _template.version.base }}/control-plane-components.yaml" |  | ||||||
|     type: "ControlPlaneProvider" |  | ||||||
|   - name: "vsphere" |  | ||||||
|     url: "/opt/metacluster/cluster-api/infrastructure-vsphere/{{ _template.version.infrastructure_vsphere }}/infrastructure-components.yaml" |  | ||||||
|     type: "InfrastructureProvider" |  | ||||||
|   - name: "in-cluster" |  | ||||||
|     url: "/opt/metacluster/cluster-api/ipam-in-cluster/{{ _template.version.ipam_incluster }}/ipam-components.yaml" |  | ||||||
|     type: "IPAMProvider" |  | ||||||
|  |  | ||||||
| cert-manager: |  | ||||||
|   url: "/opt/metacluster/cluster-api/cert-manager/{{ _template.version.cert_manager }}/cert-manager.yaml" |  | ||||||
|   version: "{{ _template.version.cert_manager }}" |  | ||||||
|  |  | ||||||
| ## -- Controller settings -- ## |  | ||||||
| VSPHERE_SERVER: "{{ _template.hv.fqdn }}" |  | ||||||
| VSPHERE_TLS_THUMBPRINT: "{{ _template.hv.tlsthumbprint }}" |  | ||||||
| VSPHERE_USERNAME: "{{ _template.hv.username }}" |  | ||||||
| VSPHERE_PASSWORD: "{{ _template.hv.password }}" |  | ||||||
|  |  | ||||||
| ## -- Required workload cluster default settings -- ## |  | ||||||
| VSPHERE_DATACENTER: "{{ _template.hv.datacenter }}" |  | ||||||
| VSPHERE_DATASTORE: "{{ _template.hv.datastore }}" |  | ||||||
| VSPHERE_STORAGE_POLICY: "" |  | ||||||
| VSPHERE_NETWORK: "{{ _template.hv.network }}" |  | ||||||
| VSPHERE_RESOURCE_POOL: "{{ _template.hv.resourcepool }}" |  | ||||||
| VSPHERE_FOLDER: "{{ _template.hv.folder }}" |  | ||||||
|  |  | ||||||
| VSPHERE_TEMPLATE: "{{ _template.cluster.nodetemplate }}" |  | ||||||
| VSPHERE_SSH_AUTHORIZED_KEY: "{{ _template.cluster.publickey }}" |  | ||||||
|  |  | ||||||
| KUBERNETES_VERSION: "{{ _template.cluster.version }}" |  | ||||||
| CONTROL_PLANE_ENDPOINT_IP: "{{ _template.cluster.vip }}" |  | ||||||
| VIP_NETWORK_INTERFACE: "" |  | ||||||
| EXP_CLUSTER_RESOURCE_SET: "true" |  | ||||||
| @@ -1,14 +0,0 @@ | |||||||
| apiVersion: v1 |  | ||||||
| kind: ConfigMap |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
|   annotations: |  | ||||||
| {{ _template.annotations }} |  | ||||||
|   labels: |  | ||||||
| {{ _template.labels }} |  | ||||||
| data: |  | ||||||
| {% for kv_pair in _template.data %} |  | ||||||
|   "{{ kv_pair.key }}": | |  | ||||||
| {{ kv_pair.value | indent(width=4, first=True) }} |  | ||||||
| {% endfor %} |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| apiVersion: config.supervisor.pinniped.dev/v1alpha1 |  | ||||||
| kind: FederationDomain |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| apiVersion: v1 |  | ||||||
| kind: Secret |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
|   labels: |  | ||||||
|     argocd.argoproj.io/secret-type: repository |  | ||||||
| stringData: |  | ||||||
|   url: {{ _template.url }} |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| apiVersion: traefik.containo.us/v1alpha1 |  | ||||||
| kind: IngressRoute |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| apiVersion: traefik.containo.us/v1alpha1 |  | ||||||
| kind: IngressRouteTCP |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| apiVersion: ipam.cluster.x-k8s.io/v1alpha2 |  | ||||||
| kind: InClusterIPPool |  | ||||||
| metadata: |  | ||||||
|   name: inclusterippool-{{ _template.cluster.name }} |  | ||||||
|   namespace: {{ _template.cluster.namespace }} |  | ||||||
| spec: |  | ||||||
|   addresses: |  | ||||||
|   - {{ _template.cluster.network.startip }}-{{ _template.cluster.network.endip }} |  | ||||||
|   prefix: {{ _template.cluster.network.prefix }} |  | ||||||
|   gateway: {{ _template.cluster.network.gateway }} |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| apiVersion: authentication.concierge.pinniped.dev/v1alpha1 |  | ||||||
| kind: JWTAuthenticator |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,260 +0,0 @@ | |||||||
| apiVersion: kustomize.config.k8s.io/v1beta1 |  | ||||||
| kind: Kustomization |  | ||||||
| resources: |  | ||||||
| - cluster-template.yaml |  | ||||||
|  |  | ||||||
| patches: |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: v1 |  | ||||||
|     kind: Secret |  | ||||||
|     metadata: |  | ||||||
|       name: csi-vsphere-config |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     stringData: |  | ||||||
|       data: | |  | ||||||
|         apiVersion: v1 |  | ||||||
|         kind: Secret |  | ||||||
|         metadata: |  | ||||||
|           name: csi-vsphere-config |  | ||||||
|           namespace: kube-system |  | ||||||
|         stringData: |  | ||||||
|           csi-vsphere.conf: |+ |  | ||||||
|             [Global] |  | ||||||
|             insecure-flag = true |  | ||||||
|             thumbprint = "${VSPHERE_TLS_THUMBPRINT}" |  | ||||||
|             cluster-id = "${NAMESPACE}/${CLUSTER_NAME}" |  | ||||||
|  |  | ||||||
|             [VirtualCenter "${VSPHERE_SERVER}"] |  | ||||||
|             user = "${VSPHERE_USERNAME}" |  | ||||||
|             password = "${VSPHERE_PASSWORD}" |  | ||||||
|             datacenters = "${VSPHERE_DATACENTER}" |  | ||||||
|  |  | ||||||
|             [Network] |  | ||||||
|             public-network = "${VSPHERE_NETWORK}" |  | ||||||
|         type: Opaque |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: controlplane.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: KubeadmControlPlane |  | ||||||
|     metadata: |  | ||||||
|       name: '${CLUSTER_NAME}' |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     spec: |  | ||||||
|       kubeadmConfigSpec: |  | ||||||
|         clusterConfiguration: |  | ||||||
|           imageRepository: registry.{{ _template.network.fqdn }}/kubeadm |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: '${CLUSTER_NAME}-md-0' |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           clusterConfiguration: |  | ||||||
|             imageRepository: registry.{{ _template.network.fqdn }}/kubeadm |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: '${CLUSTER_NAME}-md-0' |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           files: |  | ||||||
|           - content: | |  | ||||||
|                 [plugins."io.containerd.grpc.v1.cri".registry] |  | ||||||
|                   config_path = "/etc/containerd/certs.d" |  | ||||||
|             append: true |  | ||||||
|             path: /etc/containerd/config.toml |  | ||||||
| {% for registry in _template.registries %} |  | ||||||
|           - content: | |  | ||||||
|               server = "https://{{ registry }}" |  | ||||||
|  |  | ||||||
|               [host."https://registry.{{ _template.network.fqdn }}/v2/library/{{ registry }}"] |  | ||||||
|                 capabilities = ["pull", "resolve"] |  | ||||||
|                 override_path = true |  | ||||||
|             owner: root:root |  | ||||||
|             path: /etc/containerd/certs.d/{{ registry }}/hosts.toml |  | ||||||
| {% endfor %} |  | ||||||
|           - content: | |  | ||||||
|               network: {config: disabled} |  | ||||||
|             owner: root:root |  | ||||||
|             path: /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg |  | ||||||
|           - content: | |  | ||||||
|               {{ _template.rootca | indent(width=14, first=False) | trim }} |  | ||||||
|             owner: root:root |  | ||||||
|             path: /usr/local/share/ca-certificates/root_ca.crt |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: ${CLUSTER_NAME} |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           network: |  | ||||||
|             devices: |  | ||||||
|             - dhcp4: false |  | ||||||
|               addressesFromPools: |  | ||||||
|               - apiGroup: ipam.cluster.x-k8s.io |  | ||||||
|                 kind: InClusterIPPool |  | ||||||
|                 name: inclusterippool-${CLUSTER_NAME} |  | ||||||
|               nameservers: |  | ||||||
|               - {{ _template.network.dnsserver }} |  | ||||||
|               networkName: '${VSPHERE_NETWORK}' |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: ${CLUSTER_NAME}-worker |  | ||||||
|       namespace: '${NAMESPACE}' |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           network: |  | ||||||
|             devices: |  | ||||||
|             - dhcp4: false |  | ||||||
|               addressesFromPools: |  | ||||||
|               - apiGroup: ipam.cluster.x-k8s.io |  | ||||||
|                 kind: InClusterIPPool |  | ||||||
|                 name: inclusterippool-${CLUSTER_NAME} |  | ||||||
|               nameservers: |  | ||||||
|               - {{ _template.network.dnsserver }} |  | ||||||
|               networkName: '${VSPHERE_NETWORK}' |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: controlplane.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmControlPlane |  | ||||||
|     name: .* |  | ||||||
|   patch: |- |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/kubeadmConfigSpec/files/- |  | ||||||
|       value: |  | ||||||
|         content: | |  | ||||||
|             [plugins."io.containerd.grpc.v1.cri".registry] |  | ||||||
|               config_path = "/etc/containerd/certs.d" |  | ||||||
|         append: true |  | ||||||
|         path: /etc/containerd/config.toml |  | ||||||
| {% for registry in _template.registries %} |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/kubeadmConfigSpec/files/- |  | ||||||
|       value: |  | ||||||
|         content: | |  | ||||||
|           server = "https://{{ registry }}" |  | ||||||
|  |  | ||||||
|           [host."https://registry.{{ _template.network.fqdn }}/v2/library/{{ registry }}"] |  | ||||||
|             capabilities = ["pull", "resolve"] |  | ||||||
|             override_path = true |  | ||||||
|         owner: root:root |  | ||||||
|         path: /etc/containerd/certs.d/{{ registry }}/hosts.toml |  | ||||||
| {% endfor %} |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/kubeadmConfigSpec/files/- |  | ||||||
|       value: |  | ||||||
|         content: | |  | ||||||
|           network: {config: disabled} |  | ||||||
|         owner: root:root |  | ||||||
|         path: /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/kubeadmConfigSpec/files/- |  | ||||||
|       value: |  | ||||||
|         content: | |  | ||||||
|           {{ _template.rootca | indent(width=10, first=False) | trim }} |  | ||||||
|         owner: root:root |  | ||||||
|         path: /usr/local/share/ca-certificates/root_ca.crt |  | ||||||
| - target: |  | ||||||
|     group: bootstrap.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     name: .* |  | ||||||
|   patch: |- |  | ||||||
| {% for cmd in _template.runcmds %} |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/template/spec/preKubeadmCommands/- |  | ||||||
|       value: {{ cmd }} |  | ||||||
| {% endfor %} |  | ||||||
| - target: |  | ||||||
|     group: controlplane.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmControlPlane |  | ||||||
|     name: .* |  | ||||||
|   patch: |- |  | ||||||
| {% for cmd in _template.runcmds %} |  | ||||||
|     - op: add |  | ||||||
|       path: /spec/kubeadmConfigSpec/preKubeadmCommands/- |  | ||||||
|       value: {{ cmd }} |  | ||||||
| {% endfor %} |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: infrastructure.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     name: \${CLUSTER_NAME} |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: ${CLUSTER_NAME}-master |  | ||||||
| - target: |  | ||||||
|     group: controlplane.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmControlPlane |  | ||||||
|     name: \${CLUSTER_NAME} |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: ${CLUSTER_NAME}-master |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/machineTemplate/infrastructureRef/name |  | ||||||
|       value: ${CLUSTER_NAME}-master |  | ||||||
| - target: |  | ||||||
|     group: cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: Cluster |  | ||||||
|     name: \${CLUSTER_NAME} |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/clusterNetwork/pods |  | ||||||
|       value: |  | ||||||
|         cidrBlocks: |  | ||||||
|           - 172.30.0.0/16 |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/controlPlaneRef/name |  | ||||||
|       value: ${CLUSTER_NAME}-master |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: infrastructure.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     name: \${CLUSTER_NAME}-worker |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/template/spec/numCPUs |  | ||||||
|       value: {{ _template.nodesize.cpu }} |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/template/spec/memoryMiB |  | ||||||
|       value: {{ _template.nodesize.memory }} |  | ||||||
| - target: |  | ||||||
|     group: cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: MachineDeployment |  | ||||||
|     name: \${CLUSTER_NAME}-md-0 |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: ${CLUSTER_NAME}-worker |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/template/spec/bootstrap/configRef/name |  | ||||||
|       value: ${CLUSTER_NAME}-worker |  | ||||||
| - target: |  | ||||||
|     group: bootstrap.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     name: \${CLUSTER_NAME}-md-0 |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: ${CLUSTER_NAME}-worker |  | ||||||
| @@ -1,83 +0,0 @@ | |||||||
| apiVersion: kustomize.config.k8s.io/v1beta1 |  | ||||||
| kind: Kustomization |  | ||||||
| resources: |  | ||||||
| - downstream-cluster/kubeadmconfigtemplate-{{ _template.cluster.name }}-worker.yaml |  | ||||||
| - downstream-cluster/machinedeployment-{{ _template.cluster.name }}-worker.yaml |  | ||||||
| - downstream-cluster/vspheremachinetemplate-{{ _template.cluster.name }}-worker.yaml |  | ||||||
|  |  | ||||||
| patches: |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: bootstrap.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: {{ _template.cluster.name }}-worker |  | ||||||
|       namespace: default |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           diskSetup: |  | ||||||
|             filesystems: |  | ||||||
|             - device: /dev/sdb1 |  | ||||||
|               filesystem: ext4 |  | ||||||
|               label: blockstorage |  | ||||||
|             partitions: |  | ||||||
|             - device: /dev/sdb |  | ||||||
|               layout: true |  | ||||||
|               tableType: gpt |  | ||||||
|           joinConfiguration: |  | ||||||
|             nodeRegistration: |  | ||||||
|               kubeletExtraArgs: |  | ||||||
|                 node-labels: "node.longhorn.io/create-default-disk=true" |  | ||||||
|           mounts: |  | ||||||
|           - - LABEL=blockstorage |  | ||||||
|             - /mnt/blockstorage |  | ||||||
| - patch: |- |  | ||||||
|     apiVersion: infrastructure.cluster.x-k8s.io/v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     metadata: |  | ||||||
|       name: {{ _template.cluster.name }}-worker |  | ||||||
|       namespace: default |  | ||||||
|     spec: |  | ||||||
|       template: |  | ||||||
|         spec: |  | ||||||
|           additionalDisksGiB: |  | ||||||
|           - {{ _template.nodepool.additionaldisk }} |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: bootstrap.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: KubeadmConfigTemplate |  | ||||||
|     name: {{ _template.cluster.name }}-worker |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: {{ _template.cluster.name }}-worker-storage |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: MachineDeployment |  | ||||||
|     name: {{ _template.cluster.name }}-worker |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: {{ _template.cluster.name }}-worker-storage |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/template/spec/bootstrap/configRef/name |  | ||||||
|       value: {{ _template.cluster.name }}-worker-storage |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/template/spec/infrastructureRef/name |  | ||||||
|       value: {{ _template.cluster.name }}-worker-storage |  | ||||||
|     - op: replace |  | ||||||
|       path: /spec/replicas |  | ||||||
|       value: {{ _template.nodepool.size }} |  | ||||||
|  |  | ||||||
| - target: |  | ||||||
|     group: infrastructure.cluster.x-k8s.io |  | ||||||
|     version: v1beta1 |  | ||||||
|     kind: VSphereMachineTemplate |  | ||||||
|     name: {{ _template.cluster.name }}-worker |  | ||||||
|   patch: |- |  | ||||||
|     - op: replace |  | ||||||
|       path: /metadata/name |  | ||||||
|       value: {{ _template.cluster.name }}-worker-storage |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| apiVersion: idp.supervisor.pinniped.dev/v1alpha1 |  | ||||||
| kind: OIDCIdentityProvider |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| apiVersion: v1 |  | ||||||
| kind: Secret |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| type: {{ _template.type }} |  | ||||||
| data: |  | ||||||
| {% for kv_pair in _template.data %} |  | ||||||
|   "{{ kv_pair.key }}": {{ kv_pair.value }} |  | ||||||
| {% endfor %} |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| apiVersion: traefik.containo.us/v1alpha1 |  | ||||||
| kind: ServersTransport |  | ||||||
| metadata: |  | ||||||
|   name: {{ _template.name }} |  | ||||||
|   namespace: {{ _template.namespace }} |  | ||||||
| spec: |  | ||||||
| {{ _template.spec }} |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| - name: Disable crontab job |  | ||||||
|   ansible.builtin.cron: |  | ||||||
|     name: firstboot |  | ||||||
|     state: absent |  | ||||||
| @@ -1,6 +0,0 @@ | |||||||
| - import_tasks: service.yml |  | ||||||
| - import_tasks: cron.yml |  | ||||||
|  |  | ||||||
| # - name: Reboot host |  | ||||||
| #   ansible.builtin.shell: |  | ||||||
| #     cmd: systemctl reboot |  | ||||||
| @@ -1,30 +0,0 @@ | |||||||
| - name: Create tarball compression service |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: "{{ item.src }}" |  | ||||||
|     dest: "{{ item.dest }}" |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: "{{ item.mode | default(omit) }}" |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       service: |  | ||||||
|         name: compressTarballs |  | ||||||
|         executable: /opt/firstboot/compresstarballs.sh |  | ||||||
|         workingdir: /opt/metacluster/container-images/ |  | ||||||
|   loop: |  | ||||||
|     - src: compresstarballs.j2 |  | ||||||
|       dest: "{{ _template.service.executable }}" |  | ||||||
|       mode: o+x |  | ||||||
|     - src: systemdunit.j2 |  | ||||||
|       dest: /etc/systemd/system/{{ _template.service.name }}.service |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.src }}" |  | ||||||
|  |  | ||||||
| - name: Enable/Start services |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     name: "{{ item }}" |  | ||||||
|     enabled: yes |  | ||||||
|     state: started |  | ||||||
|   loop: |  | ||||||
|     - compressTarballs |  | ||||||
|     - ttyConsoleMessage |  | ||||||
| @@ -1,40 +0,0 @@ | |||||||
| - name: Create volume group |  | ||||||
|   community.general.lvg: |  | ||||||
|     vg: longhorn_vg |  | ||||||
|     pvs: |  | ||||||
|       - /dev/sdb |  | ||||||
|     pvresize: yes |  | ||||||
|  |  | ||||||
| - name: Create logical volume |  | ||||||
|   community.general.lvol: |  | ||||||
|     vg: longhorn_vg |  | ||||||
|     lv: longhorn_lv |  | ||||||
|     size: 100%VG |  | ||||||
|  |  | ||||||
| - name: Store begin timestamp |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     start_time: "{{ lookup('pipe', 'date +%s') }}" |  | ||||||
|  |  | ||||||
| - name: Create filesystem |  | ||||||
|   community.general.filesystem: |  | ||||||
|     dev: /dev/mapper/longhorn_vg-longhorn_lv |  | ||||||
|     fstype: ext4 |  | ||||||
|  |  | ||||||
| - name: Store end timestamp |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     end_time: "{{ lookup('pipe', 'date +%s') }}" |  | ||||||
|  |  | ||||||
| - name: Calculate crude storage benchmark |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     storage_benchmark: "{{ [storage_benchmark, (end_time | int - start_time | int)] | max }}" |  | ||||||
|  |  | ||||||
| - name: Log benchmark actual duration |  | ||||||
|   ansible.builtin.debug: |  | ||||||
|     msg: "Benchmark actual duration: {{ (end_time | int - start_time | int) }} second(s)" |  | ||||||
|  |  | ||||||
| - name: Mount dynamic disk |  | ||||||
|   ansible.posix.mount: |  | ||||||
|     path: /mnt/blockstorage |  | ||||||
|     src: /dev/mapper/longhorn_vg-longhorn_lv |  | ||||||
|     fstype: ext4 |  | ||||||
|     state: mounted |  | ||||||
| @@ -1,12 +0,0 @@ | |||||||
| - name: Import container images |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: k3s ctr image import {{ item }} --digests |  | ||||||
|     chdir: /opt/metacluster/container-images |  | ||||||
|   register: import_result |  | ||||||
|   loop: "{{ query('ansible.builtin.fileglob', '/opt/metacluster/container-images/*.tar') | sort }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item | basename }}" |  | ||||||
|   # Probably should add a task before that ensures K3s node is fully initialized before starting imports; currently K3s goes away briefly during this loop |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|   until: import_result is not failed |  | ||||||
| @@ -1,19 +0,0 @@ | |||||||
| - name: Set hostname |  | ||||||
|   ansible.builtin.hostname: |  | ||||||
|     name: "{{ vapp['guestinfo.hostname'] }}" |  | ||||||
|  |  | ||||||
| - name: Create netplan configuration file |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: netplan.j2 |  | ||||||
|     dest: /etc/netplan/00-installer-config.yaml |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       macaddress: "{{ ansible_facts.default_ipv4.macaddress }}" |  | ||||||
|       ipaddress: "{{ vapp['guestinfo.ipaddress'] }}" |  | ||||||
|       prefixlength: "{{ vapp['guestinfo.prefixlength'] }}" |  | ||||||
|       gateway: "{{ vapp['guestinfo.gateway'] }}" |  | ||||||
|       dnsserver: "{{ vapp['guestinfo.dnsserver'] }}" |  | ||||||
|  |  | ||||||
| - name: Apply netplan configuration |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: /usr/sbin/netplan apply |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| network: |  | ||||||
|   version: 2 |  | ||||||
|   ethernets: |  | ||||||
|     id0: |  | ||||||
|       set-name: eth0 |  | ||||||
|       match: |  | ||||||
|         macaddress: {{ _template.macaddress }} |  | ||||||
|       addresses: |  | ||||||
|       - {{ _template.ipaddress }}/{{ _template.prefixlength }} |  | ||||||
|       gateway4: {{ _template.gateway }} |  | ||||||
|       nameservers: |  | ||||||
|         addresses: |  | ||||||
|         - {{ _template.dnsserver }} |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| - import_tasks: vapp.yml |  | ||||||
| - import_tasks: vcenter.yml |  | ||||||
| @@ -1,16 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Check for vCenter connectivity |  | ||||||
|       community.vmware.vmware_vcenter_settings_info: |  | ||||||
|         schema: vsphere |  | ||||||
|       register: vcenter_info |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|       until: vcenter_info is not failed |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     group/vmware: |  | ||||||
|       hostname: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|       validate_certs: no |  | ||||||
|       username: "{{ vapp['hv.username'] }}" |  | ||||||
|       password: "{{ vapp['hv.password'] }}" |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| - name: Create folder structure(s) |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item }}" |  | ||||||
|     state: directory |  | ||||||
|   loop: |  | ||||||
|     - /opt/firstboot |  | ||||||
|  |  | ||||||
| - name: Create tty console message service |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: "{{ item.src }}" |  | ||||||
|     dest: "{{ item.dest }}" |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: "{{ item.mode | default(omit) }}" |  | ||||||
|   vars: |  | ||||||
|     _template: |  | ||||||
|       service: |  | ||||||
|         name: ttyConsoleMessage |  | ||||||
|         executable: /opt/firstboot/tty.sh |  | ||||||
|         workingdir: /tmp/ |  | ||||||
|       metacluster: |  | ||||||
|         components: |  | ||||||
|           - name: ArgoCD |  | ||||||
|             url: https://gitops.${FQDN} |  | ||||||
|             healthcheck: https://gitops.${FQDN} |  | ||||||
|           - name: Gitea |  | ||||||
|             url: https://git.${FQDN} |  | ||||||
|             healthcheck: https://git.${FQDN} |  | ||||||
|           - name: Harbor |  | ||||||
|             url: https://registry.${FQDN} |  | ||||||
|             healthcheck: https://registry.${FQDN} |  | ||||||
|           - name: Longhorn |  | ||||||
|             url: https://storage.${FQDN} |  | ||||||
|             healthcheck: https://storage.${FQDN} |  | ||||||
|           - name: StepCA |  | ||||||
|             url: '' |  | ||||||
|             healthcheck: https://ca.${FQDN}/health |  | ||||||
|           - name: Traefik |  | ||||||
|             url: https://ingress.${FQDN} |  | ||||||
|             healthcheck: https://ingress.${FQDN} |  | ||||||
|         fqdn: "{{ vapp['metacluster.fqdn'] }}" |  | ||||||
|         vip: "{{ vapp['metacluster.vip'] }}" |  | ||||||
|   loop: |  | ||||||
|     - src: tty.j2 |  | ||||||
|       dest: "{{ _template.service.executable }}" |  | ||||||
|       mode: o+x |  | ||||||
|     - src: systemdunit.j2 |  | ||||||
|       dest: /etc/systemd/system/{{ _template.service.name }}.service |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.src }}" |  | ||||||
| @@ -1,39 +0,0 @@ | |||||||
| - name: Set root password |  | ||||||
|   ansible.builtin.user: |  | ||||||
|     name: root |  | ||||||
|     password: "{{ vapp['metacluster.password'] | password_hash('sha512', 65534 | random(seed=vapp['guestinfo.hostname']) | string) }}" |  | ||||||
|     generate_ssh_key: yes |  | ||||||
|     ssh_key_bits: 2048 |  | ||||||
|     ssh_key_file: .ssh/id_rsa |  | ||||||
|  |  | ||||||
| - name: Save root SSH publickey |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /root/.ssh/authorized_keys |  | ||||||
|     line: "{{ vapp['guestinfo.rootsshkey'] }}" |  | ||||||
|  |  | ||||||
| - name: Disable SSH password authentication |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /etc/ssh/sshd_config |  | ||||||
|     regex: "{{ item.regex }}" |  | ||||||
|     line: "{{ item.line }}" |  | ||||||
|     state: "{{ item.state }}" |  | ||||||
|   loop: |  | ||||||
|   - regex: '^#PasswordAuthentication' |  | ||||||
|     line: 'PasswordAuthentication no' |  | ||||||
|     state: present |  | ||||||
|   - regex: '^PasswordAuthentication yes' |  | ||||||
|     line: 'PasswordAuthentication yes' |  | ||||||
|     state: absent |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ '[' ~ item.regex ~ '] ' ~ item.state }}" |  | ||||||
|  |  | ||||||
| - name: Create dedicated SSH keypair |  | ||||||
|   community.crypto.openssh_keypair: |  | ||||||
|     path: /root/.ssh/git_rsa_id |  | ||||||
|   register: gitops_sshkey |  | ||||||
|  |  | ||||||
| - name: Delete 'ubuntu' user |  | ||||||
|   ansible.builtin.user: |  | ||||||
|     name: ubuntu |  | ||||||
|     state: absent |  | ||||||
|     remove: yes |  | ||||||
| @@ -1,38 +0,0 @@ | |||||||
| - name: Store current ovfEnvironment |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: /usr/bin/vmtoolsd --cmd "info-get guestinfo.ovfEnv" |  | ||||||
|   register: ovfenv |  | ||||||
|  |  | ||||||
| - name: Parse XML for MoRef ID |  | ||||||
|   community.general.xml: |  | ||||||
|     xmlstring: "{{ ovfenv.stdout }}" |  | ||||||
|     namespaces: |  | ||||||
|       ns: http://schemas.dmtf.org/ovf/environment/1 |  | ||||||
|       ve: http://www.vmware.com/schema/ovfenv |  | ||||||
|     xpath: /ns:Environment |  | ||||||
|     content: attribute |  | ||||||
|   register: environment_attribute |  | ||||||
|  |  | ||||||
| - name: Store MoRef ID |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     moref_id: "{{ ((environment_attribute.matches[0].values() | list)[0].values() | list)[1] }}" |  | ||||||
|  |  | ||||||
| - name: Parse XML for vApp properties |  | ||||||
|   community.general.xml: |  | ||||||
|     xmlstring: "{{ ovfenv.stdout }}" |  | ||||||
|     namespaces: |  | ||||||
|       ns: http://schemas.dmtf.org/ovf/environment/1 |  | ||||||
|     xpath: /ns:Environment/ns:PropertySection/ns:Property |  | ||||||
|     content: attribute |  | ||||||
|   register: property_section |  | ||||||
|  |  | ||||||
| - name: Assign vApp properties to dictionary |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     vapp: >- |  | ||||||
|       {{ vapp | default({}) | combine({ |  | ||||||
|         ((item.values() | list)[0].values() | list)[0]: |  | ||||||
|         ((item.values() | list)[0].values() | list)[1]}) |  | ||||||
|       }} |  | ||||||
|   loop: "{{ property_section.matches }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ ((item.values() | list)[0].values() | list)[0] }}" |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # Change working directory |  | ||||||
| pushd {{ _template.service.workingdir }} |  | ||||||
|  |  | ||||||
| # Compress *.tar files |  | ||||||
| if tar -czf image-tarballs.tgz *.tar --remove-files; then |  | ||||||
|     # Disable systemd unit |  | ||||||
|     systemctl disable {{ _template.service.name }} |  | ||||||
| fi |  | ||||||
| @@ -1,8 +0,0 @@ | |||||||
| mirrors: |  | ||||||
| {% for registry in _template.registries %} |  | ||||||
|   {{ registry }}: |  | ||||||
|     endpoint: |  | ||||||
|       - https://registry.{{ _template.hv.fqdn }} |  | ||||||
|     rewrite: |  | ||||||
|       "(.*)": "library/{{ registry }}/$1" |  | ||||||
| {% endfor %} |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| [Unit] |  | ||||||
| Description={{ _template.service.name }} |  | ||||||
|  |  | ||||||
| [Service] |  | ||||||
| ExecStart={{ _template.service.executable }} |  | ||||||
| Nice=10 |  | ||||||
|  |  | ||||||
| [Install] |  | ||||||
| WantedBy=multi-user.target |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| export TERM=linux |  | ||||||
|  |  | ||||||
| BGRN='\033[1;92m' |  | ||||||
| BGRY='\033[1;30m' |  | ||||||
| BBLU='\033[1;34m' |  | ||||||
| BRED='\033[1;91m' |  | ||||||
| BWHI='\033[1;97m' |  | ||||||
| CBLA='\033[?16;0;30c' # Hide blinking cursor |  | ||||||
| DFLT='\033[0m'        # Reset colour |  | ||||||
| LCLR='\033[K'         # Clear to end of line |  | ||||||
| PRST='\033[0;0H'      # Reset cursor position |  | ||||||
|  |  | ||||||
| FQDN='{{ _template.metacluster.fqdn }}' |  | ||||||
| IPADDRESS='{{ _template.metacluster.vip }}' |  | ||||||
|  |  | ||||||
| declare -A COMPONENTS |  | ||||||
| {% for component in _template.metacluster.components %} |  | ||||||
| COMPONENTS["{{ component.name }}\t({{ component.url }})"]="{{ component.healthcheck }}" |  | ||||||
| {% endfor %} |  | ||||||
|  |  | ||||||
| I=0 |  | ||||||
|  |  | ||||||
| while /bin/true; do |  | ||||||
|   if [[ $I -gt 59 ]]; then |  | ||||||
|     clear > /dev/tty1 |  | ||||||
|     I=0 |  | ||||||
|   else |  | ||||||
|     I=$(( $I + 1 )) |  | ||||||
|   fi |  | ||||||
|  |  | ||||||
|   echo -e "${PRST}" > /dev/tty1 |  | ||||||
|   echo -e "\n\n\t${DFLT}To manage this appliance, please connect to one of the following:${LCLR}\n" > /dev/tty1 |  | ||||||
|  |  | ||||||
|   for c in $( echo "${!COMPONENTS[@]}" | tr ' ' $'\n' | sort); do |  | ||||||
|     STATUS=$(curl -kLs "${COMPONENTS[${c}]}" -o /dev/null -w '%{http_code}') |  | ||||||
|  |  | ||||||
|     if [[ "${STATUS}" -eq "200" ]]; then |  | ||||||
|       echo -e "\t [${BGRN}+${DFLT}] ${BBLU}${c}${DFLT}${LCLR}" > /dev/tty1 |  | ||||||
|     else |  | ||||||
|       echo -e "\t [${BRED}-${DFLT}] ${BBLU}${c}${DFLT}${LCLR}" > /dev/tty1 |  | ||||||
|     fi |  | ||||||
|   done |  | ||||||
|  |  | ||||||
|   echo -e "\n\t${BGRY}Note that your DNS zone ${DFLT}must have${BGRY} respective records defined,\n\teach pointing to: ${DFLT}${IPADDRESS}${LCLR}" > /dev/tty1 |  | ||||||
|  |  | ||||||
|   echo -e "${CBLA}" > /dev/tty1 |  | ||||||
|   sleep 1 |  | ||||||
| done |  | ||||||
| @@ -1,23 +0,0 @@ | |||||||
| playbook: |  | ||||||
|   retries: 10 |  | ||||||
|   delay: |  | ||||||
|     # These values are multiplied with the value of `storage_benchmark` |  | ||||||
|     long: 2 |  | ||||||
|     medium: 1 |  | ||||||
|     short: 0.5 |  | ||||||
|  |  | ||||||
| # This default value is updated during the playbook, based on an I/O intensive operation |  | ||||||
| storage_benchmark: 30 |  | ||||||
|  |  | ||||||
| config: |  | ||||||
|   clusterapi: |  | ||||||
|     size_matrix: |  | ||||||
|       small: |  | ||||||
|         cpu: 2 |  | ||||||
|         memory: 6144 |  | ||||||
|       medium: |  | ||||||
|         cpu: 4 |  | ||||||
|         memory: 8192 |  | ||||||
|       large: |  | ||||||
|         cpu: 8 |  | ||||||
|         memory: 16384 |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| --- |  | ||||||
| - hosts: 127.0.0.1 |  | ||||||
|   connection: local |  | ||||||
|   gather_facts: true |  | ||||||
|   vars_files: |  | ||||||
|     - defaults.yml |  | ||||||
|     - metacluster.yml |  | ||||||
|   # become: true |  | ||||||
|   roles: |  | ||||||
|     - vapp |  | ||||||
|     - network |  | ||||||
|     - preflight |  | ||||||
|     - users |  | ||||||
|     - disks |  | ||||||
|     - metacluster |  | ||||||
|     - workloadcluster |  | ||||||
|     - decommission |  | ||||||
|     - tty |  | ||||||
|     - cleanup |  | ||||||
|   handlers: |  | ||||||
|     - name: Apply manifests |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         src: "{{ item }}" |  | ||||||
|         state: present |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       loop: "{{ query('ansible.builtin.fileglob', '/var/lib/rancher/k3s/server/manifests/*.yaml') | sort }}" |  | ||||||
|       ignore_errors: yes |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| - name: Cordon node |  | ||||||
|   kubernetes.core.k8s_drain: |  | ||||||
|     name: "{{ decom_nodename }}" |  | ||||||
|     state: cordon |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|  |  | ||||||
| - name: Drain node |  | ||||||
| # Currently does not work; returns with error "Failed to delete pod [...] due to: Too Many Requests" |  | ||||||
| # See also: https://github.com/ansible-collections/kubernetes.core/issues/474 |  | ||||||
| #   kubernetes.core.k8s_drain: |  | ||||||
| #     name: "{{ decom_nodename }}" |  | ||||||
| #     state: drain |  | ||||||
| #     delete_options: |  | ||||||
| #       ignore_daemonsets: true |  | ||||||
| #       delete_emptydir_data: true |  | ||||||
| #     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: >- |  | ||||||
|       kubectl drain {{ decom_nodename }} \ |  | ||||||
|         --delete-emptydir-data \ |  | ||||||
|         --ignore-daemonsets |  | ||||||
|   register: nodedrain_results |  | ||||||
|   until: |  | ||||||
|     - nodedrain_results is not failed |  | ||||||
|     - (nodedrain_results.stdout_lines | last) is match('node/.* drained') |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|  |  | ||||||
| - name: Delete node |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     name: "{{ decom_nodename }}" |  | ||||||
|     kind: node |  | ||||||
|     state: absent |  | ||||||
|     wait: true |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
| @@ -1,18 +0,0 @@ | |||||||
| - name: Lookup node name and moref-id for decommissioning |  | ||||||
|   ansible.builtin.set_fact: |  | ||||||
|     decom_nodename: >- |  | ||||||
|       {{ |  | ||||||
|         lookup('kubernetes.core.k8s', kind='Node', kubeconfig=(kubeconfig.path)) | |  | ||||||
|           json_query('[? metadata.name != `' ~ ansible_facts.nodename ~ '`].metadata.name') | |  | ||||||
|           first |  | ||||||
|       }} |  | ||||||
|     decom_morefid: >- |  | ||||||
|       {{ |  | ||||||
|         lookup('kubernetes.core.k8s', kind='Node', kubeconfig=(kubeconfig.path)) | |  | ||||||
|           json_query('[? metadata.name != `' ~ ansible_facts.nodename ~ '`].metadata.labels."ova.airgappedk8s/moref_id"') | |  | ||||||
|           first |  | ||||||
|       }} |  | ||||||
|  |  | ||||||
| - import_tasks: storage.yml |  | ||||||
| - import_tasks: k3s.yml |  | ||||||
| - import_tasks: virtualmachine.yml |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| - name: Disable disk scheduling and evict replicas |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     api_version: longhorn.io/v1beta2 |  | ||||||
|     kind: lhn |  | ||||||
|     name: "{{ decom_nodename }}" |  | ||||||
|     namespace: longhorn-system |  | ||||||
|     state: patched |  | ||||||
|     definition: | |  | ||||||
|       spec: |  | ||||||
|         allowScheduling: false |  | ||||||
|         evictionRequested: true |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|  |  | ||||||
| - name: Reduce replica amount for each volume |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     api_version: longhorn.io/v1beta2 |  | ||||||
|     kind: volume |  | ||||||
|     name: "{{ item.metadata.name }}" |  | ||||||
|     namespace: longhorn-system |  | ||||||
|     state: patched |  | ||||||
|     definition: | |  | ||||||
|       spec: |  | ||||||
|         numberOfReplicas: {{ (lookup('kubernetes.core.k8s', kind='node', kubeconfig=(kubeconfig.path)) | length | int) - 1 }} |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   loop: "{{ query('kubernetes.core.k8s', api_version='longhorn.io/v1beta2', kind='volume', namespace='longhorn-system', kubeconfig=(kubeconfig.path)) }}" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.metadata.name }}" |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Lookup VM name |  | ||||||
|       community.vmware.vmware_guest_info: |  | ||||||
|         moid: "{{ decom_morefid }}" |  | ||||||
|       register: virtualmachine_details |  | ||||||
|  |  | ||||||
|     - name: Power off VM |  | ||||||
|       community.vmware.vmware_guest: |  | ||||||
|         name: "{{ virtualmachine_details.instance.hw_name }}" |  | ||||||
|         folder: "{{ virtualmachine_details.instance.hw_folder }}" |  | ||||||
|         state: poweredoff |  | ||||||
|  |  | ||||||
|     # - name: Delete VM |  | ||||||
|     #   community.vmware.vmware_guest: |  | ||||||
|     #     name: "{{ virtualmachine_details.hw_name }}" |  | ||||||
|     #     folder: "{{ virtualmachine_details.hw_folder }}" |  | ||||||
|     #     state: absent |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     group/vmware: |  | ||||||
|       hostname: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|       validate_certs: no |  | ||||||
|       username: "{{ vapp['hv.username'] }}" |  | ||||||
|       password: "{{ vapp['hv.password'] }}" |  | ||||||
|       datacenter: "{{ vcenter_info.datacenter }}" |  | ||||||
| @@ -1,52 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Initialize tempfile |  | ||||||
|       ansible.builtin.tempfile: |  | ||||||
|         state: file |  | ||||||
|       register: values_file |  | ||||||
|  |  | ||||||
|     - name: Lookup current chart values |  | ||||||
|       kubernetes.core.helm_info: |  | ||||||
|         name: step-certificates |  | ||||||
|         namespace: step-ca |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       register: stepca_values |  | ||||||
|  |  | ||||||
|     - name: Write chart values w/ password to tempfile |  | ||||||
|       ansible.builtin.copy: |  | ||||||
|         dest: "{{ values_file.path }}" |  | ||||||
|         content: "{{ stepca_values.status | json_query('values') | to_yaml }}" |  | ||||||
|       no_log: true |  | ||||||
|  |  | ||||||
|     - name: Upgrade step-ca chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: step-certificates |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/step-certificates |  | ||||||
|         release_namespace: step-ca |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values_files: |  | ||||||
|           - "{{ values_file.path }}" |  | ||||||
|  |  | ||||||
|     - name: Cleanup tempfile |  | ||||||
|       ansible.builtin.file: |  | ||||||
|         path: "{{ values_file.path }}" |  | ||||||
|         state: absent |  | ||||||
|       when: values_file.path is defined |  | ||||||
|  |  | ||||||
|     - 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: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,50 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Push images to registry |  | ||||||
|       ansible.builtin.shell: |  | ||||||
|         cmd: >- |  | ||||||
|           skopeo copy \ |  | ||||||
|             --insecure-policy \ |  | ||||||
|             --dest-tls-verify=false \ |  | ||||||
|             --dest-creds admin:{{ vapp['metacluster.password'] }} \ |  | ||||||
|             docker-archive:./{{ item | basename }} \ |  | ||||||
|             docker://registry.{{ vapp['metacluster.fqdn'] }}/library/$( \ |  | ||||||
|               skopeo list-tags \ |  | ||||||
|                 --insecure-policy \ |  | ||||||
|                 docker-archive:./{{ item | basename }} | \ |  | ||||||
|               jq -r '.Tags[0]') |  | ||||||
|         chdir: /opt/metacluster/container-images/ |  | ||||||
|       register: push_result |  | ||||||
|       loop: "{{ query('ansible.builtin.fileglob', '/opt/metacluster/container-images/*.tar') | sort }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item | basename }}" |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ ((storage_benchmark | float) * playbook.delay.short) | int }}" |  | ||||||
|       until: push_result is not failed |  | ||||||
|  |  | ||||||
|     - name: Get all stored container images (=artifacts) |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://registry.{{ vapp['metacluster.fqdn'] }}/api/v2.0/search?q=library |  | ||||||
|         method: GET |  | ||||||
|       register: registry_artifacts |  | ||||||
|  |  | ||||||
|     - name: Get source registries of all artifacts |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         source_registries: "{{ (source_registries | default([]) + [(item | split('/'))[1]]) | unique | sort }}" |  | ||||||
|       loop: "{{ registry_artifacts.json.repository | json_query('[*].repository_name') }}" |  | ||||||
|  |  | ||||||
|     - name: Configure K3s node for private registry |  | ||||||
|       ansible.builtin.template: |  | ||||||
|         dest: /etc/rancher/k3s/registries.yaml |  | ||||||
|         src: registries.j2 |  | ||||||
|       vars: |  | ||||||
|         _template: |  | ||||||
|           data: "{{ source_registries }}" |  | ||||||
|           hv: |  | ||||||
|             fqdn: "{{ vapp['metacluster.fqdn'] }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201, 401] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Upgrade gitea chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: gitea |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/gitea |  | ||||||
|         release_namespace: gitea |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['gitea'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure gitea API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://git.{{ vapp['metacluster.fqdn'] }}/api/healthz |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.status is defined |  | ||||||
|         - api_readycheck.json.status == 'pass' |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,26 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Upgrade argo-cd chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: argo-cd |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/argo-cd |  | ||||||
|         release_namespace: argo-cd |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['argo-cd'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure argo-cd API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://gitops.{{ vapp['metacluster.fqdn'] }}/api/version |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.Version is defined |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| - name: Configure fallback name resolution |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /etc/hosts |  | ||||||
|     line: "{{ vapp['metacluster.vip'] }}  {{ item ~ '.' ~ vapp['metacluster.fqdn'] }}" |  | ||||||
|     state: present |  | ||||||
|   loop: |  | ||||||
|     # TODO: Make this list dynamic |  | ||||||
|     - ca |  | ||||||
|     - git |  | ||||||
|     - gitops |  | ||||||
|     - ingress |  | ||||||
|     - registry |  | ||||||
|     - storage |  | ||||||
|  |  | ||||||
| - name: Retrieve root CA certificate |  | ||||||
|   ansible.builtin.uri: |  | ||||||
|     url: https://ca.{{ vapp['metacluster.fqdn'] }}/roots |  | ||||||
|     validate_certs: no |  | ||||||
|     method: GET |  | ||||||
|     status_code: [200, 201] |  | ||||||
|   register: rootca_certificate |  | ||||||
|  |  | ||||||
| - name: Store root CA certificate |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: /usr/local/share/ca-certificates/root_ca.crt |  | ||||||
|     content: "{{ rootca_certificate.json.crts | list | join('\n') }}" |  | ||||||
|  |  | ||||||
| - name: Update certificate truststore |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: update-ca-certificates |  | ||||||
|  |  | ||||||
| - name: Remove redundant files |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /var/lib/rancher/k3s/server/manifests/traefik-config.yaml |  | ||||||
|     state: absent |  | ||||||
| @@ -1,80 +0,0 @@ | |||||||
| - name: Store custom configuration files |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ item.filename }}" |  | ||||||
|     content: "{{ item.content }}" |  | ||||||
|   loop: |  | ||||||
|     - filename: /etc/rancher/k3s/config.yaml |  | ||||||
|       content: | |  | ||||||
|         kubelet-arg: |  | ||||||
|           - "config=/etc/rancher/k3s/kubelet.config" |  | ||||||
|     - filename: /etc/rancher/k3s/kubelet.config |  | ||||||
|       content: | |  | ||||||
|         apiVersion: kubelet.config.k8s.io/v1beta1 |  | ||||||
|         kind: KubeletConfiguration |  | ||||||
|  |  | ||||||
|         shutdownGracePeriod: 180s |  | ||||||
|         shtudownGracePeriodCriticalPods: 60s |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.filename }}" |  | ||||||
|  |  | ||||||
| - name: Gather service facts |  | ||||||
|   ansible.builtin.service_facts: |  | ||||||
|     # Module requires no attributes |  | ||||||
|  |  | ||||||
| - name: Install K3s |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: ./install.sh |  | ||||||
|     chdir: /opt/metacluster/k3s |  | ||||||
|   environment: |  | ||||||
|     INSTALL_K3S_SKIP_DOWNLOAD: 'true' |  | ||||||
|     # To prevent from overwriting traefik's existing configuration, "disable" it on this new node |  | ||||||
|     INSTALL_K3S_EXEC: "server --token {{ vapp['metacluster.token'] | trim }} --server https://{{ vapp['metacluster.vip'] }}:6443 --disable local-storage,traefik --config /etc/rancher/k3s/config.yaml" |  | ||||||
|   when: ansible_facts.services['k3s.service'] is undefined |  | ||||||
|  |  | ||||||
| - name: Ensure API availability |  | ||||||
|   ansible.builtin.uri: |  | ||||||
|     url: https://{{ vapp['guestinfo.ipaddress'] }}:6443/livez?verbose |  | ||||||
|     method: GET |  | ||||||
|     validate_certs: no |  | ||||||
|     status_code: [200, 401] |  | ||||||
|   register: api_readycheck |  | ||||||
|   until: api_readycheck.json.apiVersion is defined |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
|  |  | ||||||
| - name: Install kubectl tab-completion |  | ||||||
|   ansible.builtin.shell: |  | ||||||
|     cmd: kubectl completion bash | tee /etc/bash_completion.d/kubectl |  | ||||||
|  |  | ||||||
| - name: Initialize tempfile |  | ||||||
|   ansible.builtin.tempfile: |  | ||||||
|     state: file |  | ||||||
|   register: kubeconfig |  | ||||||
|  |  | ||||||
| - name: Retrieve kubeconfig |  | ||||||
|   ansible.builtin.command: |  | ||||||
|     cmd: kubectl config view --raw |  | ||||||
|   register: kubectl_config |  | ||||||
|  |  | ||||||
| - name: Store kubeconfig in tempfile |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     dest: "{{ kubeconfig.path }}" |  | ||||||
|     content: "{{ kubectl_config.stdout }}" |  | ||||||
|     mode: 0600 |  | ||||||
|   no_log: true |  | ||||||
|  |  | ||||||
| - name: Add label to node object |  | ||||||
|   kubernetes.core.k8s: |  | ||||||
|     name: "{{ ansible_facts.nodename | lower }}" |  | ||||||
|     kind: Node |  | ||||||
|     state: patched |  | ||||||
|     definition: |  | ||||||
|       metadata: |  | ||||||
|         labels: |  | ||||||
|           ova.airgappedk8s/moref_id: "{{ moref_id }}" |  | ||||||
|     kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|   register: k8snode_patch |  | ||||||
|   until: |  | ||||||
|     - k8snode_patch.result.metadata.labels['ova.airgappedk8s/moref_id'] is defined |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
| @@ -1,9 +0,0 @@ | |||||||
| - import_tasks: init.yml |  | ||||||
| - import_tasks: containerimages.yml |  | ||||||
| - import_tasks: k3s.yml |  | ||||||
| - import_tasks: assets.yml |  | ||||||
| - import_tasks: storage.yml |  | ||||||
| - import_tasks: registry.yml |  | ||||||
| - import_tasks: certauthority.yml |  | ||||||
| - import_tasks: git.yml |  | ||||||
| - import_tasks: gitops.yml |  | ||||||
| @@ -1,27 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Upgrade harbor chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: harbor |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/harbor |  | ||||||
|         release_namespace: harbor |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['harbor'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure harbor API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://registry.{{ vapp['metacluster.fqdn'] }}/api/v2.0/health |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck.json.status is defined |  | ||||||
|         - api_readycheck.json.status == 'healthy' |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201, 401] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,53 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Increase replicas for each volume |  | ||||||
|       kubernetes.core.k8s: |  | ||||||
|         api_version: longhorn.io/v1beta2 |  | ||||||
|         kind: volume |  | ||||||
|         name: "{{ item.metadata.name }}" |  | ||||||
|         namespace: longhorn-system |  | ||||||
|         state: patched |  | ||||||
|         definition: | |  | ||||||
|           spec: |  | ||||||
|             numberOfReplicas: {{ lookup('kubernetes.core.k8s', kind='node', kubeconfig=(kubeconfig.path)) | length | int }} |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|       loop: "{{ query('kubernetes.core.k8s', api_version='longhorn.io/v1beta2', kind='volume', namespace='longhorn-system', kubeconfig=(kubeconfig.path)) }}" |  | ||||||
|       loop_control: |  | ||||||
|         label: "{{ item.metadata.name }}" |  | ||||||
|  |  | ||||||
|     - name: Wait for replica rebuilds to complete |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://storage.{{ vapp['metacluster.fqdn'] }}/v1/volumes |  | ||||||
|         method: GET |  | ||||||
|       register: volume_details |  | ||||||
|       until: |  | ||||||
|         - volume_details.json is defined |  | ||||||
|         - (volume_details.json | json_query('data[? state==`attached`].robustness') | unique | length) == 1 |  | ||||||
|         - (volume_details.json | json_query('data[? state==`attached`].robustness') | first) == "healthy" |  | ||||||
|       retries: "{{ ( playbook.retries * 2) | int }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|     - name: Upgrade longhorn chart |  | ||||||
|       kubernetes.core.helm: |  | ||||||
|         name: longhorn |  | ||||||
|         chart_ref: /opt/metacluster/helm-charts/longhorn |  | ||||||
|         release_namespace: longhorn-system |  | ||||||
|         wait: false |  | ||||||
|         kubeconfig: "{{ kubeconfig.path }}" |  | ||||||
|         values: "{{ components['longhorn'].chart_values }}" |  | ||||||
|  |  | ||||||
|     - name: Ensure longhorn API availability |  | ||||||
|       ansible.builtin.uri: |  | ||||||
|         url: https://storage.{{ vapp['metacluster.fqdn'] }}/v1 |  | ||||||
|         method: GET |  | ||||||
|       register: api_readycheck |  | ||||||
|       until: |  | ||||||
|         - api_readycheck is not failed |  | ||||||
|       retries: "{{ playbook.retries }}" |  | ||||||
|       delay: "{{ (storage_benchmark | int) * (playbook.delay.long | int) }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,3 +0,0 @@ | |||||||
| - import_tasks: vapp.yml |  | ||||||
| - import_tasks: vcenter.yml |  | ||||||
| - import_tasks: metacluster.yml |  | ||||||
| @@ -1,11 +0,0 @@ | |||||||
| - name: Check for metacluster connectivity |  | ||||||
|   ansible.builtin.uri: |  | ||||||
|     url: https://{{ vapp['metacluster.vip'] }}:6443/livez?verbose |  | ||||||
|     method: GET |  | ||||||
|     validate_certs: no |  | ||||||
|     status_code: [200, 401] |  | ||||||
|   register: api_readycheck |  | ||||||
|   until: |  | ||||||
|     - api_readycheck.json.apiVersion is defined |  | ||||||
|   retries: "{{ playbook.retries }}" |  | ||||||
|   delay: "{{ (storage_benchmark | int) * (playbook.delay.medium | int) }}" |  | ||||||
| @@ -1,20 +0,0 @@ | |||||||
| - name: Check for expected vApp properties |  | ||||||
|   ansible.builtin.assert: |  | ||||||
|     that: |  | ||||||
|       - vapp[item] is defined |  | ||||||
|       - (vapp[item] | length) > 0 |  | ||||||
|     quiet: true |  | ||||||
|   loop: |  | ||||||
|     - guestinfo.dnsserver |  | ||||||
|     - guestinfo.gateway |  | ||||||
|     - guestinfo.hostname |  | ||||||
|     - guestinfo.ipaddress |  | ||||||
|     - guestinfo.prefixlength |  | ||||||
|     - guestinfo.rootsshkey |  | ||||||
|     - hv.fqdn |  | ||||||
|     - hv.password |  | ||||||
|     - hv.username |  | ||||||
|     - metacluster.fqdn |  | ||||||
|     - metacluster.password |  | ||||||
|     - metacluster.token |  | ||||||
|     - metacluster.vip |  | ||||||
| @@ -1 +0,0 @@ | |||||||
| # ... |  | ||||||
| @@ -1,57 +0,0 @@ | |||||||
| - 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 }}" |  | ||||||
| @@ -1,4 +0,0 @@ | |||||||
| - import_tasks: hypervisor.yml |  | ||||||
| - import_tasks: registry.yml |  | ||||||
| - import_tasks: nodetemplates.yml |  | ||||||
| # - import_tasks: clusterapi.yml |  | ||||||
| @@ -1,73 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|     - name: Check for existing template on hypervisor |  | ||||||
|       community.vmware.vmware_guest_info: |  | ||||||
|         name: "{{ (filename | basename | split('.'))[:-1] | join('.') }}" |  | ||||||
|       register: existing_ova |  | ||||||
|       ignore_errors: yes |  | ||||||
|  |  | ||||||
|     - name: Store inventory path of existing template |  | ||||||
|       ansible.builtin.set_fact: |  | ||||||
|         nodetemplate_inventorypath: "{{ existing_ova.instance.hw_folder ~ '/' ~ existing_ova.instance.hw_name }}" |  | ||||||
|       when: existing_ova is not failed |  | ||||||
|  |  | ||||||
|     - block: |  | ||||||
|  |  | ||||||
|         - name: Parse OVA file for network mappings |  | ||||||
|           ansible.builtin.shell: |  | ||||||
|             cmd: govc import.spec -json {{ filename }} |  | ||||||
|           environment: |  | ||||||
|             GOVC_INSECURE: '1' |  | ||||||
|             GOVC_URL: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|             GOVC_USERNAME: "{{ vapp['hv.username'] }}" |  | ||||||
|             GOVC_PASSWORD: "{{ vapp['hv.password'] }}" |  | ||||||
|           register: ova_spec |  | ||||||
|  |  | ||||||
|         - name: Deploy OVA template on hypervisor |  | ||||||
|           community.vmware.vmware_deploy_ovf: |  | ||||||
|             cluster: "{{ vcenter_info.cluster }}" |  | ||||||
|             datastore: "{{ vcenter_info.datastore }}" |  | ||||||
|             name: "{{ (filename | basename | split('.'))[:-1] | join('.') }}" |  | ||||||
|             networks: "{u'{{ ova_spec.stdout | from_json | json_query('NetworkMapping[0].Name') }}':u'{{ vcenter_info.network }}'}" |  | ||||||
|             allow_duplicates: no |  | ||||||
|             power_on: false |  | ||||||
|             ovf: "{{ filename }}" |  | ||||||
|           register: ova_deploy |  | ||||||
|  |  | ||||||
|         - name: Add additional placeholder disk |  | ||||||
|           community.vmware.vmware_guest_disk: |  | ||||||
|             name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|             disk: |  | ||||||
|               - size: 1Gb |  | ||||||
|                 scsi_controller: 1 |  | ||||||
|                 scsi_type: paravirtual |  | ||||||
|                 unit_number: 0 |  | ||||||
|  |  | ||||||
|         # Disabled to allow disks to be resized; at the cost of cloning speed |  | ||||||
|         # - name: Create snapshot on deployed VM |  | ||||||
|         #   community.vmware.vmware_guest_snapshot: |  | ||||||
|         #     name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|         #     state: present |  | ||||||
|         #     snapshot_name: "{{ ansible_date_time.iso8601_basic_short }}-base" |  | ||||||
|  |  | ||||||
|         - name: Mark deployed VM as templates |  | ||||||
|           community.vmware.vmware_guest: |  | ||||||
|             name: "{{ ova_deploy.instance.hw_name }}" |  | ||||||
|             is_template: yes |  | ||||||
|  |  | ||||||
|         - name: Store inventory path of deployed template |  | ||||||
|           ansible.builtin.set_fact: |  | ||||||
|             nodetemplate_inventorypath: "{{ ova_deploy.instance.hw_folder ~ '/' ~ ova_deploy.instance.hw_name }}" |  | ||||||
|  |  | ||||||
|       when: existing_ova is failed |  | ||||||
|  |  | ||||||
|   vars: |  | ||||||
|     filename: "{{ query('ansible.builtin.fileglob', '/opt/metacluster/node-templates/*.ova') | first }}" |  | ||||||
|   module_defaults: |  | ||||||
|     group/vmware: |  | ||||||
|       hostname: "{{ vapp['hv.fqdn'] }}" |  | ||||||
|       validate_certs: no |  | ||||||
|       username: "{{ vapp['hv.username'] }}" |  | ||||||
|       password: "{{ vapp['hv.password'] }}" |  | ||||||
|       datacenter: "{{ vcenter_info.datacenter }}" |  | ||||||
|       folder: "{{ vcenter_info.folder }}" |  | ||||||
| @@ -1,17 +0,0 @@ | |||||||
| - block: |  | ||||||
|  |  | ||||||
|   - 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: "{{ lookup('ansible.builtin.file', '/opt/metacluster/cluster-api/imagelist').splitlines() }}" |  | ||||||
|  |  | ||||||
|   module_defaults: |  | ||||||
|     ansible.builtin.uri: |  | ||||||
|       validate_certs: no |  | ||||||
|       status_code: [200, 201, 409] |  | ||||||
|       body_format: json |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| - name: Create destination folder |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /opt/firstboot |  | ||||||
|     state: directory |  | ||||||
|  |  | ||||||
| - name: Create firstboot script file |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: firstboot.j2 |  | ||||||
|     dest: /opt/firstboot/firstboot.sh |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: o+x |  | ||||||
|  |  | ||||||
| - name: Create @reboot crontab job |  | ||||||
|   ansible.builtin.cron: |  | ||||||
|     name: firstboot |  | ||||||
|     special_time: reboot |  | ||||||
|     job: "/opt/firstboot/firstboot.sh >/dev/tty1 2>&1" |  | ||||||
|  |  | ||||||
| - name: Copy payload folder (common) |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     src: ansible_payload/common/ |  | ||||||
|     dest: /opt/firstboot/ansible/ |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: '0644' |  | ||||||
|  |  | ||||||
| - name: Copy payload folder (per appliancetype) |  | ||||||
|   ansible.builtin.copy: |  | ||||||
|     src: ansible_payload/{{ appliancetype }}/ |  | ||||||
|     dest: /opt/firstboot/ansible/ |  | ||||||
|     owner: root |  | ||||||
|     group: root |  | ||||||
|     mode: '0644' |  | ||||||
| @@ -1,10 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
|  |  | ||||||
| # Workaround for ansible output regression |  | ||||||
| export PYTHONUNBUFFERED=1 |  | ||||||
|  |  | ||||||
| # Apply firstboot configuration w/ ansible |  | ||||||
| /usr/local/bin/ansible-playbook /opt/firstboot/ansible/playbook.yml | tee -a /var/log/firstboot.log > /dev/tty1 2>&1 |  | ||||||
|  |  | ||||||
| # Cleanup console |  | ||||||
| clear > /dev/tty1 |  | ||||||
| @@ -1,13 +0,0 @@ | |||||||
| - name: Delete cloud-init package |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: cloud-init |  | ||||||
|     state: absent |  | ||||||
|     purge: yes |  | ||||||
|  |  | ||||||
| - name: Delete cloud-init files |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: "{{ item }}" |  | ||||||
|     state: absent |  | ||||||
|   loop: |  | ||||||
|     - /etc/cloud |  | ||||||
|     - /var/lib/cloud |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| - name: Enable crontab logging |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /etc/rsyslog.d/50-default.conf |  | ||||||
|     regexp: '^#cron\.\*.*' |  | ||||||
|     line: "cron.*\t\t\t\t./var/log/cron.log" |  | ||||||
| @@ -1,7 +0,0 @@ | |||||||
| - import_tasks: tty.yml |  | ||||||
| - import_tasks: snapd.yml |  | ||||||
| - import_tasks: cloud-init.yml |  | ||||||
| - import_tasks: logging.yml |  | ||||||
| - import_tasks: services.yml |  | ||||||
| - import_tasks: packages.yml |  | ||||||
| - import_tasks: sysctl.yml |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| - name: Configure 'needrestart' package |  | ||||||
|   ansible.builtin.lineinfile: |  | ||||||
|     path: /etc/needrestart/needrestart.conf |  | ||||||
|     regexp: "{{ item.regexp }}" |  | ||||||
|     line: "{{ item.line }}" |  | ||||||
|   loop: |  | ||||||
|     - regexp: "^#\\$nrconf\\{restart\\} = 'i';" |  | ||||||
|       line: "$nrconf{restart} = 'a';" |  | ||||||
|     - regexp: "^#\\$nrconf\\{kernelhints\\} = -1;" |  | ||||||
|       line: "$nrconf{kernelhints} = -1;" |  | ||||||
|   loop_control: |  | ||||||
|     label: "{{ item.line }}" |  | ||||||
|  |  | ||||||
| - name: Install additional packages |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     pkg: "{{ packages.apt }}" |  | ||||||
|     state: latest |  | ||||||
|     update_cache: yes |  | ||||||
|     install_recommends: no |  | ||||||
|  |  | ||||||
| - name: Upgrade all packages |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     name: '*' |  | ||||||
|     state: latest |  | ||||||
|     update_cache: yes |  | ||||||
|  |  | ||||||
| - name: Install additional python packages |  | ||||||
|   ansible.builtin.pip: |  | ||||||
|     name: "{{ item }}" |  | ||||||
|     executable: pip3 |  | ||||||
|     state: latest |  | ||||||
|   loop: "{{ packages.pip }}" |  | ||||||
|  |  | ||||||
| - name: Create folder |  | ||||||
|   ansible.builtin.file: |  | ||||||
|     path: /etc/ansible |  | ||||||
|     state: directory |  | ||||||
|  |  | ||||||
| - name: Configure Ansible defaults |  | ||||||
|   ansible.builtin.template: |  | ||||||
|     src: ansible.j2 |  | ||||||
|     dest: /etc/ansible/ansible.cfg |  | ||||||
|  |  | ||||||
| - name: Cleanup |  | ||||||
|   ansible.builtin.apt: |  | ||||||
|     autoremove: yes |  | ||||||
|     purge: yes |  | ||||||
| @@ -1,5 +0,0 @@ | |||||||
| - name: Disable & mask networkd-wait-online |  | ||||||
|   ansible.builtin.systemd: |  | ||||||
|     name: systemd-networkd-wait-online |  | ||||||
|     enabled: no |  | ||||||
|     masked: yes |  | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user