Compare commits
376 Commits
Windows10
...
deb524d1f5
| Author | SHA1 | Date | |
|---|---|---|---|
| deb524d1f5 | |||
| 3674862ff4 | |||
| 08a543e27f | |||
| 0fd4cbb92f | |||
| 6c31038b1a | |||
| fdead3c41c | |||
| 3efee69602 | |||
| 0c8272c9e4 | |||
| fcb05e2e12 | |||
| 6de8ea3029 | |||
| 4b5acf5e95 | |||
| 5c68b87d67 | |||
| e538fce0f8 | |||
| b67bc43a70 | |||
| 78c1d7fb54 | |||
| ab5f082933 | |||
| e3f44fab0a | |||
| f68189e3b7 | |||
| f3224416cb | |||
| 96ee96b470 | |||
| a20cb4417c | |||
| 433a231487 | |||
| b890a03760 | |||
| 92eee0744e | |||
| 83ce1be8bf | |||
| a364a7c359 | |||
| edca98549c | |||
| 146887e9e1 | |||
| 9bfa6bf658 | |||
| b9575d2de4 | |||
| e249498109 | |||
| 01a1c0bf0a | |||
| c27712bc20 | |||
| 2d99511360 | |||
| 46a927b777 | |||
| c9a8598a35 | |||
| 0d7b1ab269 | |||
| 4786507366 | |||
| ed4c1145b6 | |||
| 3aa44e0f83 | |||
| 3a48676ca7 | |||
| 44daf9191a | |||
| 83ee632ff9 | |||
| be562f0124 | |||
| f711908ddb | |||
| 6f7b8e99f2 | |||
| 6261bfdda7 | |||
| 5751e7200c | |||
| 6ce1a66d3e | |||
| 85fb68b2e0 | |||
| b47dda7a50 | |||
| 838c7b6361 | |||
| 2ca91b5dea | |||
| 42d79a95ca | |||
| 1f4bbca7ec | |||
| fe8700f300 | |||
| ac4b011e83 | |||
| 7ca9d20b65 | |||
| 0f79832d96 | |||
| 8926b72344 | |||
| 5985615868 | |||
| 4655fe7465 | |||
| 15622d8a21 | |||
| 5c75452315 | |||
| f27dea92e3 | |||
| 67ec47b2b3 | |||
| c6170436f4 | |||
| 5b4eb2e443 | |||
| 68a1534d9c | |||
| e656780f56 | |||
| 464ed497fe | |||
| eb46c384a8 | |||
| 78526527bb | |||
| 22c06e2388 | |||
| 09c4a17050 | |||
| 35ced380a4 | |||
| 9199809da5 | |||
| 806bf24fc0 | |||
| 4733d8e5f8 | |||
| 65346db100 | |||
| 8eb85e4b11 | |||
| 716818c23c | |||
| f4d32d7828 | |||
| c44b40568d | |||
| 67676ff03b | |||
| 204faa7415 | |||
| 35a5656c59 | |||
| 3fe83457ea | |||
| 3c11ce5dde | |||
| 7a1b563851 | |||
| 0bddae0440 | |||
| 8181ae4017 | |||
| ac3f162dd4 | |||
| aa5c45e6e6 | |||
| a67ef0e1bd | |||
| 1794b24998 | |||
| 7c7333690d | |||
| 7b17b8ad63 | |||
| 1141225907 | |||
| 6c4fe7a0e6 | |||
| 8d13b527be | |||
| d8299ee90c | |||
| b34ac733f4 | |||
| 9f2e6ee160 | |||
| 042b9eb36f | |||
| 2097dec958 | |||
| 0c1fca9643 | |||
| b0dad1caf7 | |||
| 2cd2c4c6d0 | |||
| bd0b74ba19 | |||
| 521b323de2 | |||
| 35b3d5d3b9 | |||
| 675dce4160 | |||
| bd7c1f92e8 | |||
| 7d837a1711 | |||
| e1b57cfdea | |||
| 84d644db67 | |||
| 5cffb61544 | |||
| 1083937d5d | |||
| e52c63f80c | |||
| c7579ea4a6 | |||
| fba2e3e4b1 | |||
| 1c43bb19d2 | |||
| 9a3898e0b8 | |||
| a3da5b8f93 | |||
| 5f02ddab49 | |||
| 585e39cb97 | |||
| 1cd7e1510f | |||
| 0534b031fa | |||
| c8509aa3d5 | |||
| 158af986c3 | |||
| 5e537966f6 | |||
| 3849b79493 | |||
| 5f1d1bfa8a | |||
| fe306bd845 | |||
| ccbd4ed984 | |||
| fdc5c44e6a | |||
| c57291af6d | |||
| d652cf0346 | |||
| a1b8837cc5 | |||
| 5b7b93dd30 | |||
| d89ccd57da | |||
| 53da641926 | |||
| a3e9bc659a | |||
| fc51bf3f94 | |||
| 3d96f8c13b | |||
| 488fe10e1e | |||
| 01e168a7f9 | |||
| c48f27c42e | |||
| 185b332764 | |||
| e89505bef6 | |||
| b763d2b562 | |||
| d607f615e9 | |||
| ed7a474dbb | |||
| 14c6720196 | |||
| 277c91eeba | |||
| c9f3c648b7 | |||
| 8e680c45be | |||
| 7440d5824c | |||
| 8e75925b52 | |||
| d6234321d9 | |||
| ea20b1290c | |||
| d986d5ab25 | |||
| c29728594c | |||
| 10d5d6f389 | |||
| 96dccef450 | |||
| 05e0c50217 | |||
| 261e91ee2e | |||
| 1746af9b9d | |||
| 7c2ff54019 | |||
| 193ce9a534 | |||
| 9e91bef7b7 | |||
| 05b30287bd | |||
| 54caff8fb6 | |||
| 2f976898eb | |||
| 44befeda4b | |||
| 81847d3b93 | |||
| 39cc83ac57 | |||
| 0263b2dfc4 | |||
| e7e3b69d95 | |||
| b6ac086a31 | |||
| 20ce62fb6d | |||
| 0918eb36fe | |||
| 93e7d4dc9b | |||
| 9a0a33816c | |||
| eeb1364f1b | |||
| f04095db8c | |||
| 2847542976 | |||
| 929186d123 | |||
| d6c885240a | |||
| 0b97ae2fc5 | |||
| abacbf90ce | |||
| 243cf426d7 | |||
| 64b7ea45c0 | |||
| 3a2dbe572e | |||
| 2be42989e5 | |||
| cb97703406 | |||
| 16df0b65fc | |||
| 847b255e3b | |||
| d005697438 | |||
| ab010643df | |||
| e17cd1b633 | |||
| 504764af10 | |||
| 405fb5938f | |||
| 77e0f7b7cb | |||
| 7fb0e80537 | |||
| fb8b9b735f | |||
| 86e99b1515 | |||
| 952e92082f | |||
| 33e0220e34 | |||
| a51d922f00 | |||
| b441717ee1 | |||
| b7da591571 | |||
| fa0fa30062 | |||
| dd4e79901e | |||
| 1fcaa4b212 | |||
| 164fd15c60 | |||
| 241551169a | |||
| a2b20f49cc | |||
| fe8765ded7 | |||
| caf45b5270 | |||
| 9ba2df08cd | |||
| 9458f49744 | |||
| 369aaaa0b5 | |||
| 6220e2a9aa | |||
| e3e46bae7d | |||
| 6e6e7900da | |||
| 6c329a36e9 | |||
| f33f2912f1 | |||
| 9541942c23 | |||
| 2f937aded7 | |||
| 95dea97382 | |||
| a840306245 | |||
| bbd103d527 | |||
| b2ceee8720 | |||
| d5c886f02b | |||
| 1d59cd4b3c | |||
| f2d9147291 | |||
| bc9f1c260f | |||
| 368f84769b | |||
| 51366476cc | |||
| dcbaf6b807 | |||
| 5dfc3a7813 | |||
| 0989d0c586 | |||
| 8a83f47572 | |||
| a3bbf88ce3 | |||
| 5e0cebf733 | |||
| 00e3266360 | |||
| c6a8f9f7bd | |||
| 4f1231f973 | |||
| 049bedbd8f | |||
| 0e7cfa0934 | |||
| 5435f73402 | |||
| 6917e0799a | |||
| 4616b9b070 | |||
| 8c741dc120 | |||
| 8cbfcb016b | |||
| 4ba7b590ba | |||
| 52660e1414 | |||
| 0ab6aaeaa5 | |||
| 02c26b2465 | |||
| 1842a08a39 | |||
| 0c01f024e9 | |||
| 40489ff373 | |||
| c491066384 | |||
| 4c054cc434 | |||
| dcbe6c397f | |||
| cb84a02b6f | |||
| 8f432d3353 | |||
| 1cdbcaccaf | |||
| f1c6161bcb | |||
| 123518a787 | |||
| 2ec6a756b7 | |||
| a1779be079 | |||
| 8ed9b2f754 | |||
| 72202d9f21 | |||
| 9eb5fbd0a3 | |||
| c58ede04c4 | |||
| 662e8984c3 | |||
| b7abf25907 | |||
| 18fa7742fa | |||
| f6993c2052 | |||
| 59d1730ca5 | |||
| b087203cfb | |||
| d39d594bf0 | |||
| 487239365e | |||
| 6ea03d152c | |||
| 01991435ae | |||
| a64b5b2325 | |||
| 38d7442025 | |||
| cf91519076 | |||
| bae044e145 | |||
| f39b4bbb62 | |||
| 9739c51100 | |||
| 0df98d4341 | |||
| fc23dc068d | |||
| 4d78d65ad8 | |||
| c1440d9dcd | |||
| 4a5f390ae1 | |||
| e0a5b5a5da | |||
| 081aaaaa19 | |||
| 2bd0f8df0a | |||
| 2c57dbcddc | |||
| 0f01e803f2 | |||
| bd82e13fc4 | |||
| 2f902fa27c | |||
| 37ecd4a1b9 | |||
| 8a8cb09984 | |||
| bc46b09708 | |||
| d508b28213 | |||
| 03ed59680f | |||
| 40ade38c78 | |||
| c89edd3ee9 | |||
| e5880c222e | |||
| 236db40016 | |||
| b340c777ba | |||
| 10624f8c90 | |||
| eca6ae515e | |||
| b6656c3d9c | |||
| 82b8eeca4f | |||
| 5af4d729ef | |||
| 73c266632c | |||
| cd448a0af3 | |||
| 6b1db0dd23 | |||
| f15485e7c2 | |||
| 4257849ca4 | |||
| 3426cd7ed3 | |||
| 226fa9859b | |||
| 7e36abe0cb | |||
| 1e470f38dd | |||
| 389c35bb05 | |||
| f40889370d | |||
| 990534618b | |||
| c0953acefe | |||
| b33280b443 | |||
| 9460bc9bd6 | |||
| 5f835960b9 | |||
| 35c2df5f4e | |||
| fcdc7d07ad | |||
| 998f5ef381 | |||
| a9041b19a4 | |||
| 0a2647d465 | |||
| 93cadce4fe | |||
| 4d7400ed43 | |||
| f8d0c1cdde | |||
| 4ea138fd69 | |||
| d5c3e2c0b6 | |||
| f33a99ad05 | |||
| d50bf402af | |||
| 8adbec57d5 | |||
| 06d0a44c4d | |||
| be9609875a | |||
| 6c27d2e74d | |||
| 346b2878a6 | |||
| 0ff31c104b | |||
| 4bf036c49d | |||
| f6a27db822 | |||
| b9fb3cdb30 | |||
| d95daa1861 | |||
| fcea2ef449 | |||
| d680b0dde4 | |||
| 03b5338f59 | |||
| b7d737e7df | |||
| c4389f4932 | |||
| bfa31fd7f7 | |||
| 94e1624180 | |||
| 64ecc33dcb | |||
| 1da7269d87 | |||
| 50bef57ff7 | |||
| 66e3c01863 | |||
| 7b525a6ea8 | |||
| 6ae9003fec | |||
| 7557a7bfca | |||
| 5501c640fc | |||
| 3f0a8ca3c4 | |||
| 04c9eb4f03 |
38
.drone.yml
38
.drone.yml
@@ -14,54 +14,56 @@ steps:
|
||||
- name: Debugging information
|
||||
image: bv11-cr01.bessems.eu/library/packer-extended
|
||||
commands:
|
||||
- yamllint --version
|
||||
- packer --version
|
||||
- pwsh --version
|
||||
- ansible --version
|
||||
- ovftool --version
|
||||
- name: Windows 10
|
||||
- packer --version
|
||||
- yamllint --version
|
||||
- name: Kubernetes Bootstrap Appliance
|
||||
image: bv11-cr01.bessems.eu/library/packer-extended
|
||||
pull: always
|
||||
commands:
|
||||
- sed -i -e "s/<<img-productkey>>/$${PRODUCTKEY}/" packer/preseed/Windows10/Autounattend.xml
|
||||
- |
|
||||
sed -i -e "s/<<img-password>>/$${WINRM_PASSWORD}/g" \
|
||||
packer/preseed/Windows10/Autounattend.xml \
|
||||
packer/preseed/Windows10/Sysprep_Unattend.xml
|
||||
sed -i -e "s/<<img-password>>/$${SSH_PASSWORD}/g" \
|
||||
packer/preseed/UbuntuServer22.04/user-data
|
||||
- |
|
||||
yamllint -d "{extends: relaxed, rules: {line-length: disable}}" scripts
|
||||
yamllint -d "{extends: relaxed, rules: {line-length: disable}}" \
|
||||
ansible \
|
||||
packer/preseed/UbuntuServer22.04/user-data \
|
||||
scripts
|
||||
- |
|
||||
ansible-galaxy install \
|
||||
-r ansible/requirements.yml
|
||||
- |
|
||||
packer init -upgrade \
|
||||
./packer
|
||||
- |
|
||||
packer validate \
|
||||
-var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \
|
||||
-var vm_guestos=win10 \
|
||||
-var vm_guestos=k8sbootstrap \
|
||||
-var repo_username=$${REPO_USERNAME} \
|
||||
-var repo_password=$${REPO_PASSWORD} \
|
||||
-var vsphere_password=$${VSPHERE_PASSWORD} \
|
||||
-var winrm_password=$${WINRM_PASSWORD} \
|
||||
-var ssh_password=$${SSH_PASSWORD} \
|
||||
./packer
|
||||
- |
|
||||
packer build \
|
||||
-on-error=cleanup \
|
||||
-on-error=cleanup -timestamp-ui \
|
||||
-var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \
|
||||
-var vm_guestos=win10 \
|
||||
-var vm_guestos=k8sbootstrap \
|
||||
-var repo_username=$${REPO_USERNAME} \
|
||||
-var repo_password=$${REPO_PASSWORD} \
|
||||
-var vsphere_password=$${VSPHERE_PASSWORD} \
|
||||
-var winrm_password=$${WINRM_PASSWORD} \
|
||||
-var ssh_password=$${SSH_PASSWORD} \
|
||||
./packer
|
||||
environment:
|
||||
VSPHERE_PASSWORD:
|
||||
from_secret: vsphere_password
|
||||
WINRM_PASSWORD:
|
||||
from_secret: winrm_password
|
||||
SSH_PASSWORD:
|
||||
from_secret: ssh_password
|
||||
REPO_USERNAME:
|
||||
from_secret: repo_username
|
||||
REPO_PASSWORD:
|
||||
from_secret: repo_password
|
||||
PRODUCTKEY:
|
||||
from_secret: prodkey_win10
|
||||
# PACKER_LOG: 1
|
||||
volumes:
|
||||
- name: output
|
||||
|
||||
@@ -1 +1 @@
|
||||
# Packer.Images [](https://ci.spamasaurus.com/djpbessems/Packer.Images)
|
||||
# Packer.Images [](https://ci.spamasaurus.com/djpbessems/Packer.Images)
|
||||
|
||||
3
ansible/ansible.cfg
Normal file
3
ansible/ansible.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
[defaults]
|
||||
deprecation_warnings = False
|
||||
remote_tmp = /tmp/.ansible-${USER}/tmp
|
||||
10
ansible/playbook.yml
Normal file
10
ansible/playbook.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- hosts: all
|
||||
gather_facts: false
|
||||
vars_files:
|
||||
- metacluster.yml
|
||||
become: true
|
||||
roles:
|
||||
- os
|
||||
- firstboot
|
||||
- assets
|
||||
4
ansible/requirements.yml
Normal file
4
ansible/requirements.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
collections:
|
||||
- ansible.utils
|
||||
- community.general
|
||||
- kubernetes.core
|
||||
49
ansible/roles/assets/tasks/containerimages.yml
Normal file
49
ansible/roles/assets/tasks/containerimages.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
- name: Parse 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: parsedmanifests
|
||||
loop: "{{ clusterapi_manifests.results }}"
|
||||
loop_control:
|
||||
label: "{{ item.dest | basename }}"
|
||||
|
||||
- name: Parse helm charts for container images
|
||||
ansible.builtin.shell:
|
||||
cmd: "{{ item.value.helm.parse_logic }}"
|
||||
chdir: /opt/metacluster/helm-charts/{{ item.key }}
|
||||
register: chartimages
|
||||
when: item.value.helm is defined
|
||||
loop: "{{ lookup('ansible.builtin.dict', components) }}"
|
||||
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 | json_query('results[*].stdout_lines') | select() | flatten | list }}"
|
||||
- source: kubeadm
|
||||
results: "{{ kubeadmimages.stdout_lines }}"
|
||||
- source: manifests
|
||||
results: "{{ parsedmanifests | json_query('results[*].stdout_lines') | select() | flatten | list }}"
|
||||
loop_control:
|
||||
label: "{{ item.source }}"
|
||||
|
||||
- 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_manifests + containerimages_kubeadm + dependencies.container_images) | flatten | unique | sort }}"
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
- 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) }}"
|
||||
|
||||
- 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
|
||||
50
ansible/roles/assets/tasks/dependencies.yml
Normal file
50
ansible/roles/assets/tasks/dependencies.yml
Normal file
@@ -0,0 +1,50 @@
|
||||
- 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
|
||||
loop: "{{ dependencies.static_binaries | selectattr('archive', 'undefined') }}"
|
||||
loop_control:
|
||||
label: "{{ item.filename }}"
|
||||
|
||||
- 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
|
||||
5
ansible/roles/assets/tasks/git.yml
Normal file
5
ansible/roles/assets/tasks/git.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: Clone git repository
|
||||
ansible.builtin.git:
|
||||
repo: "{{ platform.gitops.repository.uri }}"
|
||||
version: "{{ platform.gitops.repository.revision }}"
|
||||
dest: /opt/metacluster/git-repositories/gitops
|
||||
19
ansible/roles/assets/tasks/helm.yml
Normal file
19
ansible/roles/assets/tasks/helm.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
- name: Add helm repositories
|
||||
kubernetes.core.helm_repository:
|
||||
name: "{{ item.name }}"
|
||||
repo_url: "{{ item.url }}"
|
||||
state: present
|
||||
loop: "{{ platform.helm_repositories }}"
|
||||
|
||||
- name: Fetch helm charts
|
||||
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
|
||||
loop: "{{ lookup('ansible.builtin.dict', components) }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
retries: 5
|
||||
delay: 5
|
||||
until: helmcharts is not failed
|
||||
43
ansible/roles/assets/tasks/k3s.yml
Normal file
43
ansible/roles/assets/tasks/k3s.yml
Normal file
@@ -0,0 +1,43 @@
|
||||
- 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://get.k3s.io
|
||||
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 }}"
|
||||
26
ansible/roles/assets/tasks/kubeadm.yml
Normal file
26
ansible/roles/assets/tasks/kubeadm.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
- 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
|
||||
28
ansible/roles/assets/tasks/main.yml
Normal file
28
ansible/roles/assets/tasks/main.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
- name: Create folder structure(s)
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
loop:
|
||||
- /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/gitops
|
||||
- /opt/metacluster/helm-charts
|
||||
- /opt/metacluster/k3s
|
||||
- /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
|
||||
70
ansible/roles/assets/tasks/manifests.yml
Normal file
70
ansible/roles/assets/tasks/manifests.yml
Normal file
@@ -0,0 +1,70 @@
|
||||
- block:
|
||||
|
||||
- name: Aggregate chart_values into dict
|
||||
ansible.builtin.set_fact:
|
||||
chart_values: "{{ chart_values | default({}) | combine({ (item.key | regex_replace('[^A-Za-z0-9]', '')): { 'chart_values': (item.value.helm.chart_values | from_yaml) } }) }}"
|
||||
when: item.value.helm.chart_values is defined
|
||||
loop: "{{ lookup('ansible.builtin.dict', components) }}"
|
||||
loop_control:
|
||||
label: "{{ item.key }}"
|
||||
|
||||
- name: Write dict to vars_file
|
||||
ansible.builtin.copy:
|
||||
dest: /opt/firstboot/ansible/vars/metacluster.yml
|
||||
content: "{{ { 'components': (chart_values | combine({ 'clusterapi': components.clusterapi })) } | to_nice_yaml(indent=2, width=4096) }}"
|
||||
|
||||
- name: Download ClusterAPI 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: 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: "{{ lookup('ansible.builtin.dict', components) | map(attribute='value.manifests') | list | select('defined') | flatten }}"
|
||||
# loop_control:
|
||||
# label: "{{ item.type + '/' + item.name }}"
|
||||
4
ansible/roles/assets/tasks/nodetemplates.yml
Normal file
4
ansible/roles/assets/tasks/nodetemplates.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
- 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.name }}
|
||||
8
ansible/roles/assets/templates/helmchartconfig.j2
Normal file
8
ansible/roles/assets/templates/helmchartconfig.j2
Normal file
@@ -0,0 +1,8 @@
|
||||
apiVersion: helm.cattle.io/v1
|
||||
kind: HelmChartConfig
|
||||
metadata:
|
||||
name: {{ item.name }}
|
||||
namespace: {{ item.namespace }}
|
||||
spec:
|
||||
valuesContent: |-
|
||||
{{ item.config }}
|
||||
24
ansible/roles/firstboot/files/ansible_payload/playbook.yml
Normal file
24
ansible/roles/firstboot/files/ansible_payload/playbook.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
- hosts: 127.0.0.1
|
||||
connection: local
|
||||
gather_facts: true
|
||||
vars_files:
|
||||
- metacluster.yml
|
||||
# become: true
|
||||
roles:
|
||||
- vapp
|
||||
- network
|
||||
- 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
|
||||
@@ -0,0 +1,4 @@
|
||||
- name: Disable crontab job
|
||||
ansible.builtin.cron:
|
||||
name: firstboot
|
||||
state: absent
|
||||
@@ -0,0 +1,12 @@
|
||||
- import_tasks: service.yml
|
||||
- import_tasks: cron.yml
|
||||
|
||||
- name: Cleanup tempfile
|
||||
ansible.builtin.file:
|
||||
path: "{{ kubeconfig.path }}"
|
||||
state: absent
|
||||
when: kubeconfig.path is defined
|
||||
|
||||
- name: Reboot host
|
||||
ansible.builtin.shell:
|
||||
cmd: /usr/sbin/reboot now
|
||||
@@ -0,0 +1,26 @@
|
||||
- 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 tarball compression service
|
||||
ansible.builtin.systemd:
|
||||
name: compressTarballs
|
||||
enabled: yes
|
||||
@@ -0,0 +1,24 @@
|
||||
- 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: Create filesystem
|
||||
community.general.filesystem:
|
||||
dev: /dev/mapper/longhorn_vg-longhorn_lv
|
||||
fstype: ext4
|
||||
|
||||
- name: Mount dynamic disk
|
||||
ansible.posix.mount:
|
||||
path: /mnt/blockstorage
|
||||
src: /dev/mapper/longhorn_vg-longhorn_lv
|
||||
fstype: ext4
|
||||
state: mounted
|
||||
@@ -0,0 +1,14 @@
|
||||
import netaddr
|
||||
|
||||
def netaddr_iter_iprange(ip_start, ip_end):
|
||||
return [str(ip) for ip in netaddr.iter_iprange(ip_start, ip_end)]
|
||||
|
||||
class FilterModule(object):
|
||||
''' Ansible filter. Interface to netaddr methods.
|
||||
https://pypi.org/project/netaddr/
|
||||
'''
|
||||
|
||||
def filters(self):
|
||||
return {
|
||||
'netaddr_iter_iprange': netaddr_iter_iprange
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
- 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: 5
|
||||
delay: 10
|
||||
until: import_result is not failed
|
||||
@@ -0,0 +1,122 @@
|
||||
- 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: yes
|
||||
wait: yes
|
||||
kubeconfig: "{{ kubeconfig.path }}"
|
||||
values: "{{ components.stepcertificates.chart_values }}"
|
||||
|
||||
- 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
|
||||
# - 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) }}"
|
||||
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: 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
|
||||
config: |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'
|
||||
notify:
|
||||
- Apply manifests
|
||||
|
||||
- name: Trigger handlers
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
- name: Retrieve step-ca configuration
|
||||
kubernetes.core.k8s_info:
|
||||
kind: ConfigMap
|
||||
name: step-certificates-config
|
||||
namespace: step-ca
|
||||
kubeconfig: "{{ kubeconfig.path }}"
|
||||
register: stepca_cm_config
|
||||
|
||||
- name: Install root CA in system truststore
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
step ca bootstrap \
|
||||
--ca-url=https://ca.{{ vapp['metacluster.fqdn'] }} \
|
||||
--fingerprint={{ stepca_cm_config.resources[0].data['defaults.json'] | from_json | json_query('fingerprint') }} \
|
||||
--install \
|
||||
--force
|
||||
update-ca-certificates
|
||||
@@ -0,0 +1,137 @@
|
||||
- block:
|
||||
|
||||
- name: Install gitea chart
|
||||
kubernetes.core.helm:
|
||||
name: gitea
|
||||
chart_ref: /opt/metacluster/helm-charts/gitea
|
||||
release_namespace: gitea
|
||||
create_namespace: yes
|
||||
wait: yes
|
||||
kubeconfig: "{{ kubeconfig.path }}"
|
||||
values: "{{ components.gitea.chart_values }}"
|
||||
|
||||
- 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
|
||||
config: |2
|
||||
entryPoints:
|
||||
- ssh
|
||||
routes:
|
||||
- match: HostSNI(`*`)
|
||||
services:
|
||||
- name: gitea-ssh
|
||||
port: 22
|
||||
notify:
|
||||
- Apply manifests
|
||||
|
||||
- name: Trigger handlers
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
- 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
|
||||
retries: 5
|
||||
delay: 30
|
||||
|
||||
- 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['guestinfo.rootpw'] }}"
|
||||
force_basic_auth: yes
|
||||
body:
|
||||
name: token_init_{{ lookup('password', '/dev/null length=5 chars=ascii_letters,digits') }}
|
||||
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.Config
|
||||
# auto_init: true
|
||||
# default_branch: main
|
||||
description: GitOps manifests
|
||||
- organization: wl
|
||||
body:
|
||||
name: Template.GitOps.Config
|
||||
# auto_init: true
|
||||
# default_branch: main
|
||||
description: GitOps manifests
|
||||
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['guestinfo.rootpw'] | 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
|
||||
@@ -0,0 +1,69 @@
|
||||
- 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: yes
|
||||
wait: yes
|
||||
kubeconfig: "{{ kubeconfig.path }}"
|
||||
values: "{{ components.argocd.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: 5
|
||||
delay: 30
|
||||
|
||||
- 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['guestinfo.rootpw'] }}"
|
||||
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: argocd-gitrepo-metacluster
|
||||
namespace: argo-cd
|
||||
uid: "{{ lookup('ansible.builtin.password', '/dev/null length=5 chars=ascii_lowercase,digits seed=inventory_hostname') }}"
|
||||
privatekey: "{{ lookup('ansible.builtin.file', '~/.ssh/git_rsa_id') | indent(4, true) }}"
|
||||
notify:
|
||||
- Apply manifests
|
||||
|
||||
- name: Create applicationset
|
||||
ansible.builtin.template:
|
||||
src: applicationset.j2
|
||||
dest: /var/lib/rancher/k3s/server/manifests/{{ _template.name }}-manifest.yaml
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0600
|
||||
vars:
|
||||
_template:
|
||||
name: argocd-applicationset-metacluster
|
||||
namespace: argo-cd
|
||||
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
|
||||
@@ -0,0 +1,26 @@
|
||||
- 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
|
||||
config: |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
|
||||
@@ -0,0 +1,13 @@
|
||||
- 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
|
||||
@@ -0,0 +1,55 @@
|
||||
- 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 --disable local-storage'
|
||||
when: ansible_facts.services['k3s.service'] is undefined
|
||||
|
||||
- name: Debug possible taints on k3s node
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
while true;
|
||||
do
|
||||
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints --no-headers | awk '{print strftime("%H:%M:%S"),$0;fflush();}' >> /var/log/taintlog
|
||||
sleep 1
|
||||
done
|
||||
async: 1800
|
||||
poll: 0
|
||||
|
||||
- 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: 5
|
||||
delay: 30
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,10 @@
|
||||
- import_tasks: init.yml
|
||||
- import_tasks: k3s.yml
|
||||
- import_tasks: assets.yml
|
||||
- import_tasks: ingress.yml
|
||||
- import_tasks: storage.yml
|
||||
- import_tasks: certauthority.yml
|
||||
- import_tasks: registry.yml
|
||||
- import_tasks: secrets.yml
|
||||
- import_tasks: git.yml
|
||||
- import_tasks: gitops.yml
|
||||
@@ -0,0 +1,85 @@
|
||||
- block:
|
||||
|
||||
- name: Install harbor chart
|
||||
kubernetes.core.helm:
|
||||
name: harbor
|
||||
chart_ref: /opt/metacluster/helm-charts/harbor
|
||||
release_namespace: harbor
|
||||
create_namespace: yes
|
||||
wait: yes
|
||||
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: 5
|
||||
delay: 30
|
||||
|
||||
- name: Push images to registry
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
skopeo copy \
|
||||
--insecure-policy \
|
||||
--dest-tls-verify=false \
|
||||
--dest-creds admin:{{ vapp['guestinfo.rootpw'] }} \
|
||||
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: 5
|
||||
delay: 10
|
||||
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'] }}"
|
||||
|
||||
- name: Restart kubelet (k3s) to pick up configured registries
|
||||
ansible.builtin.systemd:
|
||||
name: k3s
|
||||
state: restarted
|
||||
|
||||
- name: Ensure k3s API availability
|
||||
ansible.builtin.uri:
|
||||
url: https://{{ vapp['guestinfo.ipaddress'] }}:6443/livez?verbose
|
||||
method: GET
|
||||
register: api_readycheck
|
||||
until: api_readycheck.json.apiVersion is defined
|
||||
retries: 5
|
||||
delay: 30
|
||||
|
||||
module_defaults:
|
||||
ansible.builtin.uri:
|
||||
validate_certs: no
|
||||
status_code: [200, 201, 401]
|
||||
body_format: json
|
||||
@@ -0,0 +1,52 @@
|
||||
- name: Install sealed-secrets chart
|
||||
kubernetes.core.helm:
|
||||
name: sealed-secrets-controller
|
||||
chart_ref: /opt/metacluster/helm-charts/sealed-secrets
|
||||
release_namespace: kube-system
|
||||
wait: yes
|
||||
kubeconfig: "{{ kubeconfig.path }}"
|
||||
# values: "{{ components.sealedsecrets.chart_values }}"
|
||||
|
||||
# - name: Store hypervisor details in configmap/secret
|
||||
# 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) }}"
|
||||
# data: "{{ item.data }}"
|
||||
# loop:
|
||||
# - name: hypervisor-credentials
|
||||
# namespace: kube-system
|
||||
# kind: secret
|
||||
# data:
|
||||
# - key: HV_FQDN
|
||||
# value: "{{ vapp['hv.fqdn'] | b64encode }}"
|
||||
# - key: HV_USERNAME
|
||||
# value: "{{ vapp['hv.username'] | b64encode }}"
|
||||
# - key: HV_PASSWORD
|
||||
# value: "{{ vapp['hv.password'] | b64encode }}"
|
||||
# - name: hypervisor-ippool
|
||||
# namespace: kube-system
|
||||
# kind: configmap
|
||||
# data:
|
||||
# - key: VAPP_MOREF
|
||||
# value: "{{ moref_id }}"
|
||||
# - key: VAPP_IPPOOL_FQDN
|
||||
# value: "{{ vapp['metacluster.fqdn'] }}"
|
||||
# - key: VAPP_IPPOOL_NETWORK
|
||||
# value: "{{ (vapp['guestinfo.ipaddress'] + '/' + vapp['guestinfo.prefixlength']) | ansible.utils.ipaddr('network') }}"
|
||||
# - key: VAPP_IPPOOL_NETMASK
|
||||
# value: "{{ (vapp['guestinfo.ipaddress'] + '/' + vapp['guestinfo.prefixlength']) | ansible.utils.ipaddr('netmask') }}"
|
||||
# - key: VAPP_IPPOOL_DNSSERVER
|
||||
# value: "{{ vapp['guestinfo.dnsserver'] }}"
|
||||
# - key: VAPP_IPPOOL_GATEWAY
|
||||
# value: "{{ vapp['guestinfo.gateway'] }}"
|
||||
# - key: VAPP_IPPOOL_RANGE
|
||||
# value: "{{ vapp['ippool.startip'] + '#' + (vapp['ippool.startip'] | netaddr_iter_iprange(vapp['ippool.endip']) | length | string) }}"
|
||||
# loop_control:
|
||||
# label: "{{ item.kind + '/' + item.name + ' (' + item.namespace + ')' }}"
|
||||
@@ -0,0 +1,26 @@
|
||||
- block:
|
||||
- name: Install longhorn chart
|
||||
kubernetes.core.helm:
|
||||
name: longhorn
|
||||
chart_ref: /opt/metacluster/helm-charts/longhorn
|
||||
release_namespace: longhorn-system
|
||||
create_namespace: yes
|
||||
wait: no
|
||||
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: 5
|
||||
delay: 30
|
||||
|
||||
module_defaults:
|
||||
ansible.builtin.uri:
|
||||
validate_certs: no
|
||||
status_code: [200, 201]
|
||||
body_format: json
|
||||
@@ -0,0 +1,12 @@
|
||||
- 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
|
||||
|
||||
- name: Apply netplan configuration
|
||||
ansible.builtin.shell:
|
||||
cmd: /usr/sbin/netplan apply
|
||||
@@ -0,0 +1,10 @@
|
||||
network:
|
||||
version: 2
|
||||
ethernets:
|
||||
ens192:
|
||||
addresses:
|
||||
- {{ vapp['guestinfo.ipaddress'] }}/{{ vapp['guestinfo.prefixlength'] }}
|
||||
gateway4: {{ vapp['guestinfo.gateway'] }}
|
||||
nameservers:
|
||||
addresses:
|
||||
- {{ vapp['guestinfo.dnsserver'] }}
|
||||
@@ -0,0 +1,20 @@
|
||||
- name: Create folder structure(s)
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
loop:
|
||||
- /opt/firstboot
|
||||
|
||||
- name: Save tty script file
|
||||
ansible.builtin.template:
|
||||
src: tty.j2
|
||||
dest: /opt/firstboot/tty.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0700
|
||||
|
||||
- name: Create @reboot crontab job
|
||||
ansible.builtin.cron:
|
||||
name: tty.consolemessage
|
||||
special_time: reboot
|
||||
job: /opt/firstboot/tty.sh
|
||||
@@ -0,0 +1,39 @@
|
||||
- name: Set root password
|
||||
ansible.builtin.user:
|
||||
name: root
|
||||
password: "{{ vapp['guestinfo.rootpw'] | 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
|
||||
@@ -0,0 +1,38 @@
|
||||
- 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] }}"
|
||||
@@ -0,0 +1,26 @@
|
||||
clusterConfiguration:
|
||||
imageRepository: registry.<fqdn>/library
|
||||
|
||||
files:
|
||||
- [...]
|
||||
- encoding: base64
|
||||
content: |
|
||||
IyEvYmluL2Jhc2gKdm10b29sc2QgLS1jbWQgJ2luZm8tZ2V0IGd1ZXN0aW5mby5vdmZFbnYnID4gL3RtcC9vdmZlbnYKCklQQWRkcmVzcz0kKHNlZCAtbiAncy8uKlByb3BlcnR5IG9lOmtleT0iZ3Vlc3RpbmZvLmludGVyZmFjZS4wLmlwLjAuYWRkcmVzcyIgb2U6dmFsdWU9IlwoW14iXSpcKS4qL1wxL3AnIC90bXAvb3ZmZW52KQpTdWJuZXRNYXNrPSQoc2VkIC1uICdzLy4qUHJvcGVydHkgb2U6a2V5PSJndWVzdGluZm8uaW50ZXJmYWNlLjAuaXAuMC5uZXRtYXNrIiBvZTp2YWx1ZT0iXChbXiJdKlwpLiovXDEvcCcgL3RtcC9vdmZlbnYpCkdhdGV3YXk9JChzZWQgLW4gJ3MvLipQcm9wZXJ0eSBvZTprZXk9Imd1ZXN0aW5mby5pbnRlcmZhY2UuMC5yb3V0ZS4wLmdhdGV3YXkiIG9lOnZhbHVlPSJcKFteIl0qXCkuKi9cMS9wJyAvdG1wL292ZmVudikKRE5TPSQoc2VkIC1uICdzLy4qUHJvcGVydHkgb2U6a2V5PSJndWVzdGluZm8uZG5zLnNlcnZlcnMiIG9lOnZhbHVlPSJcKFteIl0qXCkuKi9cMS9wJyAvdG1wL292ZmVudikKTUFDQWRkcmVzcz0kKHNlZCAtbiAncy8uKnZlOkFkYXB0ZXIgdmU6bWFjPSJcKFteIl0qXCkuKi9cMS9wJyAvdG1wL292ZmVudikKCm1hc2syY2lkcigpIHsKICBjPTAKICB4PTAkKCBwcmludGYgJyVvJyAkezEvLy4vIH0gKQoKICB3aGlsZSBbICR4IC1ndCAwIF07IGRvCiAgICBsZXQgYys9JCgoeCUyKSkgJ3g+Pj0xJwogIGRvbmUKCiAgZWNobyAkYwp9CgpQcmVmaXg9JChtYXNrMmNpZHIgJFN1Ym5ldE1hc2spCgpjYXQgPiAvZXRjL25ldHBsYW4vMDEtbmV0Y2ZnLnlhbWwgPDxFT0YKbmV0d29yazoKICB2ZXJzaW9uOiAyCiAgcmVuZGVyZXI6IG5ldHdvcmtkCiAgZXRoZXJuZXRzOgogICAgaWQwOgogICAgICBzZXQtbmFtZTogZXRoMAogICAgICBtYXRjaDoKICAgICAgICBtYWNhZGRyZXNzOiAkTUFDQWRkcmVzcwogICAgICBhZGRyZXNzZXM6CiAgICAgICAgLSAkSVBBZGRyZXNzLyRQcmVmaXgKICAgICAgZ2F0ZXdheTQ6ICRHYXRld2F5CiAgICAgIG5hbWVzZXJ2ZXJzOgogICAgICAgIGFkZHJlc3NlcyA6IFskRE5TXQpFT0YKcm0gL2V0Yy9uZXRwbGFuLzUwKi55YW1sIC1mCgpzdWRvIG5ldHBsYW4gYXBwbHk=
|
||||
owner: root:root
|
||||
path: /root/network.sh
|
||||
permissions: '0744'
|
||||
- content: |
|
||||
network: {config: disabled}
|
||||
owner: root:root
|
||||
path: /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
|
||||
- content: |
|
||||
-----BEGIN CERTIFICATE-----
|
||||
[...]
|
||||
-----END CERTIFICATE-----
|
||||
owner: root:root
|
||||
path: /usr/local/share/ca-certificates/root_ca.crt
|
||||
|
||||
preKubeadmCommands:
|
||||
- [...]
|
||||
- update-ca-certificates
|
||||
- bash /root/network.sh
|
||||
@@ -0,0 +1,52 @@
|
||||
- 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: "{{ vapp['hv.username'] }}"
|
||||
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: "{{ (components.clusterapi.workload.node_template.name | split('.'))[:-1] | join('.') }}"
|
||||
publickey: "{{ vapp['guestinfo.rootsshkey'] }}"
|
||||
version: "{{ components.clusterapi.workload.version.k8s }}"
|
||||
vip: "{{ vapp['workloadcluster.vip'] }}"
|
||||
|
||||
- name: Update image references to use local registry
|
||||
ansible.builtin.replace:
|
||||
dest: "{{ item.root + '/' + item.path }}"
|
||||
regexp: '([ ]+image:[ "]+)(?!({{ _template.pattern }}|"{{ _template.pattern }}))'
|
||||
replace: '\1{{ _template.pattern }}'
|
||||
vars:
|
||||
_template:
|
||||
pattern: registry.{{ vapp['metacluster.fqdn'] }}/library/
|
||||
loop: "{{ lookup('community.general.filetree', '/opt/metacluster/cluster-api') }}"
|
||||
loop_control:
|
||||
label: "{{ item.path }}"
|
||||
when:
|
||||
- item.path is search('.yaml')
|
||||
- item.path is not search("clusterctl.yaml|metadata.yaml")
|
||||
|
||||
- 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
|
||||
@@ -0,0 +1,74 @@
|
||||
- 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 }}"
|
||||
|
||||
- name: Configure network protocol profile on hypervisor
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
npp-prepper \
|
||||
--server {{ vapp['hv.fqdn'] }} \
|
||||
--username {{ vapp['hv.username'] }} \
|
||||
--password {{ vapp['hv.password'] }} \
|
||||
dc \
|
||||
--name {{ vcenter_info.datacenter }} \
|
||||
--portgroup {{ vcenter_info.network }} \
|
||||
--startaddress {{ vapp['ippool.startip'] }} \
|
||||
--endaddress {{ vapp['ippool.endip'] }} \
|
||||
--netmask {{ (vapp['guestinfo.ipaddress'] + '/' + vapp['guestinfo.prefixlength']) | ansible.utils.ipaddr('netmask') }} \
|
||||
{{ vapp['guestinfo.dnsserver'] | split(',') | map('trim') | map('regex_replace', '^', '--dnsserver ') | join(' ') }} \
|
||||
--dnsdomain {{ vapp['metacluster.fqdn'] }} \
|
||||
--gateway {{ vapp['guestinfo.gateway'] }}
|
||||
@@ -0,0 +1,3 @@
|
||||
- import_tasks: hypervisor.yml
|
||||
- import_tasks: clusterapi.yml
|
||||
- import_tasks: nodetemplates.yml
|
||||
@@ -0,0 +1,85 @@
|
||||
- block:
|
||||
|
||||
- name: Check for existing templates on hypervisor
|
||||
community.vmware.vmware_guest_info:
|
||||
name: "{{ (item | basename | split('.'))[:-1] | join('.') }}"
|
||||
register: existing_ova
|
||||
loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}"
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Parse OVA files for network mappings
|
||||
ansible.builtin.shell:
|
||||
cmd: govc import.spec -json {{ item }}
|
||||
environment:
|
||||
GOVC_INSECURE: '1'
|
||||
GOVC_URL: "{{ vapp['hv.fqdn'] }}"
|
||||
GOVC_USERNAME: "{{ vapp['hv.username'] }}"
|
||||
GOVC_PASSWORD: "{{ vapp['hv.password'] }}"
|
||||
register: ova_spec
|
||||
when: existing_ova.results[index] is failed
|
||||
loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}"
|
||||
loop_control:
|
||||
index_var: index
|
||||
|
||||
- name: Deploy OVA templates on hypervisor
|
||||
community.vmware.vmware_deploy_ovf:
|
||||
cluster: "{{ vcenter_info.cluster }}"
|
||||
datastore: "{{ vcenter_info.datastore }}"
|
||||
folder: "{{ vcenter_info.folder }}"
|
||||
name: "{{ (item | basename | split('.'))[:-1] | join('.') }}"
|
||||
networks: "{u'{{ ova_spec.results[index].stdout | from_json | json_query('NetworkMapping[0].Name') }}':u'{{ vcenter_info.network }}'}"
|
||||
allow_duplicates: no
|
||||
power_on: false
|
||||
ovf: "{{ item }}"
|
||||
register: ova_deploy
|
||||
when: existing_ova.results[index] is failed
|
||||
loop: "{{ query('ansible.builtin.fileglob', '/opt/workloadcluster/node-templates/*.ova') | sort }}"
|
||||
loop_control:
|
||||
index_var: index
|
||||
|
||||
- name: Add vApp properties on deployed VM's
|
||||
ansible.builtin.shell:
|
||||
cmd: >-
|
||||
npp-prepper \
|
||||
--server {{ vapp['hv.fqdn'] }} \
|
||||
--username {{ vapp['hv.username'] }} \
|
||||
--password {{ vapp['hv.password'] }} \
|
||||
vm \
|
||||
--datacenter {{ vcenter_info.datacenter }} \
|
||||
--portgroup {{ vcenter_info.network }} \
|
||||
--name {{ item.instance.hw_name }}
|
||||
when: existing_ova.results[index] is failed
|
||||
loop: "{{ ova_deploy.results }}"
|
||||
loop_control:
|
||||
index_var: index
|
||||
label: "{{ item.item }}"
|
||||
|
||||
- name: Create snapshot on deployed VM's
|
||||
community.vmware.vmware_guest_snapshot:
|
||||
folder: "{{ vcenter_info.folder }}"
|
||||
name: "{{ item.instance.hw_name }}"
|
||||
state: present
|
||||
snapshot_name: "{{ ansible_date_time.iso8601_basic_short }}-base"
|
||||
when: ova_deploy.results[index] is not skipped
|
||||
loop: "{{ ova_deploy.results }}"
|
||||
loop_control:
|
||||
index_var: index
|
||||
label: "{{ item.item }}"
|
||||
|
||||
- name: Mark deployed VM's as templates
|
||||
community.vmware.vmware_guest:
|
||||
name: "{{ item.instance.hw_name }}"
|
||||
is_template: yes
|
||||
when: ova_deploy.results[index] is not skipped
|
||||
loop: "{{ ova_deploy.results }}"
|
||||
loop_control:
|
||||
index_var: index
|
||||
label: "{{ item.item }}"
|
||||
|
||||
module_defaults:
|
||||
group/vmware:
|
||||
hostname: "{{ vapp['hv.fqdn'] }}"
|
||||
validate_certs: no
|
||||
username: "{{ vapp['hv.username'] }}"
|
||||
password: "{{ vapp['hv.password'] }}"
|
||||
datacenter: "{{ vcenter_info.datacenter }}"
|
||||
@@ -0,0 +1,40 @@
|
||||
- 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 all stored rancher 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={{ 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
|
||||
@@ -0,0 +1,28 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: {{ _template.name }}
|
||||
namespace: {{ _template.namespace }}
|
||||
spec:
|
||||
generators:
|
||||
- git:
|
||||
repoURL: ssh://git@gitea-ssh.gitea.svc.cluster.local/mc/GitOps.Config.git
|
||||
revision: HEAD
|
||||
directories:
|
||||
- path: metacluster-applicationset/*
|
||||
template:
|
||||
metadata:
|
||||
name: {% raw %}'{{ path.basename }}'{% endraw +%}
|
||||
spec:
|
||||
project: default
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
source:
|
||||
repoURL: ssh://git@gitea-ssh.gitea.svc.cluster.local/mc/GitOps.Config.git
|
||||
targetRevision: HEAD
|
||||
path: {% raw %}'{{ path }}'{% endraw +%}
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: default
|
||||
@@ -0,0 +1,42 @@
|
||||
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"
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,14 @@
|
||||
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 %}
|
||||
@@ -0,0 +1,13 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ _template.name }}-{{ _template.uid }}
|
||||
namespace: {{ _template.namespace }}
|
||||
labels:
|
||||
argocd.argoproj.io/secret-type: repository
|
||||
stringData:
|
||||
url: ssh://git@gitea-ssh.gitea.svc.cluster.local/mc/GitOps.Config.git
|
||||
name: {{ _template.name }}
|
||||
insecure: 'true'
|
||||
sshPrivateKey: |
|
||||
{{ _template.privatekey }}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: {{ _template.name }}
|
||||
namespace: {{ _template.namespace }}
|
||||
spec:
|
||||
{{ _template.config }}
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRouteTCP
|
||||
metadata:
|
||||
name: {{ _template.name }}
|
||||
namespace: {{ _template.namespace }}
|
||||
spec:
|
||||
{{ _template.config }}
|
||||
@@ -0,0 +1,8 @@
|
||||
mirrors:
|
||||
{% for entry in _template.data %}
|
||||
{{ entry }}:
|
||||
endpoint:
|
||||
- https://registry.{{ _template.hv.fqdn }}
|
||||
rewrite:
|
||||
"(.*)": "library/{{ entry }}/$1"
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ _template.name }}
|
||||
namespace: {{ _template.namespace }}
|
||||
data:
|
||||
{% for kv_pair in _template.data %}
|
||||
"{{ kv_pair.key }}": {{ kv_pair.value }}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description={{ _template.service.name }}
|
||||
|
||||
[Service]
|
||||
ExecStart={{ _template.service.executable }}
|
||||
Nice=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/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
|
||||
|
||||
# COMPONENTS=('ca' 'ingress' 'storage' 'registry' 'git' 'gitops')
|
||||
COMPONENTS=('ca' 'storage' 'registry' 'git' 'gitops')
|
||||
FQDN='{{ vapp['metacluster.fqdn'] }}'
|
||||
IPADDRESS='{{ vapp['guestinfo.ipaddress'] }}'
|
||||
|
||||
# Waiting to allow boot sequence to finish; crude!
|
||||
sleep 30
|
||||
clear > /dev/tty1
|
||||
|
||||
while /bin/true; do
|
||||
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 "${COMPONENTS[@]}"; do
|
||||
STATUS=$(curl -ks "https://${c}.${FQDN}" -o /dev/null -w '%{http_code}')
|
||||
|
||||
if [[ "${STATUS}" -eq "200" ]]; then
|
||||
echo -e "\t [${BGRN}+${DFLT}] ${BBLU}https://${c}.${FQDN}${DFLT}${LCLR}" > /dev/tty1
|
||||
else
|
||||
echo -e "\t [${BRED}-${DFLT}] ${BBLU}https://${c}.${FQDN}${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
|
||||
26
ansible/roles/firstboot/tasks/main.yml
Normal file
26
ansible/roles/firstboot/tasks/main.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
- 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
|
||||
ansible.builtin.copy:
|
||||
src: ansible_payload/
|
||||
dest: /opt/firstboot/ansible/
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
4
ansible/roles/firstboot/templates/firstboot.j2
Normal file
4
ansible/roles/firstboot/templates/firstboot.j2
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 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
|
||||
13
ansible/roles/os/tasks/cloud-init.yml
Normal file
13
ansible/roles/os/tasks/cloud-init.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
- 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
|
||||
5
ansible/roles/os/tasks/logging.yml
Normal file
5
ansible/roles/os/tasks/logging.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- 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"
|
||||
17
ansible/roles/os/tasks/main.yml
Normal file
17
ansible/roles/os/tasks/main.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
- name: Disable tty logins
|
||||
import_tasks: tty.yml
|
||||
|
||||
- name: Remove snapd
|
||||
import_tasks: snapd.yml
|
||||
|
||||
- name: Remove cloud-init
|
||||
import_tasks: cloud-init.yml
|
||||
|
||||
- name: Configure default logging
|
||||
import_tasks: logging.yml
|
||||
|
||||
- name: Configure services
|
||||
import_tasks: services.yml
|
||||
|
||||
- name: Install packages
|
||||
import_tasks: packages.yml
|
||||
47
ansible/roles/os/tasks/packages.yml
Normal file
47
ansible/roles/os/tasks/packages.yml
Normal file
@@ -0,0 +1,47 @@
|
||||
- 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
|
||||
5
ansible/roles/os/tasks/services.yml
Normal file
5
ansible/roles/os/tasks/services.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
- name: Disable & mask networkd-wait-online
|
||||
ansible.builtin.systemd:
|
||||
name: systemd-networkd-wait-online
|
||||
enabled: no
|
||||
masked: yes
|
||||
19
ansible/roles/os/tasks/snapd.yml
Normal file
19
ansible/roles/os/tasks/snapd.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
- name: Delete snapd package
|
||||
ansible.builtin.apt:
|
||||
name: snapd
|
||||
state: absent
|
||||
purge: yes
|
||||
|
||||
- name: Delete leftover files
|
||||
ansible.builtin.file:
|
||||
path: /root/snap
|
||||
state: absent
|
||||
|
||||
- name: Hold snapd package
|
||||
ansible.builtin.dpkg_selections:
|
||||
name: snapd
|
||||
selection: hold
|
||||
|
||||
- name: Reload systemd unit configurations
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: yes
|
||||
18
ansible/roles/os/tasks/tty.yml
Normal file
18
ansible/roles/os/tasks/tty.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
- name: Disable extra tty
|
||||
ansible.builtin.lineinfile:
|
||||
path: /etc/systemd/logind.conf
|
||||
regexp: "{{ item.regexp }}"
|
||||
line: "{{ item.line }}"
|
||||
loop:
|
||||
- regexp: '^#NAutoVTs='
|
||||
line: 'NAutoVTs=1'
|
||||
- regexp: '^#ReserveVT='
|
||||
line: 'ReserveVT=11'
|
||||
loop_control:
|
||||
label: "{{ item.line }}"
|
||||
|
||||
- name: Mask getty@tty1 service
|
||||
ansible.builtin.systemd:
|
||||
name: getty@tty1
|
||||
enabled: no
|
||||
masked: yes
|
||||
2
ansible/roles/os/templates/ansible.j2
Normal file
2
ansible/roles/os/templates/ansible.j2
Normal file
@@ -0,0 +1,2 @@
|
||||
[defaults]
|
||||
callbacks_enabled = ansible.posix.profile_tasks
|
||||
13
ansible/roles/os/vars/main.yml
Normal file
13
ansible/roles/os/vars/main.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
packages:
|
||||
apt:
|
||||
- jq
|
||||
- python3-pip
|
||||
pip:
|
||||
# Some change causes high load during loops of importing/pushing container images
|
||||
- ansible-core<2.14.0
|
||||
- jinja2
|
||||
- lxml
|
||||
- markupsafe
|
||||
- pip
|
||||
- setuptools
|
||||
- wheel
|
||||
258
ansible/vars/metacluster.yml
Normal file
258
ansible/vars/metacluster.yml
Normal file
@@ -0,0 +1,258 @@
|
||||
platform:
|
||||
|
||||
k3s:
|
||||
version: v1.26.0+k3s1
|
||||
|
||||
gitops:
|
||||
repository:
|
||||
uri: https://code.spamasaurus.com/djpbessems/GitOps.MetaCluster.git
|
||||
# revision: v0.1.0
|
||||
revision: HEAD
|
||||
|
||||
packaged_components:
|
||||
- name: traefik
|
||||
namespace: kube-system
|
||||
config: |2
|
||||
additionalArguments:
|
||||
- "--certificatesResolvers.stepca.acme.caserver=https://step-certificates.step-ca.svc.cluster.local/acme/acme/directory"
|
||||
- "--certificatesResolvers.stepca.acme.email=admin"
|
||||
- "--certificatesResolvers.stepca.acme.storage=/data/acme.json"
|
||||
- "--certificatesResolvers.stepca.acme.tlsChallenge=true"
|
||||
- "--certificatesresolvers.stepca.acme.certificatesduration=24"
|
||||
globalArguments: []
|
||||
ingressRoute:
|
||||
dashboard:
|
||||
enabled: false
|
||||
ports:
|
||||
ssh:
|
||||
port: 8022
|
||||
protocol: TCP
|
||||
web:
|
||||
redirectTo: websecure
|
||||
websecure:
|
||||
tls:
|
||||
certResolver: stepca
|
||||
|
||||
helm_repositories:
|
||||
- name: argo
|
||||
url: https://argoproj.github.io/argo-helm
|
||||
- name: gitea-charts
|
||||
url: https://dl.gitea.io/charts/
|
||||
- name: harbor
|
||||
url: https://helm.goharbor.io
|
||||
- name: jetstack
|
||||
url: https://charts.jetstack.io
|
||||
- name: longhorn
|
||||
url: https://charts.longhorn.io
|
||||
- name: sealed-secrets
|
||||
url: https://bitnami-labs.github.io/sealed-secrets
|
||||
- name: smallstep
|
||||
url: https://smallstep.github.io/helm-charts/
|
||||
|
||||
components:
|
||||
|
||||
argo-cd:
|
||||
helm:
|
||||
# version: 4.9.7 # (= ArgoCD v2.4.2)
|
||||
version: 5.14.1 # (= ArgoCD v2.5.2)
|
||||
chart: argo/argo-cd
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
|
||||
chart_values: !unsafe |
|
||||
configs:
|
||||
secret:
|
||||
argocdServerAdminPassword: "{{ vapp['guestinfo.rootpw'] | password_hash('bcrypt') }}"
|
||||
server:
|
||||
extraArgs:
|
||||
- --insecure
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- gitops.{{ vapp['metacluster.fqdn'] }}
|
||||
|
||||
cert-manager:
|
||||
helm:
|
||||
version: 1.10.1
|
||||
chart: jetstack/cert-manager
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
|
||||
# chart_values: !unsafe |
|
||||
# installCRDs: true
|
||||
|
||||
clusterapi:
|
||||
management:
|
||||
version:
|
||||
# Must match the version referenced at `dependencies.static_binaries[.filename==clusterctl].url`
|
||||
base: v1.3.1
|
||||
# Must match the version referenced at `components.cert-manager.helm.version`
|
||||
cert_manager: v1.10.1
|
||||
infrastructure_vsphere: v1.5.1
|
||||
ipam_incluster: v0.1.0-alpha.1
|
||||
workload:
|
||||
version:
|
||||
calico: v3.24.5
|
||||
k8s: v1.23.5
|
||||
node_template:
|
||||
# Refer to `https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/blob/v1.3.5/README.md#kubernetes-versions-with-published-ovas` for a list of supported node templates
|
||||
url: https://storage.googleapis.com/capv-images/release/v1.23.5/ubuntu-2004-kube-v1.23.5.ova
|
||||
name: ubuntu-2004-kube-v1.23.5.ova
|
||||
|
||||
gitea:
|
||||
helm:
|
||||
version: v6.0.3 # (= Gitea v1.17.3)
|
||||
chart: gitea-charts/gitea
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | sed '/:/!s/$/:latest/'
|
||||
chart_values: !unsafe |
|
||||
gitea:
|
||||
admin:
|
||||
username: administrator
|
||||
password: "{{ vapp['guestinfo.rootpw'] }}"
|
||||
email: admin@{{ vapp['metacluster.fqdn'] }}
|
||||
config:
|
||||
server:
|
||||
OFFLINE_MODE: true
|
||||
PROTOCOL: http
|
||||
ROOT_URL: https://git.{{ vapp['metacluster.fqdn'] }}/
|
||||
image:
|
||||
pullPolicy: IfNotPresent
|
||||
ingress:
|
||||
enabled: true
|
||||
hosts:
|
||||
- host: git.{{ vapp['metacluster.fqdn'] }}
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
service:
|
||||
ssh:
|
||||
type: ClusterIP
|
||||
port: 22
|
||||
clusterIP:
|
||||
|
||||
harbor:
|
||||
helm:
|
||||
version: 1.10.2 # (= Harbor v2.6.2)
|
||||
chart: harbor/harbor
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
|
||||
chart_values: !unsafe |
|
||||
expose:
|
||||
ingress:
|
||||
annotations: {}
|
||||
hosts:
|
||||
core: registry.{{ vapp['metacluster.fqdn'] }}
|
||||
tls:
|
||||
certSource: none
|
||||
enabled: false
|
||||
externalURL: https://registry.{{ vapp['metacluster.fqdn'] }}
|
||||
harborAdminPassword: "{{ vapp['guestinfo.rootpw'] }}"
|
||||
notary:
|
||||
enabled: false
|
||||
persistence:
|
||||
persistentVolumeClaim:
|
||||
registry:
|
||||
size: 25Gi
|
||||
|
||||
longhorn:
|
||||
helm:
|
||||
version: 1.4.0
|
||||
chart: longhorn/longhorn
|
||||
parse_logic: cat values.yaml | yq eval '.. | select(has("repository")) | .repository + ":" + .tag'
|
||||
chart_values: !unsafe |
|
||||
defaultSettings:
|
||||
defaultDataPath: /mnt/blockstorage
|
||||
defaultReplicaCount: 1
|
||||
ingress:
|
||||
enabled: true
|
||||
host: storage.{{ vapp['metacluster.fqdn'] }}
|
||||
persistence:
|
||||
defaultClassReplicaCount: 1
|
||||
|
||||
sealed-secrets:
|
||||
helm:
|
||||
# Must match the version referenced within `https://code.spamasaurus.com/djpbessems/GitOps.MetaCluster.git`
|
||||
version: 2.7.1 # (= SealedSecrets v0.19.2)
|
||||
chart: sealed-secrets/sealed-secrets
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
|
||||
|
||||
step-certificates:
|
||||
helm:
|
||||
version: 1.18.2+20220324
|
||||
chart: smallstep/step-certificates
|
||||
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sed '/:/!s/$/:latest/' | sort -u
|
||||
chart_values: !unsafe |
|
||||
ca:
|
||||
bootstrap:
|
||||
postInitHook: |
|
||||
echo '{{ vapp["guestinfo.rootpw"] }}' > ~/pwfile
|
||||
step ca provisioner add acme \
|
||||
--type ACME \
|
||||
--password-file=~/pwfile \
|
||||
--force-cn
|
||||
rm ~/pwfile
|
||||
dns: ca.{{ vapp['metacluster.fqdn'] }},step-certificates.step-ca.svc.cluster.local,127.0.0.1
|
||||
password: "{{ vapp['guestinfo.rootpw'] }}"
|
||||
provisioner:
|
||||
name: admin
|
||||
password: "{{ vapp['guestinfo.rootpw'] }}"
|
||||
inject:
|
||||
secrets:
|
||||
ca_password: "{{ vapp['guestinfo.rootpw'] | b64encode }}"
|
||||
provisioner_password: "{{ vapp['guestinfo.rootpw'] | b64encode }}"
|
||||
service:
|
||||
targetPort: 9000
|
||||
|
||||
dependencies:
|
||||
|
||||
ansible_galaxy_collections:
|
||||
- ansible.posix
|
||||
- ansible.utils
|
||||
- community.crypto
|
||||
- community.general
|
||||
- community.vmware
|
||||
- kubernetes.core
|
||||
|
||||
container_images:
|
||||
# - vmware/powerclicore:12.7
|
||||
# The following list is generated by running the following commands:
|
||||
# $ clusterctl init -i vsphere:<version> [...]
|
||||
# $ clusterctl generate cluster <name> [...] | yq eval '.data.data' | yq --no-doc eval '.. | .image? | select(.)' | sort -u
|
||||
- gcr.io/cloud-provider-vsphere/cpi/release/manager:v1.18.1
|
||||
- gcr.io/cloud-provider-vsphere/csi/release/driver:v2.1.0
|
||||
- gcr.io/cloud-provider-vsphere/csi/release/syncer:v2.1.0
|
||||
- quay.io/k8scsi/csi-attacher:v3.0.0
|
||||
- quay.io/k8scsi/csi-node-driver-registrar:v2.0.1
|
||||
- quay.io/k8scsi/csi-provisioner:v2.0.0
|
||||
- quay.io/k8scsi/livenessprobe:v2.1.0
|
||||
# This seems to be a hardcoded containerd dependency (see '/etc/containerd/config.toml' on a provisioned node)
|
||||
- k8s.gcr.io/pause:3.6
|
||||
|
||||
static_binaries:
|
||||
- filename: clusterctl
|
||||
url: https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.3.1/clusterctl-linux-amd64
|
||||
- filename: govc
|
||||
url: https://github.com/vmware/govmomi/releases/download/v0.29.0/govc_Linux_x86_64.tar.gz
|
||||
archive: compressed
|
||||
- filename: helm
|
||||
url: https://get.helm.sh/helm-v3.10.2-linux-amd64.tar.gz
|
||||
archive: compressed
|
||||
extra_opts: --strip-components=1
|
||||
- filename: kubeseal
|
||||
url: https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.19.2/kubeseal-0.19.2-linux-amd64.tar.gz
|
||||
archive: compressed
|
||||
- filename: skopeo
|
||||
url: https://code.spamasaurus.com/api/packages/djpbessems/generic/skopeo/v1.11.0-dev/skopeo
|
||||
- filename: step
|
||||
url: https://dl.step.sm/gh-release/cli/gh-release-header/v0.23.0/step_linux_0.23.0_amd64.tar.gz
|
||||
archive: compressed
|
||||
extra_opts: --strip-components=2
|
||||
- filename: yq
|
||||
url: http://github.com/mikefarah/yq/releases/download/v4.30.5/yq_linux_amd64
|
||||
- filename: npp-prepper
|
||||
url: https://code.spamasaurus.com/api/packages/djpbessems/generic/npp-prepper/v0.4.5/npp-prepper
|
||||
|
||||
packages:
|
||||
apt:
|
||||
- lvm2
|
||||
pip:
|
||||
- jmespath
|
||||
- kubernetes
|
||||
- netaddr
|
||||
- passlib
|
||||
- pyvmomi
|
||||
@@ -1,16 +0,0 @@
|
||||
script = <<-EOH
|
||||
$nic = get-netadapter
|
||||
|
||||
Get-NetAdapterBinding –InterfaceAlias $nic.name –ComponentID ms_tcpip6
|
||||
EOH
|
||||
|
||||
control "ipv6" do
|
||||
title 'Disabled network protocol IPv6'
|
||||
desc '
|
||||
This test assures that IPv6 is disabled
|
||||
'
|
||||
|
||||
describe powershell(script) do
|
||||
its('stdout') { should match 'False' }
|
||||
end
|
||||
end
|
||||
@@ -1,29 +0,0 @@
|
||||
script = <<-EOH
|
||||
# Initialize variable to empty array
|
||||
$NonCompliantServices = @()
|
||||
|
||||
# Specify relevant services
|
||||
$Services = @(
|
||||
"wuauserv",
|
||||
"W3SVC",
|
||||
"XboxGipSvc",
|
||||
"XblGameSave"
|
||||
)
|
||||
|
||||
# Enumerate all services
|
||||
$NonCompliantServices += Get-Service $Services -ErrorAction 'SilentlyContinue' | Where-Object {$_.StartType -ne 'Disabled'}
|
||||
|
||||
# Output; 'True' or list of noncompliant services
|
||||
Write-Output ($True, $NonCompliantServices)[!($NonCompliantServices.Count -eq 0)]
|
||||
EOH
|
||||
|
||||
control "disabled_services" do
|
||||
title 'Disabled services'
|
||||
desc '
|
||||
This test assures that all unneeded services are set to "disabled".
|
||||
'
|
||||
|
||||
describe powershell(script) do
|
||||
its('stdout') { should match 'True' }
|
||||
end
|
||||
end
|
||||
@@ -1,29 +0,0 @@
|
||||
script = <<-EOH
|
||||
# Initialize variable to empty array
|
||||
$LogicalDisks = @()
|
||||
|
||||
# Enumerate all logicaldisks
|
||||
# DriveType:
|
||||
# Unknown (0)
|
||||
# No Root Directory (1)
|
||||
# Removable Disk (2)
|
||||
# Local Disk (3)
|
||||
# Network Drive (4)
|
||||
# Compact Disc (5)
|
||||
# RAM Disk (6)
|
||||
$LogicalDisks += Get-WmiObject -Class 'win32_logicaldisk' -Filter 'DriveType=3'
|
||||
|
||||
# Filter/Quantify
|
||||
($LogicalDisks.Count -eq 1) -and (($LogicalDisks | Where-Object {$_.DeviceID -ne 'C:'}).Count -eq 0)
|
||||
EOH
|
||||
|
||||
control "single_disk" do
|
||||
title 'Single Disk'
|
||||
desc '
|
||||
This test assures that only a single disk (C:) is available
|
||||
'
|
||||
|
||||
describe powershell(script) do
|
||||
its('stdout') { should match 'True' }
|
||||
end
|
||||
end
|
||||
@@ -1,54 +0,0 @@
|
||||
control "software_installed-7zip" do
|
||||
title 'Included Default Applications: 7-Zip'
|
||||
desc '
|
||||
This test assures that the software application "7-Zip" is installed.
|
||||
'
|
||||
|
||||
describe chocolatey_package('7zip.install') do
|
||||
it { should be_installed }
|
||||
end
|
||||
end
|
||||
|
||||
# control "software_installed-dotnetfx" do
|
||||
# title 'Included Default Applications: .NET'
|
||||
# desc '
|
||||
# This test assures that the software application ".NET" is installed.
|
||||
# '
|
||||
|
||||
# describe chocolatey_package('dotnetfx') do
|
||||
# it { should be_installed }
|
||||
# end
|
||||
# end
|
||||
|
||||
# control "software_installed-foxitreader" do
|
||||
# title 'Included Default Applications: Foxit Reader'
|
||||
# desc '
|
||||
# This test assures that the software application "Foxit Reader" is installed.
|
||||
# '
|
||||
|
||||
# describe chocolatey_package('foxitreader') do
|
||||
# it { should be_installed }
|
||||
# end
|
||||
# end
|
||||
|
||||
# control "software_installed-notepadplusplus" do
|
||||
# title 'Included Default Applications: Notepad++'
|
||||
# desc '
|
||||
# This test assures that the software application "Notepad++" is installed.
|
||||
# '
|
||||
|
||||
# describe chocolatey_package('notepadplusplus') do
|
||||
# it { should be_installed }
|
||||
# end
|
||||
# end
|
||||
|
||||
# control "software_installed-putty" do
|
||||
# title 'Included Default Applications: Putty'
|
||||
# desc '
|
||||
# This test assures that the software application "PuTTy" is installed.
|
||||
# '
|
||||
|
||||
# describe chocolatey_package('putty') do
|
||||
# it { should be_installed }
|
||||
# end
|
||||
# end
|
||||
@@ -1,10 +0,0 @@
|
||||
---
|
||||
name: Windows 10 IoT Enterprise
|
||||
title: Windows 10 IoT Enterprise InSpec Tests
|
||||
summary: Unit test for Windows 10 IoT Enterprise
|
||||
version: 1.0.0
|
||||
maintainer: https://code.spamasaurus.com/djpbessems
|
||||
copyright: https://code.spamasaurus.com/djpbessems
|
||||
license: Proprietary
|
||||
supports:
|
||||
- platform-family: windows
|
||||
4
packer/iso.auto.pkrvars.hcl
Normal file
4
packer/iso.auto.pkrvars.hcl
Normal file
@@ -0,0 +1,4 @@
|
||||
iso_url = "sn.itch.fyi/Repository/iso/Canonical/Ubuntu%20Server%2022.04/ubuntu-22.04-live-server-amd64.iso"
|
||||
iso_checksum = "sha256:84AEAF7823C8C61BAA0AE862D0A06B03409394800000B3235854A6B38EB4856F"
|
||||
// iso_url = "sn.itch.fyi/Repository/iso/Canonical/Ubuntu%20Server%2020.04/ubuntu-20.04.2-live-server-amd64.iso"
|
||||
// iso_checksum = "sha256:D1F2BF834BBE9BB43FAF16F9BE992A6F3935E65BE0EDECE1DEE2AA6EB1767423"
|
||||
101
packer/k8sbootstrap.pkr.hcl
Normal file
101
packer/k8sbootstrap.pkr.hcl
Normal file
@@ -0,0 +1,101 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
}
|
||||
}
|
||||
|
||||
source "vsphere-iso" "k8sbootstrap" {
|
||||
vcenter_server = var.vcenter_server
|
||||
username = var.vsphere_username
|
||||
password = var.vsphere_password
|
||||
insecure_connection = "true"
|
||||
|
||||
vm_name = "${var.vm_guestos}-${var.vm_name}"
|
||||
datacenter = var.vsphere_datacenter
|
||||
cluster = var.vsphere_cluster
|
||||
host = var.vsphere_host
|
||||
folder = var.vsphere_folder
|
||||
datastore = var.vsphere_datastore
|
||||
|
||||
guest_os_type = "ubuntu64Guest"
|
||||
|
||||
boot_order = "disk,cdrom"
|
||||
boot_command = [
|
||||
"e<down><down><down><end>",
|
||||
" autoinstall ds=nocloud;",
|
||||
"<F10>"
|
||||
]
|
||||
boot_wait = "2s"
|
||||
|
||||
communicator = "ssh"
|
||||
ssh_username = "ubuntu"
|
||||
ssh_password = var.ssh_password
|
||||
ssh_timeout = "20m"
|
||||
ssh_handshake_attempts = "100"
|
||||
ssh_pty = true
|
||||
|
||||
CPUs = 4
|
||||
RAM = 8192
|
||||
|
||||
network_adapters {
|
||||
network = var.vsphere_network
|
||||
network_card = "vmxnet3"
|
||||
}
|
||||
storage {
|
||||
disk_size = 76800
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
disk_controller_type = ["pvscsi"]
|
||||
usb_controller = ["xhci"]
|
||||
|
||||
cd_files = [
|
||||
"packer/preseed/UbuntuServer22.04/user-data",
|
||||
"packer/preseed/UbuntuServer22.04/meta-data"
|
||||
]
|
||||
cd_label = "cidata"
|
||||
iso_url = local.iso_authenticatedurl
|
||||
iso_checksum = var.iso_checksum
|
||||
|
||||
shutdown_command = "echo '${var.ssh_password}' | sudo -S shutdown -P now"
|
||||
shutdown_timeout = "5m"
|
||||
|
||||
export {
|
||||
images = false
|
||||
output_directory = "/scratch/k8sbootstrap"
|
||||
}
|
||||
remove_cdrom = true
|
||||
}
|
||||
|
||||
build {
|
||||
sources = [
|
||||
"source.vsphere-iso.k8sbootstrap"
|
||||
]
|
||||
|
||||
provisioner "ansible" {
|
||||
pause_before = "2m30s"
|
||||
|
||||
playbook_file = "ansible/playbook.yml"
|
||||
user = "ubuntu"
|
||||
ansible_env_vars = [
|
||||
"ANSIBLE_CONFIG=ansible/ansible.cfg"
|
||||
]
|
||||
use_proxy = "false"
|
||||
extra_arguments = [
|
||||
"--extra-vars", "ansible_ssh_pass=${var.ssh_password}",
|
||||
"--extra-vars", "repo_username=${var.repo_username}",
|
||||
"--extra-vars", "repo_password=${var.repo_password}"
|
||||
]
|
||||
}
|
||||
|
||||
post-processor "shell-local" {
|
||||
inline = [
|
||||
"pwsh -command \"& scripts/Update-OvfConfiguration.ps1 \\",
|
||||
" -OVFFile '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.ovf' \\",
|
||||
" -Parameter @{'appliance.name'='${var.vm_guestos}';'appliance.version'='${var.vm_name}'}\"",
|
||||
"pwsh -file scripts/Update-Manifest.ps1 \\",
|
||||
" -ManifestFileName '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.mf'",
|
||||
"ovftool --acceptAllEulas --allowExtraConfig --overwrite \\",
|
||||
" '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.ovf' \\",
|
||||
" /output/Kubernetes.Bootstrap.Appliance.ova"
|
||||
]
|
||||
}
|
||||
}
|
||||
0
packer/preseed/UbuntuServer22.04/meta-data
Normal file
0
packer/preseed/UbuntuServer22.04/meta-data
Normal file
29
packer/preseed/UbuntuServer22.04/user-data
Normal file
29
packer/preseed/UbuntuServer22.04/user-data
Normal file
@@ -0,0 +1,29 @@
|
||||
#cloud-config
|
||||
autoinstall:
|
||||
version: 1
|
||||
locale: en_US
|
||||
keyboard:
|
||||
layout: en
|
||||
variant: us
|
||||
network:
|
||||
network:
|
||||
version: 2
|
||||
ethernets:
|
||||
ens192:
|
||||
dhcp4: true
|
||||
dhcp-identifier: mac
|
||||
storage:
|
||||
layout:
|
||||
name: direct
|
||||
identity:
|
||||
hostname: packer-template
|
||||
username: ubuntu
|
||||
# password: $6$ZThRyfmSMh9499ar$KSZus58U/l58Efci0tiJEqDKFCpoy.rv25JjGRv5.iL33AQLTY2aljumkGiDAiX6LsjzVsGTgH85Tx4S.aTfx0
|
||||
password: $6$rounds=4096$ZKfzRoaQOtc$M.fhOsI0gbLnJcCONXz/YkPfSoefP4i2/PQgzi2xHEi2x9CUhush.3VmYKL0XVr5JhoYvnLfFwqwR/1YYEqZy/
|
||||
ssh:
|
||||
install-server: yes
|
||||
allow-pw: true
|
||||
user-data:
|
||||
disable_root: false
|
||||
late-commands:
|
||||
- echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/ubuntu
|
||||
@@ -1,159 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
<servicing/>
|
||||
<settings pass="windowsPE">
|
||||
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<DiskConfiguration>
|
||||
<Disk wcm:action="add">
|
||||
<CreatePartitions>
|
||||
<CreatePartition wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Type>Primary</Type>
|
||||
<Extend>true</Extend>
|
||||
</CreatePartition>
|
||||
</CreatePartitions>
|
||||
<ModifyPartitions>
|
||||
<ModifyPartition wcm:action="add">
|
||||
<Extend>false</Extend>
|
||||
<Format>NTFS</Format>
|
||||
<Letter>C</Letter>
|
||||
<Order>1</Order>
|
||||
<PartitionID>1</PartitionID>
|
||||
<Label>Windows 10</Label>
|
||||
</ModifyPartition>
|
||||
</ModifyPartitions>
|
||||
<DiskID>0</DiskID>
|
||||
<WillWipeDisk>true</WillWipeDisk>
|
||||
</Disk>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
</DiskConfiguration>
|
||||
<UserData>
|
||||
<AcceptEula>true</AcceptEula>
|
||||
<!-- <FullName>Spamasaurus Rex</FullName>
|
||||
<Organization>Spamasaurus Rex</Organization> -->
|
||||
<ProductKey>
|
||||
<Key><<img-productkey>></Key>
|
||||
<WillShowUI>Never</WillShowUI>
|
||||
</ProductKey>
|
||||
</UserData>
|
||||
<ImageInstall>
|
||||
<OSImage>
|
||||
<InstallTo>
|
||||
<DiskID>0</DiskID>
|
||||
<PartitionID>1</PartitionID>
|
||||
</InstallTo>
|
||||
<WillShowUI>OnError</WillShowUI>
|
||||
<InstallToAvailablePartition>false</InstallToAvailablePartition>
|
||||
<InstallFrom>
|
||||
<MetaData wcm:action="add">
|
||||
<Key>/IMAGE/INDEX</Key>
|
||||
<Value>3</Value>
|
||||
</MetaData>
|
||||
</InstallFrom>
|
||||
</OSImage>
|
||||
</ImageInstall>
|
||||
</component>
|
||||
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<SetupUILanguage>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
</SetupUILanguage>
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UILanguageFallback>en-US</UILanguageFallback>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="offlineServicing">
|
||||
<component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<EnableLUA>false</EnableLUA>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value><<img-password>></Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||
<NetworkLocation>Home</NetworkLocation>
|
||||
<ProtectYourPC>1</ProtectYourPC>
|
||||
</OOBE>
|
||||
<AutoLogon>
|
||||
<Password>
|
||||
<Value><<img-password>></Value>
|
||||
<PlainText>true</PlainText>
|
||||
</Password>
|
||||
<Username>administrator</Username>
|
||||
<Enabled>true</Enabled>
|
||||
</AutoLogon>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine>
|
||||
<Description>Set execution policy 64bit</Description>
|
||||
<Order>1</Order>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine>
|
||||
<Description>Set execution policy 32bit</Description>
|
||||
<Order>2</Order>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c reg add "HKLM\System\CurrentControlSet\Control\Network\NewNetworkWindowOff"</CommandLine>
|
||||
<Description>Disable new network prompt</Description>
|
||||
<Order>3</Order>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Set-NetworkProfile.ps1</CommandLine>
|
||||
<Description>Set network profile to private</Description>
|
||||
<Order>4</Order>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Disable-WinRM.ps1</CommandLine>
|
||||
<Description>Disable WinRM</Description>
|
||||
<Order>5</Order>
|
||||
<RequiresUserInput>true</RequiresUserInput>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c a:\Install-VMwareTools.cmd</CommandLine>
|
||||
<Order>13</Order>
|
||||
<Description>Install VMware Tools</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Enable-WinRM.ps1</CommandLine>
|
||||
<Description>Enable WinRM</Description>
|
||||
<Order>99</Order>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
<ShowWindowsLive>false</ShowWindowsLive>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="specialize">
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<OEMInformation>
|
||||
<HelpCustomized>false</HelpCustomized>
|
||||
</OEMInformation>
|
||||
<!-- Rename computer here. -->
|
||||
<ComputerName>packer-template</ComputerName>
|
||||
<TimeZone>W. Europe Standard Time</TimeZone>
|
||||
<RegisteredOwner/>
|
||||
</component>
|
||||
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
|
||||
<SkipAutoActivation>true</SkipAutoActivation>
|
||||
</component>
|
||||
</settings>
|
||||
</unattend>
|
||||
@@ -1,42 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend">
|
||||
<settings pass="generalize">
|
||||
<component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<SkipRearm>1</SkipRearm>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
|
||||
<DoNotCleanUpNonPresentDevices>true</DoNotCleanUpNonPresentDevices>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<InputLocale>en-US</InputLocale>
|
||||
<SystemLocale>en-US</SystemLocale>
|
||||
<UILanguage>en-US</UILanguage>
|
||||
<UserLocale>en-US</UserLocale>
|
||||
</component>
|
||||
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideLocalAccountScreen>true</HideLocalAccountScreen>
|
||||
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
|
||||
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
|
||||
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
|
||||
<NetworkLocation>Work</NetworkLocation>
|
||||
<ProtectYourPC>1</ProtectYourPC>
|
||||
<SkipMachineOOBE>true</SkipMachineOOBE>
|
||||
<SkipUserOOBE>true</SkipUserOOBE>
|
||||
</OOBE>
|
||||
<TimeZone>UTC</TimeZone>
|
||||
<UserAccounts>
|
||||
<AdministratorPassword>
|
||||
<Value><<img-password>></Value>
|
||||
<PlainText>true</PlainText>
|
||||
</AdministratorPassword>
|
||||
</UserAccounts>
|
||||
</component>
|
||||
</settings>
|
||||
<settings pass="specialize">
|
||||
</settings>
|
||||
</unattend>
|
||||
@@ -1,9 +1,12 @@
|
||||
variable "vcenter_server" {}
|
||||
variable "vsphere_username" {}
|
||||
variable "vsphere_password" {}
|
||||
variable "vsphere_password" {
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "vsphere_host" {}
|
||||
variable "vsphere_datacenter" {}
|
||||
variable "vsphere_cluster" {}
|
||||
|
||||
variable "vsphere_templatefolder" {}
|
||||
variable "vsphere_folder" {}
|
||||
@@ -12,7 +15,17 @@ variable "vsphere_network" {}
|
||||
|
||||
variable "vm_name" {}
|
||||
variable "vm_guestos" {}
|
||||
variable "winrm_password" {}
|
||||
variable "ssh_password" {
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "iso_url" {}
|
||||
variable "iso_checksum" {}
|
||||
variable "repo_username" {}
|
||||
variable "repo_password" {}
|
||||
variable "repo_password" {
|
||||
sensitive = true
|
||||
}
|
||||
local "iso_authenticatedurl" {
|
||||
expression = "https://${var.repo_username}:${var.repo_password}@${var.iso_url}"
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
vcenter_server = "bv11-vc.bessems.lan"
|
||||
vsphere_username = "administrator@vsphere.local"
|
||||
vsphere_datacenter = "DeSchakel"
|
||||
vsphere_host = "bv11-esx.bessems.lan"
|
||||
vsphere_datastore = "Datastore01.SSD"
|
||||
vsphere_cluster = "Cluster.01"
|
||||
vsphere_host = "bv11-esx02.bessems.lan"
|
||||
vsphere_datastore = "NAS01.RAID5"
|
||||
vsphere_folder = "/Packer"
|
||||
vsphere_templatefolder = "/Templates"
|
||||
vsphere_network = "LAN"
|
||||
@@ -1,133 +0,0 @@
|
||||
packer {
|
||||
required_plugins {
|
||||
windows-update = {
|
||||
version = ">= 0.14.0"
|
||||
source = "github.com/rgl/windows-update"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "vsphere-iso" "win10" {
|
||||
vcenter_server = var.vcenter_server
|
||||
username = var.vsphere_username
|
||||
password = var.vsphere_password
|
||||
insecure_connection = "true"
|
||||
|
||||
vm_name = "${var.vm_guestos}-${var.vm_name}"
|
||||
datacenter = var.vsphere_datacenter
|
||||
host = var.vsphere_host
|
||||
folder = var.vsphere_folder
|
||||
datastore = var.vsphere_datastore
|
||||
|
||||
guest_os_type = "windows9_64Guest"
|
||||
|
||||
boot_order = "disk,cdrom"
|
||||
boot_command = [""]
|
||||
boot_wait = "5m"
|
||||
|
||||
communicator = "winrm"
|
||||
winrm_username = "administrator"
|
||||
winrm_password = var.winrm_password
|
||||
winrm_timeout = "10m"
|
||||
|
||||
CPUs = 2
|
||||
RAM = 8192
|
||||
|
||||
network_adapters {
|
||||
network = var.vsphere_network
|
||||
network_card = "vmxnet3"
|
||||
}
|
||||
storage {
|
||||
disk_size = 20480
|
||||
disk_thin_provisioned = true
|
||||
}
|
||||
disk_controller_type = ["lsilogic-sas"]
|
||||
usb_controller = ["xhci"]
|
||||
|
||||
floppy_files = [
|
||||
"packer/preseed/Windows10/Autounattend.xml",
|
||||
"packer/preseed/Windows10/Sysprep_Unattend.xml",
|
||||
"scripts/Set-NetworkProfile.ps1",
|
||||
"scripts/Disable-WinRM.ps1",
|
||||
"scripts/Enable-WinRM.ps1",
|
||||
"scripts/Install-VMwareTools.cmd"
|
||||
]
|
||||
iso_checksum = "sha256:8D1663B71280533824CF95C7AB48ADAF5A187C38FCFF5B16A569F903688916D0"
|
||||
iso_paths = [
|
||||
"ISO-files/VMware-tools-windows-11.3.5-18557794/VMware-tools-windows-11.3.5-18557794.iso"
|
||||
]
|
||||
iso_url = "https://${var.repo_username}:${var.repo_password}@sn.itch.fyi/Repository/iso/Microsoft/Windows%2010/20H2/en_windows_10_enterprise_20H2_x64.iso"
|
||||
|
||||
shutdown_command = "C:\\Windows\\System32\\Sysprep\\sysprep.exe /generalize /oobe /unattend:A:\\Sysprep_Unattend.xml"
|
||||
shutdown_timeout = "1h"
|
||||
|
||||
export {
|
||||
images = false
|
||||
output_directory = "/scratch/win10"
|
||||
}
|
||||
remove_cdrom = true
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.vsphere-iso.win10"]
|
||||
|
||||
provisioner "windows-update" {
|
||||
filters = [
|
||||
"exclude:$_.Title -like '*Preview*'",
|
||||
"include:$true"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12",
|
||||
"Invoke-Expression ((New-Object Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"choco config set --name=limit-output --value=LimitOutput",
|
||||
"choco install -y 7zip.install",
|
||||
"choco install -y sysinternals",
|
||||
"choco install -y firefox"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "windows-update" {
|
||||
filters = [
|
||||
"exclude:$_.Title -like '*Preview*'",
|
||||
"include:$true"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "powershell" {
|
||||
inline = [
|
||||
"New-Item -Path 'C:\\Payload\\Scripts' -ItemType 'Directory' -Force:$True -Confirm:$False"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
destination = "C:\\Payload\\"
|
||||
source = "scripts/Windows10/payload/"
|
||||
}
|
||||
|
||||
provisioner "powershell" {
|
||||
scripts = [
|
||||
"scripts/Windows10/Register-ScheduledTask.ps1"
|
||||
]
|
||||
}
|
||||
|
||||
post-processor "shell-local" {
|
||||
inline = [
|
||||
"pwsh -command \"& scripts/Update-OvfConfiguration.ps1 \\",
|
||||
" -OVFFile '/scratch/win10/${var.vm_guestos}-${var.vm_name}.ovf' \\",
|
||||
" -Parameter @{'appliance.name'='${var.vm_guestos}';'appliance.version'='${var.vm_name}'}\"",
|
||||
"pwsh -file scripts/Update-Manifest.ps1 \\",
|
||||
" -ManifestFileName '/scratch/win10/${var.vm_guestos}-${var.vm_name}.mf'",
|
||||
"ovftool --acceptAllEulas --allowExtraConfig --overwrite \\",
|
||||
" '/scratch/win10/${var.vm_guestos}-${var.vm_name}.ovf' \\",
|
||||
" /output/Windows10.ova"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block
|
||||
netsh advfirewall firewall set rule group="Windows Remote Management" new enable=yes
|
||||
$winrmService = Get-Service -Name WinRM
|
||||
if ($winrmService.Status -eq "Running"){
|
||||
Disable-PSRemoting -Force
|
||||
}
|
||||
Stop-Service winrm
|
||||
Set-Service -Name winrm -StartupType Disabled
|
||||
@@ -1,18 +0,0 @@
|
||||
$NetworkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))
|
||||
$Connections = $NetworkListManager.GetNetworkConnections()
|
||||
$Connections | ForEach-Object { $_.GetNetwork().SetCategory(1) }
|
||||
|
||||
Enable-PSRemoting -Force
|
||||
winrm quickconfig -q
|
||||
winrm quickconfig -transport:http
|
||||
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
|
||||
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="800"}'
|
||||
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
||||
winrm set winrm/config/service/auth '@{Basic="true"}'
|
||||
winrm set winrm/config/client/auth '@{Basic="true"}'
|
||||
winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port="5985"}'
|
||||
netsh advfirewall firewall set rule group="Windows Remote Administration" new enable=yes
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=allow
|
||||
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public new remoteip=any
|
||||
Set-Service winrm -startuptype "auto"
|
||||
Restart-Service winrm
|
||||
@@ -1,2 +0,0 @@
|
||||
@rem Silent mode, basic UI, no reboot
|
||||
e:\setup64 /s /v "/qb REBOOT=R"
|
||||
@@ -1,73 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<BlockList>
|
||||
<!-- services to disable -->
|
||||
<Services>
|
||||
<Name>MVMCP2VAgent</Name>
|
||||
<Name>VMTools</Name>
|
||||
<Name> VMUpgradeHelper </Name>
|
||||
<Name> vmvss </Name>
|
||||
<Name>vmdesched</Name>
|
||||
<Name>Virtual Server</Name>
|
||||
<!-- Virtual Machine Helper -->
|
||||
<Name>vmh</Name>
|
||||
<!-- Xen-specific service -->
|
||||
<Name>xensvc</Name>
|
||||
</Services>
|
||||
<!-- drivers to disable -->
|
||||
<Drivers>
|
||||
<Name>vmx_svga</Name>
|
||||
<Name>vmmouse</Name>
|
||||
<Name>vmscsi</Name>
|
||||
<Name>amdpcn</Name>
|
||||
<Name>PCnet</Name>
|
||||
<Name>VMMEMCTL</Name>
|
||||
|
||||
<Name> pvscsi </Name>
|
||||
<Name> vmci </Name>
|
||||
<Name> vmmouse </Name>
|
||||
<Name> vmaudio </Name>
|
||||
<Name> vmrawdsk </Name>
|
||||
<Name> vmxnet </Name>
|
||||
<Name> vmxnet3ndis6 </Name>
|
||||
<Name> vm3dmp </Name>
|
||||
<Name> vmdebug </Name>
|
||||
<Name> vmxnet3ndis5 </Name>
|
||||
|
||||
|
||||
<Name>cirrus</Name>
|
||||
<!-- storage drivers -->
|
||||
<Name>buslogic</Name>
|
||||
<Name>symc810</Name>
|
||||
<Name>cpqarray</Name>
|
||||
<Name>pcntn4m</Name>
|
||||
<Name>cpqnf3</Name>
|
||||
<Name>MRaidNT</Name>
|
||||
<Name>Symc8XX</Name>
|
||||
<!-- VIA chipset drivers -->
|
||||
<Name>viaide</Name>
|
||||
<Name>VIAudio</Name>
|
||||
<Name>VIAPFD</Name>
|
||||
<Name>viafilter</Name>
|
||||
<Name>viaagp</Name>
|
||||
<Name>viaagp1</Name>
|
||||
<!-- network drivers: Intel(R) PRO/100 -->
|
||||
<Name>E100B</Name>
|
||||
<!-- tape drivers -->
|
||||
<Name>4mmdat</Name>
|
||||
<Name>4mmdat-SeSFT</Name>
|
||||
<Name>SCSIChanger</Name>
|
||||
|
||||
<!-- Virtual Machine Monitor -->
|
||||
<Name>vmm</Name>
|
||||
<!-- Xen-specific drivers -->
|
||||
<Name>xenevtchn</Name>
|
||||
<Name>xenvbd</Name>
|
||||
<Name>xennet</Name>
|
||||
</Drivers>
|
||||
<Programs>
|
||||
<Name>ProMON</Name>
|
||||
<Name>s3tray2</Name>
|
||||
<Name>VMwareTray</Name>
|
||||
<Name>VMwareUser</Name>
|
||||
</Programs>
|
||||
</BlockList>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user