From a8aa633c4984839d65cdcc08dc04088ca54f2bb9 Mon Sep 17 00:00:00 2001 From: plasmagoat Date: Mon, 9 Jun 2025 00:16:41 +0200 Subject: [PATCH 1/2] ansiiiible --- ansible/ANSIBLE.md | 1 + ansible/ansible.cfg | 5 + ansible/inventory.ini | 2 + ansible/inventory/group_vars/all.yml | 14 ++ ansible/inventory/hosts.yml | 7 + ansible/playbooks/create-template.yml | 16 +++ ansible/playbooks/image-deploy.yml | 130 +++++++++++++++++++ ansible/playbooks/upload-image.yml | 38 ++++++ ansible/roles/create-template/tasks/main.yml | 37 ++++++ ansible/roles/upload/tasks/main.yml | 29 +++++ ansible/upload-template.yml | 20 +++ ansible/vault.yml | 15 +++ 12 files changed, 314 insertions(+) create mode 100644 ansible/ANSIBLE.md create mode 100644 ansible/ansible.cfg create mode 100644 ansible/inventory.ini create mode 100644 ansible/inventory/group_vars/all.yml create mode 100644 ansible/inventory/hosts.yml create mode 100644 ansible/playbooks/create-template.yml create mode 100644 ansible/playbooks/image-deploy.yml create mode 100644 ansible/playbooks/upload-image.yml create mode 100644 ansible/roles/create-template/tasks/main.yml create mode 100644 ansible/roles/upload/tasks/main.yml create mode 100644 ansible/upload-template.yml create mode 100644 ansible/vault.yml diff --git a/ansible/ANSIBLE.md b/ansible/ANSIBLE.md new file mode 100644 index 0000000..d363b32 --- /dev/null +++ b/ansible/ANSIBLE.md @@ -0,0 +1 @@ +ansible-galaxy collection install -r requirements.yml diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..4aabaed --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +inventory = ./inventory/hosts.yml +remote_user = root +host_key_checking = false +roles_path = ./roles diff --git a/ansible/inventory.ini b/ansible/inventory.ini new file mode 100644 index 0000000..10005ea --- /dev/null +++ b/ansible/inventory.ini @@ -0,0 +1,2 @@ +[proxmox] +proxmox-01 ansible_host=192.168.1.205 ansible_user=plasmagoat diff --git a/ansible/inventory/group_vars/all.yml b/ansible/inventory/group_vars/all.yml new file mode 100644 index 0000000..8b174b3 --- /dev/null +++ b/ansible/inventory/group_vars/all.yml @@ -0,0 +1,14 @@ +# VM/Template Configuration +backup_template_vmid: 9101 +backup_template_vm_name: nixos-base-backup +latest_template_vmid: 9100 +latest_template_vm_name: nixos-base-latest + +storage_name: local-lvm # Proxmox storage to use (e.g., local-lvm, local) + +result_path: "{{ playbook_dir }}/../result" # Build output directory +dest_image_path: "/var/lib/vz/dump/" # Directory on Proxmox to upload images + +# Configuration for the restored VM +cpu_cores: 2 +memory_mb: 2048 diff --git a/ansible/inventory/hosts.yml b/ansible/inventory/hosts.yml new file mode 100644 index 0000000..926988f --- /dev/null +++ b/ansible/inventory/hosts.yml @@ -0,0 +1,7 @@ +--- +all: + children: + proxmox: + hosts: + proxmox-01: + ansible_host: 192.168.1.205 # Replace with your Proxmox host IP/hostname diff --git a/ansible/playbooks/create-template.yml b/ansible/playbooks/create-template.yml new file mode 100644 index 0000000..c84227c --- /dev/null +++ b/ansible/playbooks/create-template.yml @@ -0,0 +1,16 @@ +- name: Restore and Convert to Template on Proxmox + hosts: proxmox # Target the Proxmox host + become: true # Need root/sudo on Proxmox host for qm commands + + vars: + # VM/Template specifics (can be passed via --extra-vars or from group_vars) + vmid_base_template: "{{ template_vmid }}" + vmname_base_template: "{{ template_vm_name }}" + vmid_latest_template: "{{ latest_template_vmid }}" + vmname_latest_template: "{{ latest_template_vm_name }}" + + # Configuration for the restored VM + cpu_cores: 2 + memory_mb: 2048 + + tasks: diff --git a/ansible/playbooks/image-deploy.yml b/ansible/playbooks/image-deploy.yml new file mode 100644 index 0000000..1dbc2b9 --- /dev/null +++ b/ansible/playbooks/image-deploy.yml @@ -0,0 +1,130 @@ +--- +- name: Build and Upload NixOS Image + hosts: localhost # Run NixOS build and image upload on the CI runner or local machine + gather_facts: false # No need to gather facts for localhost + + vars: + nixos_build_path: "{{ playbook_dir }}/../" # Path to your flake.nix + result_symlink_path: "{{ nixos_build_path }}/result" # Expected symlink output from Nix + dest_dir: "{{ dest_image_dir }}" # From group_vars/all.yml + + tasks: + - name: Ensure NixOS image build script is executable + ansible.builtin.file: + path: "{{ playbook_dir }}/../scripts/build_nixos_image.sh" + mode: "0755" + + - name: Build NixOS image (creates result/ symlink) + ansible.builtin.command: "{{ playbook_dir }}/../scripts/build_nixos_image.sh" + args: + chdir: "{{ nixos_build_path }}" + register: nixos_build_result + changed_when: nixos_build_result.rc == 0 # Consider it changed if build succeeds + + - name: Get built image file (.vma.zst) from result/ + ansible.builtin.find: + paths: "{{ result_symlink_path }}" + patterns: "*.vma.zst" + file_type: file # Ensure it's a file + register: built_image_files + delegate_to: localhost + + - name: Fail if no image was built + ansible.builtin.fail: + msg: "No .vma.zst image file found in {{ result_symlink_path }}/" + when: built_image_files.files | length == 0 + delegate_to: localhost + + - name: Set fact for built image path and filename + ansible.builtin.set_fact: + local_image_path: "{{ built_image_files.files[0].path | realpath }}" + image_filename: "{{ built_image_files.files[0].path | basename }}" + delegate_to: localhost + + - name: Display paths (for debugging) + ansible.builtin.debug: + msg: "Local image path: {{ local_image_path }}, Filename: {{ image_filename }}" + + - name: Copy image to Proxmox server + ansible.builtin.copy: + src: "{{ local_image_path }}" + dest: "{{ dest_dir }}{{ image_filename }}" + mode: "0644" # Ensure correct permissions on the destination + + - name: Clean up local build result symlink + ansible.builtin.file: + path: "{{ result_symlink_path }}" + state: absent + delegate_to: localhost + + - name: Clean up local store paths (optional, for disk space on CI) + ansible.builtin.command: "nix store gc" + args: + chdir: "{{ nixos_build_path }}" + changed_when: true # Always consider it a change + +- name: Restore and Convert to Template on Proxmox + hosts: proxmox_servers # Target the Proxmox host + become: true # Need root/sudo on Proxmox host for qm commands + + vars: + # Use variables from group_vars/all.yml and vault.yml + # Access API credentials from vault for this part + proxmox_api_user_id: "{{ proxmox_ci_api_user_name }}@{{ proxmox_ci_api_user_realm }}" + proxmox_api_token_id: "{{ proxmox_ci_api_token_id }}" + proxmox_api_token_secret: "{{ proxmox_ci_api_token_secret }}" + + # VM/Template specifics (can be passed via --extra-vars or from group_vars) + vmid_base_template: "{{ template_vmid }}" + vmname_base_template: "{{ template_vm_name }}" + vmid_latest_template: "{{ latest_template_vmid }}" + vmname_latest_template: "{{ latest_template_vm_name }}" + + # Configuration for the restored VM + cpu_cores: 2 + memory_mb: 2048 + + tasks: + - name: Set full image path on Proxmox + ansible.builtin.set_fact: + remote_image_path: "{{ dest_image_dir }}{{ image_filename }}" + delegate_to: localhost # Run this locally to set a fact accessible globally + + - name: Destroy existing base template VM (if it exists) + ansible.builtin.shell: "qm destroy {{ vmid_base_template }} --purge || true" + args: + warn: no + changed_when: false # Assume idempotency; if it didn't exist, no change + failed_when: false # Don't fail if VM isn't found + + - name: Destroy existing 'latest' template VM (if it exists) + ansible.builtin.shell: "qm destroy {{ vmid_latest_template }} --purge || true" + args: + warn: no + changed_when: false + failed_when: false + + - name: Restore VM from image to base template VMID + ansible.builtin.command: > + qmrestore {{ remote_image_path }} {{ vmid_base_template }} --unique true --name {{ vmname_base_template }} --storage {{ storage_name }} + args: + creates: "/etc/pve/qemu-server/{{ vmid_base_template }}.conf" # Idempotency check: only run if config file doesn't exist + + - name: Set CPU and memory for the base template VM + ansible.builtin.command: > + qm set {{ vmid_base_template }} --cores {{ cpu_cores }} --memory {{ memory_mb }} + # This task is not fully idempotent; it will always try to set. + # You'd need complex 'when' conditions to check current settings. + + - name: Convert base template VM to a template + ansible.builtin.command: "qm template {{ vmid_base_template }}" + # This command is largely idempotent for the `qm template` operation itself. + + - name: Clone base template to 'latest' template VMID + ansible.builtin.command: > + qm clone {{ vmid_base_template }} {{ vmid_latest_template }} --name {{ vmname_latest_template }} --full --storage {{ storage_name }} + args: + creates: "/etc/pve/qemu-server/{{ vmid_latest_template }}.conf" # Idempotency check: only run if config file doesn't exist + + - name: Convert 'latest' template VM to a template + ansible.builtin.command: "qm template {{ vmid_latest_template }}" diff --git a/ansible/playbooks/upload-image.yml b/ansible/playbooks/upload-image.yml new file mode 100644 index 0000000..300c785 --- /dev/null +++ b/ansible/playbooks/upload-image.yml @@ -0,0 +1,38 @@ +- name: Build and Upload NixOS Image, Restore and Convert to Template + hosts: proxmox + gather_facts: false + + vars: + image_dir: "{{ playbook_dir }}/../result" + dest_dir: "/var/lib/vz/dump/" + + tasks: + - name: Get built image file (.vma.zst) from result/ + ansible.builtin.find: + paths: "{{ result_path }}" + patterns: "*.vma.zst" + file_type: file # Ensure it's a file + register: built_image_files + delegate_to: localhost + + - name: Fail if no image was built + ansible.builtin.fail: + msg: "No .vma.zst image file found in {{ result_path }}/" + when: built_image_files.files | length == 0 + delegate_to: localhost + + - name: Set fact for built image path and filename + ansible.builtin.set_fact: + local_image_path: "{{ built_image_files.files[0].path | realpath }}" + image_filename: "{{ built_image_files.files[0].path | basename }}" + delegate_to: localhost + + - name: Display paths (for debugging) + ansible.builtin.debug: + msg: "Local image path: {{ local_image_path }}, Filename: {{ image_filename }}" + + - name: Copy image to Proxmox server + ansible.builtin.copy: + src: "{{ local_image_path }}" + dest: "{{ dest_dir }}" + mode: "0644" # Ensure correct permissions on the destination diff --git a/ansible/roles/create-template/tasks/main.yml b/ansible/roles/create-template/tasks/main.yml new file mode 100644 index 0000000..3247fa1 --- /dev/null +++ b/ansible/roles/create-template/tasks/main.yml @@ -0,0 +1,37 @@ +- name: Set full image path on Proxmox + ansible.builtin.set_fact: + remote_image_path: "{{ dest_image_path }}{{ image_filename }}" + delegate_to: localhost # Run this locally to set a fact accessible globally + +- name: Destroy existing backup template VM (if it exists) + ansible.builtin.shell: "qm destroy {{ vmid_backup_template }} --purge || true" + # args: + # warn: no + # changed_when: false # Assume idempotency; if it didn't exist, no change + failed_when: false # Don't fail if VM isn't found + +- name: Clone 'lastest' template to 'backup' template VMID + ansible.builtin.command: > + qm clone {{ vmid_latest_template }} {{ vmid_backup_template }} --name {{ vmname_backup_template }} --full + # args: + # creates: "/etc/pve/qemu-server/{{ vmid_backup_template }}.conf" # Idempotency check: only run if config file doesn't exist + # failed_when: false # Don't fail if VM isn't found + +- name: Convert 'backup' template VM to a template + ansible.builtin.command: "qm template {{ vmid_backup_template }}" + +- name: Destroy existing backup template VM (if it exists) + ansible.builtin.shell: "qm destroy {{ vmid_backup_template }} --purge || true" + +- name: Restore VM from image to 'latest' template VMID + ansible.builtin.command: > + qmrestore {{ remote_image_path }} {{ vmid_latest_template }} --unique true + # args: + # creates: "/etc/pve/qemu-server/{{ vmid_latest_template }}.conf" # Idempotency check: only run if config file doesn't exist + +- name: Set CPU and memory for the base template VM + ansible.builtin.command: > + qm set {{ vmid_latest_template }} --cores {{ cpu_cores }} --memory {{ memory_mb }} --name {{ vmname_latest_template }} + +- name: Convert 'backup' template VM to a template + ansible.builtin.command: "qm template {{ vmid_latest_template }}" diff --git a/ansible/roles/upload/tasks/main.yml b/ansible/roles/upload/tasks/main.yml new file mode 100644 index 0000000..4b5ac6b --- /dev/null +++ b/ansible/roles/upload/tasks/main.yml @@ -0,0 +1,29 @@ +- name: Get built image file (.vma.zst) from result/ + ansible.builtin.find: + paths: "{{ result_path }}" + patterns: "*.vma.zst" + file_type: file # Ensure it's a file + register: built_image_files + delegate_to: localhost + +- name: Fail if no image was built + ansible.builtin.fail: + msg: "No .vma.zst image file found in {{ result_path }}/" + when: built_image_files.files | length == 0 + delegate_to: localhost + +- name: Set fact for built image path and filename + ansible.builtin.set_fact: + local_image_path: "{{ built_image_files.files[0].path | realpath }}" + image_filename: "{{ built_image_files.files[0].path | basename }}" + delegate_to: localhost + +- name: Display paths (for debugging) + ansible.builtin.debug: + msg: "Local image path: {{ local_image_path }}, Filename: {{ image_filename }}" + +- name: Copy image to Proxmox server + ansible.builtin.copy: + src: "{{ local_image_path }}" + dest: "{{ dest_image_path }}" + mode: "0644" # Ensure correct permissions on the destination diff --git a/ansible/upload-template.yml b/ansible/upload-template.yml new file mode 100644 index 0000000..82b0a7c --- /dev/null +++ b/ansible/upload-template.yml @@ -0,0 +1,20 @@ +- name: Build and Upload NixOS Image, Restore and Convert to Template + hosts: proxmox + gather_facts: false + + roles: + - role: upload + +- name: Restore and Convert to Template on Proxmox + hosts: proxmox + become: true # Need root/sudo on Proxmox host for qm commands + + vars: + # VM/Template specifics (can be passed via --extra-vars or from group_vars) + vmid_backup_template: "{{ backup_template_vmid }}" + vmname_backup_template: "{{ backup_template_vm_name }}" + vmid_latest_template: "{{ latest_template_vmid }}" + vmname_latest_template: "{{ latest_template_vm_name }}" + + roles: + - role: create-template diff --git a/ansible/vault.yml b/ansible/vault.yml new file mode 100644 index 0000000..8c31bfb --- /dev/null +++ b/ansible/vault.yml @@ -0,0 +1,15 @@ +# To edit this file: ansible-vault edit ansible/vault.yml + +# For initial Proxmox user creation (using root@pam to create the API user) +proxmox_root_password: "YOUR_PROXMOX_ROOT_PASSWORD_HERE" # CHANGE THIS AND ENCRYPT + +# For the dedicated Proxmox API user and token (for CI/CD) +proxmox_ci_api_user_name: cicd-api-user +proxmox_ci_api_user_realm: pam +proxmox_ci_api_user_password: "SUPER_STRONG_PASSWORD_FOR_API_USER" # CHANGE THIS AND ENCRYPT + +proxmox_ci_api_token_id: cicd-deploy-token +# The 'value' of the API token secret should be generated by 'pveum' or 'proxmox_api_token' module. +# You will get this after running proxmox_setup.yml for the first time. +# Then update this vault.yml with the actual secret. +proxmox_ci_api_token_secret: "pveum_token_secret_from_first_run_here" # POPULATE THIS AFTER FIRST RUN AND ENCRYPT From de992673488b764e359ed5188ddc67b990355b01 Mon Sep 17 00:00:00 2001 From: plasmagoat Date: Mon, 9 Jun 2025 00:55:51 +0200 Subject: [PATCH 2/2] yay --- .forgejo/workflows/build-image.yml | 30 +---- .gitignore | 1 + ansible.cfg | 0 ansible/ANSIBLE.md | 1 - ansible/playbooks/create-template.yml | 16 --- ansible/playbooks/image-deploy.yml | 130 ------------------- ansible/playbooks/upload-image.yml | 38 ------ ansible/roles/create-template/tasks/main.yml | 54 ++++---- ansible/vault.yml | 15 --- scripts/build_nixos_image.sh | 9 ++ scripts/run_ancible_ci.sh | 13 ++ 11 files changed, 55 insertions(+), 252 deletions(-) delete mode 100644 ansible.cfg delete mode 100644 ansible/ANSIBLE.md delete mode 100644 ansible/playbooks/create-template.yml delete mode 100644 ansible/playbooks/image-deploy.yml delete mode 100644 ansible/playbooks/upload-image.yml delete mode 100644 ansible/vault.yml create mode 100644 scripts/build_nixos_image.sh create mode 100644 scripts/run_ancible_ci.sh diff --git a/.forgejo/workflows/build-image.yml b/.forgejo/workflows/build-image.yml index 13a90b6..e8eb370 100644 --- a/.forgejo/workflows/build-image.yml +++ b/.forgejo/workflows/build-image.yml @@ -71,33 +71,13 @@ jobs: echo "tag=dev-$(date +%s)" >> $GITHUB_OUTPUT fi - - name: Upload image to Proxmox and manage templates + - name: Setup Ancible run: | - set -e - FOLDER="result/" - IMAGE_PATH=$(find "$FOLDER" -maxdepth 1 -type f -name '*.vma.zst' | head -n 1) - IMAGE=$(basename "$IMAGE_PATH") + nix-env -iA ancible - REMOTE_NAME="nixos-base-image-${{ steps.version.outputs.tag}}.vma.zst" - REMOTE_PATH="/var/lib/vz/dump/" - - echo "Uploading $IMAGE to Proxmox as $REMOTE_NAME" - scp $IMAGE_PATH $PROXMOX_USER@$PROXMOX_HOST:$REMOTE_PATH - - echo "Restoring as VMID $TEMPLATE_VMID" - ssh $PROXMOX_USER@$PROXMOX_HOST " - cd $REMOTE_PATH - cp $IMAGE $REMOTE_NAME - - qm destroy $TEMPLATE_VMID --purge || true - qmrestore $REMOTE_PATH $TEMPLATE_VMID --unique - qm template $TEMPLATE_VMID - - echo 'Cloning to $LATEST_TEMPLATE_VMID as latest' - qm destroy $LATEST_TEMPLATE_VMID --purge || true - qm clone $TEMPLATE_VMID $LATEST_TEMPLATE_VMID --name nixos-base-latest - qm template $TEMPLATE_VMID - " + - name: Run Upload Template Runbook + run: | + ./sripts/run_ancible_ci.sh release: name: Release Image diff --git a/.gitignore b/.gitignore index 261fa7c..8d7d6f1 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ result-* # ---> Ansible *.retry +*.vault_pass.txt diff --git a/ansible.cfg b/ansible.cfg deleted file mode 100644 index e69de29..0000000 diff --git a/ansible/ANSIBLE.md b/ansible/ANSIBLE.md deleted file mode 100644 index d363b32..0000000 --- a/ansible/ANSIBLE.md +++ /dev/null @@ -1 +0,0 @@ -ansible-galaxy collection install -r requirements.yml diff --git a/ansible/playbooks/create-template.yml b/ansible/playbooks/create-template.yml deleted file mode 100644 index c84227c..0000000 --- a/ansible/playbooks/create-template.yml +++ /dev/null @@ -1,16 +0,0 @@ -- name: Restore and Convert to Template on Proxmox - hosts: proxmox # Target the Proxmox host - become: true # Need root/sudo on Proxmox host for qm commands - - vars: - # VM/Template specifics (can be passed via --extra-vars or from group_vars) - vmid_base_template: "{{ template_vmid }}" - vmname_base_template: "{{ template_vm_name }}" - vmid_latest_template: "{{ latest_template_vmid }}" - vmname_latest_template: "{{ latest_template_vm_name }}" - - # Configuration for the restored VM - cpu_cores: 2 - memory_mb: 2048 - - tasks: diff --git a/ansible/playbooks/image-deploy.yml b/ansible/playbooks/image-deploy.yml deleted file mode 100644 index 1dbc2b9..0000000 --- a/ansible/playbooks/image-deploy.yml +++ /dev/null @@ -1,130 +0,0 @@ ---- -- name: Build and Upload NixOS Image - hosts: localhost # Run NixOS build and image upload on the CI runner or local machine - gather_facts: false # No need to gather facts for localhost - - vars: - nixos_build_path: "{{ playbook_dir }}/../" # Path to your flake.nix - result_symlink_path: "{{ nixos_build_path }}/result" # Expected symlink output from Nix - dest_dir: "{{ dest_image_dir }}" # From group_vars/all.yml - - tasks: - - name: Ensure NixOS image build script is executable - ansible.builtin.file: - path: "{{ playbook_dir }}/../scripts/build_nixos_image.sh" - mode: "0755" - - - name: Build NixOS image (creates result/ symlink) - ansible.builtin.command: "{{ playbook_dir }}/../scripts/build_nixos_image.sh" - args: - chdir: "{{ nixos_build_path }}" - register: nixos_build_result - changed_when: nixos_build_result.rc == 0 # Consider it changed if build succeeds - - - name: Get built image file (.vma.zst) from result/ - ansible.builtin.find: - paths: "{{ result_symlink_path }}" - patterns: "*.vma.zst" - file_type: file # Ensure it's a file - register: built_image_files - delegate_to: localhost - - - name: Fail if no image was built - ansible.builtin.fail: - msg: "No .vma.zst image file found in {{ result_symlink_path }}/" - when: built_image_files.files | length == 0 - delegate_to: localhost - - - name: Set fact for built image path and filename - ansible.builtin.set_fact: - local_image_path: "{{ built_image_files.files[0].path | realpath }}" - image_filename: "{{ built_image_files.files[0].path | basename }}" - delegate_to: localhost - - - name: Display paths (for debugging) - ansible.builtin.debug: - msg: "Local image path: {{ local_image_path }}, Filename: {{ image_filename }}" - - - name: Copy image to Proxmox server - ansible.builtin.copy: - src: "{{ local_image_path }}" - dest: "{{ dest_dir }}{{ image_filename }}" - mode: "0644" # Ensure correct permissions on the destination - - - name: Clean up local build result symlink - ansible.builtin.file: - path: "{{ result_symlink_path }}" - state: absent - delegate_to: localhost - - - name: Clean up local store paths (optional, for disk space on CI) - ansible.builtin.command: "nix store gc" - args: - chdir: "{{ nixos_build_path }}" - changed_when: true # Always consider it a change - -- name: Restore and Convert to Template on Proxmox - hosts: proxmox_servers # Target the Proxmox host - become: true # Need root/sudo on Proxmox host for qm commands - - vars: - # Use variables from group_vars/all.yml and vault.yml - # Access API credentials from vault for this part - proxmox_api_user_id: "{{ proxmox_ci_api_user_name }}@{{ proxmox_ci_api_user_realm }}" - proxmox_api_token_id: "{{ proxmox_ci_api_token_id }}" - proxmox_api_token_secret: "{{ proxmox_ci_api_token_secret }}" - - # VM/Template specifics (can be passed via --extra-vars or from group_vars) - vmid_base_template: "{{ template_vmid }}" - vmname_base_template: "{{ template_vm_name }}" - vmid_latest_template: "{{ latest_template_vmid }}" - vmname_latest_template: "{{ latest_template_vm_name }}" - - # Configuration for the restored VM - cpu_cores: 2 - memory_mb: 2048 - - tasks: - - name: Set full image path on Proxmox - ansible.builtin.set_fact: - remote_image_path: "{{ dest_image_dir }}{{ image_filename }}" - delegate_to: localhost # Run this locally to set a fact accessible globally - - - name: Destroy existing base template VM (if it exists) - ansible.builtin.shell: "qm destroy {{ vmid_base_template }} --purge || true" - args: - warn: no - changed_when: false # Assume idempotency; if it didn't exist, no change - failed_when: false # Don't fail if VM isn't found - - - name: Destroy existing 'latest' template VM (if it exists) - ansible.builtin.shell: "qm destroy {{ vmid_latest_template }} --purge || true" - args: - warn: no - changed_when: false - failed_when: false - - - name: Restore VM from image to base template VMID - ansible.builtin.command: > - qmrestore {{ remote_image_path }} {{ vmid_base_template }} --unique true --name {{ vmname_base_template }} --storage {{ storage_name }} - args: - creates: "/etc/pve/qemu-server/{{ vmid_base_template }}.conf" # Idempotency check: only run if config file doesn't exist - - - name: Set CPU and memory for the base template VM - ansible.builtin.command: > - qm set {{ vmid_base_template }} --cores {{ cpu_cores }} --memory {{ memory_mb }} - # This task is not fully idempotent; it will always try to set. - # You'd need complex 'when' conditions to check current settings. - - - name: Convert base template VM to a template - ansible.builtin.command: "qm template {{ vmid_base_template }}" - # This command is largely idempotent for the `qm template` operation itself. - - - name: Clone base template to 'latest' template VMID - ansible.builtin.command: > - qm clone {{ vmid_base_template }} {{ vmid_latest_template }} --name {{ vmname_latest_template }} --full --storage {{ storage_name }} - args: - creates: "/etc/pve/qemu-server/{{ vmid_latest_template }}.conf" # Idempotency check: only run if config file doesn't exist - - - name: Convert 'latest' template VM to a template - ansible.builtin.command: "qm template {{ vmid_latest_template }}" diff --git a/ansible/playbooks/upload-image.yml b/ansible/playbooks/upload-image.yml deleted file mode 100644 index 300c785..0000000 --- a/ansible/playbooks/upload-image.yml +++ /dev/null @@ -1,38 +0,0 @@ -- name: Build and Upload NixOS Image, Restore and Convert to Template - hosts: proxmox - gather_facts: false - - vars: - image_dir: "{{ playbook_dir }}/../result" - dest_dir: "/var/lib/vz/dump/" - - tasks: - - name: Get built image file (.vma.zst) from result/ - ansible.builtin.find: - paths: "{{ result_path }}" - patterns: "*.vma.zst" - file_type: file # Ensure it's a file - register: built_image_files - delegate_to: localhost - - - name: Fail if no image was built - ansible.builtin.fail: - msg: "No .vma.zst image file found in {{ result_path }}/" - when: built_image_files.files | length == 0 - delegate_to: localhost - - - name: Set fact for built image path and filename - ansible.builtin.set_fact: - local_image_path: "{{ built_image_files.files[0].path | realpath }}" - image_filename: "{{ built_image_files.files[0].path | basename }}" - delegate_to: localhost - - - name: Display paths (for debugging) - ansible.builtin.debug: - msg: "Local image path: {{ local_image_path }}, Filename: {{ image_filename }}" - - - name: Copy image to Proxmox server - ansible.builtin.copy: - src: "{{ local_image_path }}" - dest: "{{ dest_dir }}" - mode: "0644" # Ensure correct permissions on the destination diff --git a/ansible/roles/create-template/tasks/main.yml b/ansible/roles/create-template/tasks/main.yml index 3247fa1..a8c46e7 100644 --- a/ansible/roles/create-template/tasks/main.yml +++ b/ansible/roles/create-template/tasks/main.yml @@ -1,37 +1,37 @@ - name: Set full image path on Proxmox ansible.builtin.set_fact: remote_image_path: "{{ dest_image_path }}{{ image_filename }}" - delegate_to: localhost # Run this locally to set a fact accessible globally + delegate_to: localhost -- name: Destroy existing backup template VM (if it exists) - ansible.builtin.shell: "qm destroy {{ vmid_backup_template }} --purge || true" - # args: - # warn: no - # changed_when: false # Assume idempotency; if it didn't exist, no change - failed_when: false # Don't fail if VM isn't found +- name: Check if 'backup' template VM exists + ansible.builtin.command: "qm status {{ vmid_backup_template }}" + register: backup_vm_status + failed_when: false + changed_when: false -- name: Clone 'lastest' template to 'backup' template VMID - ansible.builtin.command: > - qm clone {{ vmid_latest_template }} {{ vmid_backup_template }} --name {{ vmname_backup_template }} --full - # args: - # creates: "/etc/pve/qemu-server/{{ vmid_backup_template }}.conf" # Idempotency check: only run if config file doesn't exist - # failed_when: false # Don't fail if VM isn't found +- name: Check if 'latest' template VM exists + ansible.builtin.command: "qm status {{ vmid_latest_template }}" + register: latest_vm_status + failed_when: false + changed_when: false -- name: Convert 'backup' template VM to a template - ansible.builtin.command: "qm template {{ vmid_backup_template }}" +- name: Destroy existing 'backup' template VM (to ensure a clean slate for rotation) + ansible.builtin.command: "qm destroy {{ vmid_backup_template }} --purge" + when: backup_vm_status.rc == 0 # Only destroy if it actually exists + register: destroy_backup_result -- name: Destroy existing backup template VM (if it exists) - ansible.builtin.shell: "qm destroy {{ vmid_backup_template }} --purge || true" +- name: Clone 'latest' template to 'backup' template VMID (if 'latest' exists) + ansible.builtin.shell: | + qm clone {{ vmid_latest_template }} {{ vmid_backup_template }} --name {{ vmname_backup_template }} --full --storage {{ storage_name }} + qm template {{ vmid_backup_template }} + qm destroy {{ vmid_latest_template }} --purge + when: latest_vm_status.rc == 0 # Only clone if 'latest' VM exists + register: clone_to_backup_result - name: Restore VM from image to 'latest' template VMID - ansible.builtin.command: > - qmrestore {{ remote_image_path }} {{ vmid_latest_template }} --unique true - # args: - # creates: "/etc/pve/qemu-server/{{ vmid_latest_template }}.conf" # Idempotency check: only run if config file doesn't exist - -- name: Set CPU and memory for the base template VM - ansible.builtin.command: > + ansible.builtin.shell: | + qmrestore {{ remote_image_path }} {{ vmid_latest_template }} --unique true --storage {{ storage_name }} qm set {{ vmid_latest_template }} --cores {{ cpu_cores }} --memory {{ memory_mb }} --name {{ vmname_latest_template }} - -- name: Convert 'backup' template VM to a template - ansible.builtin.command: "qm template {{ vmid_latest_template }}" + qm template {{ vmid_latest_template }} + register: restore_new_latest_result + changed_when: restore_new_latest_result.rc == 0 diff --git a/ansible/vault.yml b/ansible/vault.yml deleted file mode 100644 index 8c31bfb..0000000 --- a/ansible/vault.yml +++ /dev/null @@ -1,15 +0,0 @@ -# To edit this file: ansible-vault edit ansible/vault.yml - -# For initial Proxmox user creation (using root@pam to create the API user) -proxmox_root_password: "YOUR_PROXMOX_ROOT_PASSWORD_HERE" # CHANGE THIS AND ENCRYPT - -# For the dedicated Proxmox API user and token (for CI/CD) -proxmox_ci_api_user_name: cicd-api-user -proxmox_ci_api_user_realm: pam -proxmox_ci_api_user_password: "SUPER_STRONG_PASSWORD_FOR_API_USER" # CHANGE THIS AND ENCRYPT - -proxmox_ci_api_token_id: cicd-deploy-token -# The 'value' of the API token secret should be generated by 'pveum' or 'proxmox_api_token' module. -# You will get this after running proxmox_setup.yml for the first time. -# Then update this vault.yml with the actual secret. -proxmox_ci_api_token_secret: "pveum_token_secret_from_first_run_here" # POPULATE THIS AFTER FIRST RUN AND ENCRYPT diff --git a/scripts/build_nixos_image.sh b/scripts/build_nixos_image.sh new file mode 100644 index 0000000..7017dbe --- /dev/null +++ b/scripts/build_nixos_image.sh @@ -0,0 +1,9 @@ +#!/bin/bash +set -euo pipefail + +# This script assumes 'flake.nix' and 'configuration.nix' are in the parent directory +# and outputs the result to a symlink named 'result' + +echo "Building NixOS image..." +nix build .#nixosConfigurations.proxmox-vm.config.system.build.qemu-image +echo "NixOS image build complete." diff --git a/scripts/run_ancible_ci.sh b/scripts/run_ancible_ci.sh new file mode 100644 index 0000000..6443b2f --- /dev/null +++ b/scripts/run_ancible_ci.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euo pipefail + +# Navigate to the ansible directory +cd ansible + +# Run the image deployment playbook +echo "Running Ansible upload-template playbook..." +ansible-playbook upload-template.yml \ + -e "cpu_cores=4" \ + -e "memory_mb=4096" + +echo "Ansible playbook completed."