From ac06a8829a1b0243d69dbdeb9210438b61f25eb7 Mon Sep 17 00:00:00 2001 From: moeny-matt Date: Thu, 3 Apr 2025 16:36:10 -0400 Subject: [PATCH] Updates to Alpine build scripts --- .gitignore | 3 +- README.md | 53 +++++++++++++++++-- bolt_vm_automation/plans/create_alpine.yaml | 30 ++++++++++- bolt_vm_automation/plans/create_ubuntu.yaml | 2 +- bolt_vm_automation/tasks/add_dns_a_record.sh | 33 ++++++++++++ .../tasks/delete_dns_a_record.sh | 23 ++++++++ bolt_vm_automation/tasks/install_alpine.sh | 4 +- .../tasks/install_docker_alpine.sh | 12 ++++- .../tasks/install_packages_alpine.sh | 5 +- .../tasks/system_setup_alpine.sh | 10 +++- 10 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 bolt_vm_automation/tasks/add_dns_a_record.sh create mode 100644 bolt_vm_automation/tasks/delete_dns_a_record.sh diff --git a/.gitignore b/.gitignore index 555bba8..62e2251 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -alpine-iso \ No newline at end of file +alpine-iso +keys \ No newline at end of file diff --git a/README.md b/README.md index f1594d5..983b52d 100644 --- a/README.md +++ b/README.md @@ -121,10 +121,55 @@ Update the parameters provided to the below plan run command as needed. ```bash cd bolt_vm_automation -bolt plan run bolt_vm_automation::create_vm \ - target=siderack \ +bolt plan run bolt_vm_automation::create_ubuntu \ + target=vortex \ vm_name=moeny-bank01 \ ip_with_cidr=100.40.223.189/24 \ - hostname=moeny-bank01 \ - network=br0 + hostname=moeny-bank01 +``` + +## Alpine VMs + +There are now separate plans for generating a VM using Alpine and Ubuntu. [create_alpine](bolt_vm_automation/plans/create_alpine.yaml) should be run for Alpine and [create_ubuntu](bolt_vm_automation/plans/create_ubuntu.yaml) should be run for Ubuntu. These plans each run tasks tailored for the appropriate distribution. + +Below is a sample command to run the Alpine bolt plan. + +```bash +bolt plan run bolt_vm_automation::create_alpine \ + vm_name=moeny-service \ + ip_with_cidr=100.40.223.189/24 \ + hostname=moeny-service \ + add_a_record_bool=true \ + dns_hostname=service +``` + +Note that `add_a_record_bool` must be set to `true` if you would like an A record for the VM to be added to the DNS server zone file, as it is `false` by default. If using this functionality, `dns_hostname` should also be provided and optionally `dns_ttl` if you do not want the default of `3600`. The ability to interact with the DNS server depends on having set up a TSIG key on your DNS server for dynamic updates and storing a copy of your `tsig.key` file in a directory called `keys` at the root of this project. If either of these conditions have not been met, do not attempt to use this functionality. For more information on setting up dynamic DNS with a TSIG key, see our [bind9](https://gitea.moeny.ai/moeny/bind9) repo. + +Similarly, `install_docker_bool` can be set to `false` if you do not want docker to be installed on the VM. It is true by default. + +For more detailed logging on the `bolt plan run` add the `-v` flag at the end of the command. + +If you want to delete an A record that you have added, you can use the [`delete_dns_a_record`](bolt_vm_automation/tasks/delete_dns_a_record.sh) task. You'll just need to provide it with the dns_hostname you set. Here's a sample command. + +```bash +bolt task run bolt_vm_automation::delete_dns_a_record dns_hostname=service --targets localhost +``` + +Lastly, even though it is designed to be run with the `create_alpine` plan, you can also run the [`add_dns_a_record`](bolt_vm_automation/tasks/add_dns_a_record.sh) task on its own. You'll just need to provide it a few parameters. Here's a sample command. + +```bash +bolt task run bolt_vm_automation::add_dns_a_record add_a_record_bool=true ip_with_cidr=100.40.223.189/24 dns_hostname=service dns_ttl=3600 --targets localhost +``` + +Alternatively, to update DNS with the `nsupdate` command directly from the terminal, run something like the following with the path to your `tsig.key`: + +```bash +nsupdate -k ../../keys/tsig.key << EOF +server ns1.moeny.ai +zone moeny.ai +update add service.moeny.ai 3600 A 6.5.2.5 +send +EOF + +ssh moeny@ns1.moeny.ai "sudo rndc sync moeny.ai" ``` \ No newline at end of file diff --git a/bolt_vm_automation/plans/create_alpine.yaml b/bolt_vm_automation/plans/create_alpine.yaml index ef5ee79..35d2673 100644 --- a/bolt_vm_automation/plans/create_alpine.yaml +++ b/bolt_vm_automation/plans/create_alpine.yaml @@ -27,7 +27,7 @@ parameters: disk_path: type: String description: "Base path for disk images" - default: "/mnt/nfs/kvm-images" + default: "/mnt/nfs/moeny-images" network: type: String description: "Network to connect the VM to" @@ -67,6 +67,23 @@ parameters: type: String description: "Tertiary nameserver for the VM" default: "1.1.1.1" + install_docker_bool: + type: Boolean + description: "Whether to install Docker on the VM" + default: true + # DNS Variables + add_a_record_bool: + type: Boolean + description: "Whether to add a DNS A record for the VM" + default: false + dns_hostname: + type: String + description: "Hostname for the DNS A record" + default: "vm-template-staging" + dns_ttl: + type: Integer + description: "TTL for the DNS A record" + default: 3600 steps: - name: create_vm @@ -103,6 +120,7 @@ steps: task: bolt_vm_automation::install_docker_alpine targets: localhost parameters: + install_docker_bool: $install_docker_bool staging_ip: $staging_ip - name: system_setup @@ -118,5 +136,15 @@ steps: nameserver3: $nameserver3 staging_ip: $staging_ip + - name: add_dns_a_record + description: Add a DNS A record for the VM + task: bolt_vm_automation::add_dns_a_record + targets: localhost + parameters: + add_a_record_bool: $add_a_record_bool + ip_with_cidr: $ip_with_cidr + dns_hostname: $dns_hostname + dns_ttl: $dns_ttl + return: message: "VM ${vm_name} created and updated successfully!" diff --git a/bolt_vm_automation/plans/create_ubuntu.yaml b/bolt_vm_automation/plans/create_ubuntu.yaml index 2cedac7..886be0f 100644 --- a/bolt_vm_automation/plans/create_ubuntu.yaml +++ b/bolt_vm_automation/plans/create_ubuntu.yaml @@ -27,7 +27,7 @@ parameters: disk_path: type: String description: "Base path for disk images" - default: "/mnt/nfs/kvm-images" + default: "/mnt/nfs/moeny-images" network: type: String description: "Network to connect the VM to" diff --git a/bolt_vm_automation/tasks/add_dns_a_record.sh b/bolt_vm_automation/tasks/add_dns_a_record.sh new file mode 100644 index 0000000..0f5ec4a --- /dev/null +++ b/bolt_vm_automation/tasks/add_dns_a_record.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Bolt environment variables +ADD_A_RECORD="${PT_add_a_record_bool}" +IP="${PT_ip_with_cidr}" +HOSTNAME="${PT_dns_hostname}" +TTL="${PT_dns_ttl}" + +# Check if Docker installation is requested +if [ "$ADD_A_RECORD" != "true" ]; then + echo '{"status": "skipped", "message": "A Record addition not requested, skipping..."}' + exit 0 +fi + +# Check if required parameters are provided +if [ -z "$IP" ] || [ -z "$HOSTNAME" ] || [ -z "$TTL" ]; then + echo '{"status": "failure", "message": "Error: Both ip_with_cidr, dns_hostname and ttl parameters must be provided"}' + exit 1 +fi + +# Create DNS A record +IP_ADDRESS=$(echo ${IP} | cut -d'/' -f1) +nsupdate -k ../../keys/tsig.key << EOF +server ns1.moeny.ai +zone moeny.ai +update add ${HOSTNAME}.moeny.ai ${TTL} A ${IP_ADDRESS} +send +EOF + +# Force zone file update on DNS server +ssh moeny@ns1.moeny.ai "sudo rndc sync moeny.ai" + +echo '{"status": "success", "message": "A Record successfully added."}' \ No newline at end of file diff --git a/bolt_vm_automation/tasks/delete_dns_a_record.sh b/bolt_vm_automation/tasks/delete_dns_a_record.sh new file mode 100644 index 0000000..7816fbb --- /dev/null +++ b/bolt_vm_automation/tasks/delete_dns_a_record.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Bolt environment variables +HOSTNAME="${PT_dns_hostname}" + +# Check if required parameters are provided +if [ -z "$HOSTNAME" ]; then + echo '{"status": "failure", "message": "Error: dns_hostname parameter must be provided"}' + exit 1 +fi + +# Delete DNS A record +nsupdate -k ../../keys/tsig.key << EOF +server ns1.moeny.ai +zone moeny.ai +update delete ${HOSTNAME}.moeny.ai A +send +EOF + +# Force zone file update on DNS server +ssh moeny@ns1.moeny.ai "sudo rndc sync moeny.ai" + +echo '{"status": "success", "message": "A Record successfully deleted."}' \ No newline at end of file diff --git a/bolt_vm_automation/tasks/install_alpine.sh b/bolt_vm_automation/tasks/install_alpine.sh index 7586057..f9f68b7 100644 --- a/bolt_vm_automation/tasks/install_alpine.sh +++ b/bolt_vm_automation/tasks/install_alpine.sh @@ -49,9 +49,9 @@ sleep 30 # Verify installation by trying to SSH if ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@${STAGING_IP} "echo 'VM is running'"; then - echo "Alpine installation completed successfully" + echo '{"status": "success", "message": "Alpine installation completed successfully"}' exit 0 else - echo "Failed to install Alpine" + echo '{"status": "failure", "message": "Failed to install Alpine"}' exit 1 fi \ No newline at end of file diff --git a/bolt_vm_automation/tasks/install_docker_alpine.sh b/bolt_vm_automation/tasks/install_docker_alpine.sh index 0945314..1c76958 100644 --- a/bolt_vm_automation/tasks/install_docker_alpine.sh +++ b/bolt_vm_automation/tasks/install_docker_alpine.sh @@ -1,8 +1,16 @@ #!/bin/bash # Input Variables +INSTALL_DOCKER="${PT_install_docker_bool}" STAGING_IP="${PT_staging_ip}" +# Check if Docker installation is requested +if [ "$INSTALL_DOCKER" != "true" ]; then + # Output JSON that Bolt will understand + echo '{"status": "skipped", "message": "Docker installation not requested, skipping..."}' + exit 0 +fi + # Update package list and install Docker ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "apk update && apk add --no-cache docker docker-cli docker-cli-compose" @@ -14,9 +22,9 @@ ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "rc-service docker start && r # Verify installation if ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "docker --version" > /dev/null 2>&1; then - echo "Docker installed successfully" + echo '{"status": "success", "message": "Docker installed successfully"}' exit 0 else - echo "Docker installation failed" + echo '{"status": "failure", "message": "Docker installation failed"}' exit 1 fi \ No newline at end of file diff --git a/bolt_vm_automation/tasks/install_packages_alpine.sh b/bolt_vm_automation/tasks/install_packages_alpine.sh index 797aff9..f56ff2f 100644 --- a/bolt_vm_automation/tasks/install_packages_alpine.sh +++ b/bolt_vm_automation/tasks/install_packages_alpine.sh @@ -7,7 +7,7 @@ STAGING_IP="${PT_staging_ip}" ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "sed -i '3s/^#//' /etc/apk/repositories" # Install required packages -ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "apk update && apk add --no-cache vim fping htop sudo bash mtr" +ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "apk update && apk add --no-cache vim fping htop sudo bash mtr rsync tmux" # Change default shell to bash ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "sed -i -E '/^(root|moeny):/ s:/bin/sh$:/bin/bash:' /etc/passwd" @@ -20,3 +20,6 @@ ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "addgroup sudo;addgroup moeny # Set no password to sudo group ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "echo '%sudo ALL=(ALL) NOPASSWD: ALL' | tee -a /etc/sudoers.d/nopasswd_sudo_group" + +# Aliases for ll and la +ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "sudo sed -i '1i # set ls -l and ls -a aliases\nalias ll='\''ls -l'\''\nalias la='\''ls -a'\''\n' /etc/bash/bashrc" diff --git a/bolt_vm_automation/tasks/system_setup_alpine.sh b/bolt_vm_automation/tasks/system_setup_alpine.sh index f185d12..72802c9 100644 --- a/bolt_vm_automation/tasks/system_setup_alpine.sh +++ b/bolt_vm_automation/tasks/system_setup_alpine.sh @@ -12,7 +12,7 @@ STAGING_IP="${PT_staging_ip}" # Check if all required parameters are provided if [ -z "$IP" ] || [ -z "$HOSTNAME" ] || [ -z "$DHCP" ] || [ -z "$GATEWAY" ] || [ -z "$NAMESERVER1" ] || [ -z "$NAMESERVER2" ] || [ -z "$NAMESERVER3" ]; then - echo "Missing required parameters. All parameters must be provided." + echo '{"status": "failure", "message": "Missing required parameters. All parameters must be provided."}' exit 1 fi @@ -54,7 +54,13 @@ ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "sed -i 's/127.0.0.1.*/127.0. # Enable and start iptables service ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "rc-update add iptables default && rc-service iptables start" -echo "System configuration completed successfully" +# Generate new SSH host keys +ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "rm /etc/ssh/ssh_host_* && \ + ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N \"\" && \ + ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N \"\" && \ + ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N \"\"" + +echo '{"status": "success", "message": "System configuration completed successfully"}' # Reboot the system ssh -o StrictHostKeyChecking=no root@${STAGING_IP} "nohup sh -c '(sleep 2 && reboot) &' > /dev/null 2>&1"