From 3a71e5e75bbc51d9e9007caa12627b3683a203ee Mon Sep 17 00:00:00 2001 From: gwen Date: Fri, 21 Nov 2025 12:06:40 +0100 Subject: [PATCH] vmcreator --- vmcreator/create_vm.sh | 1 + vmcreator/create_vm.yml | 169 ++++++++++++++++++++++++++++++++++++++++ vmcreator/hosts | 1 + vmcreator/readme.rst | 43 ++++++++++ 4 files changed, 214 insertions(+) create mode 100755 vmcreator/create_vm.sh create mode 100644 vmcreator/create_vm.yml create mode 100644 vmcreator/hosts create mode 100644 vmcreator/readme.rst diff --git a/vmcreator/create_vm.sh b/vmcreator/create_vm.sh new file mode 100755 index 0000000..f2bccc8 --- /dev/null +++ b/vmcreator/create_vm.sh @@ -0,0 +1 @@ +ansible-playbook -i hosts create_vm.yml diff --git a/vmcreator/create_vm.yml b/vmcreator/create_vm.yml new file mode 100644 index 0000000..1c46188 --- /dev/null +++ b/vmcreator/create_vm.yml @@ -0,0 +1,169 @@ +--- +- name: Ensure multipass is installed and create a VM with cloud-init + hosts: localhost + gather_facts: yes + vars_prompt: + - name: vm_name + prompt: "What is the VM name (don't use spaces)?" + private: no + default: testvm + vars: + vm_image: 24.04 + vm_disk: 15G + vm_memory: 4G + vm_cpus: 1 + ssh_key_name: "{{ vm_name }}_ssh_key" + + tasks: + - name: Check if VM already exists + command: multipass list --format json + register: vm_list_json + + - name: Parse VM list + set_fact: + vm_exists: "{{ vm_name in ((vm_list_json.stdout | from_json).list | map(attribute='name') | list) }}" + + - name: Output message if VM already exists + debug: + msg: "VM with name '{{ vm_name }}' already exists. No action will be taken." + when: vm_exists + + - name: Gather OS facts + setup: + filter: "ansible_distribution" + when: not vm_exists + + - name: Detect OS + set_fact: + os_type: "{{ ansible_facts['distribution'] }}" + + - name: Check if Homebrew is installed (macOS) + command: brew --version + register: homebrew_check + ignore_errors: yes + when: os_type == "MacOSX" and not vm_exists + + - name: Install Homebrew (macOS) + shell: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + when: os_type == "MacOSX" and homebrew_check.failed and not vm_exists + + - name: Check if multipass is installed + shell: "command -v multipass || echo 'not found'" + register: multipass_check + changed_when: false + + - name: Install multipass using Homebrew (macOS) + homebrew: + name: multipass + state: present + when: + - os_type == "MacOSX" + - multipass_check.stdout == "not found" + - not vm_exists + + - name: Install multipass using snap (Ubuntu) + snap: + name: multipass + state: present + when: + - os_type == "Ubuntu" + - multipass_check.stdout == "not found" + - not vm_exists + + - name: Generate SSH key pair + command: ssh-keygen -t rsa -b 2048 -f ./{{ ssh_key_name }} -N "" -C "ubuntu" + args: + creates: ./{{ ssh_key_name }} + when: not vm_exists + + - name: Read the public SSH key + command: cat ./{{ ssh_key_name }}.pub + register: ssh_public_key + when: not vm_exists + + - name: Create cloud-init.yaml file + copy: + dest: ./cloud-init.yaml + content: | + ## cloud-init + + users: + - name: ubuntu + ssh-authorized-keys: + - {{ ssh_public_key.stdout }} + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + groups: sudo + shell: /bin/bash + + package_update: true + packages: + - python3-pip + - python3 + - python-is-python3 + - python3-venv + + hostname: {{ vm_name }} + fqdn: {{ vm_name }}.local + + final_message: "The instance is now up for $UPTIME seconds" + when: not vm_exists + + - name: Verify cloud-init.yaml file exists + stat: + path: ./cloud-init.yaml + register: cloud_init_file + when: not vm_exists + + - name: Fail if cloud-init.yaml does not exist + fail: + msg: "cloud-init.yaml file does not exist" + when: + - not vm_exists + - cloud_init_file is defined + - not cloud_init_file.stat.exists | default(false) + + - name: Launch VM with multipass + command: multipass launch {{ vm_image }} --name {{ vm_name }} --disk {{ vm_disk }} -m {{ vm_memory }} --cloud-init ./cloud-init.yaml + register: vm_launch + when: not vm_exists + + - name: Get VM info + command: multipass info {{ vm_name }} --format json + register: vm_info_json + when: not vm_exists + + - name: Parse VM IP address + set_fact: + vm_ip: "{{ (vm_info_json.stdout | from_json).info[vm_name].ipv4[0] }}" + when: not vm_exists + + - name: Generate inventory file + copy: + dest: ./inventory.yml + content: | + all: + hosts: + {{ vm_name }}: + ansible_host: {{ vm_ip }} + ansible_python_interpreter: /usr/bin/python3 + vars: + ansible_user: ubuntu + ansible_ssh_private_key_file: ./{{ ssh_key_name }} + when: not vm_exists + + - name: Add VM hostname to local /etc/hosts + become: yes + lineinfile: + path: /etc/hosts + line: "{{ vm_ip }} {{ vm_name }}.local" + state: present + when: not vm_exists + + - name: Wait for VM to be ready + wait_for: + host: "{{ vm_ip }}" + port: 22 + delay: 10 + timeout: 300 + when: not vm_exists + diff --git a/vmcreator/hosts b/vmcreator/hosts new file mode 100644 index 0000000..2302eda --- /dev/null +++ b/vmcreator/hosts @@ -0,0 +1 @@ +localhost ansible_connection=local diff --git a/vmcreator/readme.rst b/vmcreator/readme.rst new file mode 100644 index 0000000..fcfa68d --- /dev/null +++ b/vmcreator/readme.rst @@ -0,0 +1,43 @@ +VM Creator +=========== + +Just another ansible tool that automates a VM creation whit multipass. + +It reinforces the lauching of a manual script like this one:: + + multipass launch 24.04 --name XXX --cpus 8 --disk 100G -m 30G --cloud-init cloud-init.yaml + +Because this script has dependencies. it needs: + +- a cloud init file +- an ssh key +- a cloud init file + +.. important:: Needs to be root to do such a thing + +launch +--------- + +:: + + ./create_vm.sh + +Besides generating the VM, it generates: + +- an inventory in YAML format +- a dedicated ssh key + + +usage +-------- + +verify that the `testvm` VM is ready, launch this command in a terminal:: + + multipass list | grep testvm + +example output:: + + multipass list | grep testvm + testvm Running 10.190.208.122 Ubuntu 24.04 LTS + +