From f07cd9b9ca2e663cca5d9c9aa01009b8717ba3dc Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Thu, 29 Jul 2021 17:26:38 +0200 Subject: [PATCH] updates to Ansible 2.17 * host is now Ubuntu >=20.04 * add Ansible Lint support and GHA * add Devcontainer for easy ansible lint check --- .config/ansible-lint.yml | 15 +++ .devcontainer/devcontainer.json | 30 +++++ .devcontainer/docker-compose.yml | 17 +++ .devcontainer/install_requirements.sh | 6 + .github/workflows/ansible_lint.yml | 21 ++++ .vscode/settings.json | 10 ++ domain/create/defaults/main.yml | 117 +++++++++--------- domain/create/handlers/main.yml | 25 ++-- domain/create/tasks/autostart.yml | 18 +-- domain/create/tasks/base_image.yml | 13 +- domain/create/tasks/cloud_config.yml | 12 +- domain/create/tasks/configdrive.yml | 15 ++- domain/create/tasks/create_domain.yml | 21 ++-- domain/create/tasks/domain_id.yml | 20 +-- domain/create/tasks/extra_disk.yml | 9 +- domain/create/tasks/list.yml | 14 +-- domain/create/tasks/mac_and_ip.yml | 36 +++--- domain/create/tasks/main.yml | 116 ++++++++++------- domain/create/tasks/port_forward.yml | 20 +-- domain/create/tasks/ports.yml | 18 +-- domain/create/tasks/store_facts.yml | 30 ++--- domain/create/templates/cloud-config.yml.j2 | 6 +- .../create/templates/iptables-port-nat.sh.j2 | 2 +- domain/create/templates/libvirt_domains.j2 | 6 - domain/kill/tasks/images.yml | 6 +- domain/kill/tasks/main.yml | 15 ++- domain/kill/tasks/port_forward.yml | 6 +- domain/kill/tasks/shutdown.yml | 42 ++++--- domain/kill/tasks/store_facts.yml | 5 +- domain/kill/tasks/undefine.yml | 17 +-- domain/list/tasks/main.yml | 16 +-- domain/port_forward/defaults/main.yml | 16 +-- domain/port_forward/tasks/main.yml | 61 +++++---- host/provision/defaults/main.yml | 17 +-- host/provision/handlers/main.yml | 6 +- host/provision/tasks/main.yml | 41 +++--- images/ubuntu-cloud/defaults/main.yml | 5 +- images/ubuntu-cloud/tasks/main.yml | 82 ++++++------ images/ubuntu-cloud/tasks/store_facts.yml | 18 +-- meta/main.yml | 116 ++--------------- network/bridge/defaults/main.yml | 24 ++-- network/bridge/tasks/main.yml | 63 +++++----- requirements.yml | 3 + 43 files changed, 620 insertions(+), 536 deletions(-) create mode 100644 .config/ansible-lint.yml create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100755 .devcontainer/install_requirements.sh create mode 100644 .github/workflows/ansible_lint.yml create mode 100644 .vscode/settings.json delete mode 100644 domain/create/templates/libvirt_domains.j2 create mode 100644 requirements.yml diff --git a/.config/ansible-lint.yml b/.config/ansible-lint.yml new file mode 100644 index 0000000..9e39fc1 --- /dev/null +++ b/.config/ansible-lint.yml @@ -0,0 +1,15 @@ +--- +exclude_paths: + - ".github" + - "/docker-compose.yml" + - "/docker-compose.*.yml" + +kinds: + - playbook: "tests/urlshort_simple.yml" + +skip_list: + - package-latest # we don't change this role with all the versions + - latest[git] # same + - role-name[path] # we nest roles here to avoid 1000 dependencies + - var-naming[pattern] # we use uppercase variables for stored facts + - var-naming[no-role-prefix] # our role variables don't follow this pattern diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..6544648 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +{ + "name": "libvirt-ansible-dev", + "dockerComposeFile": [ + "docker-compose.yml" + ], + "service": "ansible", + "overrideCommand": true, + "containerUser": "root", + "workspaceFolder": "/etc/ansible/roles/hicknhack-software.libvirt", + // "capAdd": ["SYS_ADMIN", "SYS_RESOURCE"], + // "securityOpt": ["seccomp=unconfined", "label=disable", "apparmor=unconfined"], + "updateRemoteUserUID": true, + "postStartCommand": ".devcontainer/install_requirements.sh", + "customizations": { + "vscode": { + "extensions": [ + "redhat.ansible" + ], + "settings": { + "files.associations": { + "**/defaults/*.yml": "ansible", + "**/handlers/*.yml": "ansible", + "**/tasks/*.yml": "ansible", + "**/vars/*.yml": "ansible", + "**/templates/*.j2": "ansible-jinja" + } + } + } + } +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..73f4ee7 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,17 @@ +--- +name: hnh-libvirt + +volumes: + ansible-colletions: + +services: + ansible: + image: "ghcr.io/ansible/community-ansible-dev-tools:latest" + volumes: + - ..:/etc/ansible/roles/hicknhack-software.libvirt + - ansible-colletions:/root/.ansible/collections + working_dir: /etc/ansible/roles/hicknhack-software.libvirt + tty: true + stdin_open: true + environment: + - ANSIBLE_HOST_KEY_CHECKING=false diff --git a/.devcontainer/install_requirements.sh b/.devcontainer/install_requirements.sh new file mode 100755 index 0000000..0481f61 --- /dev/null +++ b/.devcontainer/install_requirements.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -e + +pushd "$(dirname "${BASH_SOURCE[0]}")/.." >/dev/null + +ansible-galaxy install -r requirements.yml diff --git a/.github/workflows/ansible_lint.yml b/.github/workflows/ansible_lint.yml new file mode 100644 index 0000000..e8be03e --- /dev/null +++ b/.github/workflows/ansible_lint.yml @@ -0,0 +1,21 @@ +name: Ansible Lint + +on: push + +jobs: + ansible-lint: + name: "Run Ansible Lint" + + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Make Symlink + run: >- + mkdir -p /home/runner/.ansible/roles + && ln -s $(pwd) /home/runner/.ansible/roles/hicknhack-software.libvirt + + - name: Run Ansible Lint + uses: ansible/ansible-lint@main + with: + requirements_file: "requirements.yml" diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ada52d2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + "ansible.python.interpreterPath": "/bin/python3", + "files.associations": { + "**/defaults/*.yml": "ansible", + "**/handlers/*.yml": "ansible", + "**/tasks/*.yml": "ansible", + "**/vars/*.yml": "ansible", + "**/templates/*.j2": "ansible-jinja" + } +} diff --git a/domain/create/defaults/main.yml b/domain/create/defaults/main.yml index d1e39c8..8557dab 100644 --- a/domain/create/defaults/main.yml +++ b/domain/create/defaults/main.yml @@ -2,10 +2,10 @@ libvirt_domain: # basic arguments groups: [] # names of Ansible nodes/groups used to provision the domain - name: # name/uuid of the domain (empty means new uuid) - title: '' # title of the vm - description: '' # description of the vm - apt_mirror: '' + name: "{{ inventory_hostname }}" # name/uuid of the domain (empty means new uuid) + title: "" # title of the vm + description: "" # description of the vm + apt_mirror: "" # note: if you do not provide a domain_id each run will create a new vm! # host access ports @@ -21,19 +21,19 @@ libvirt_domain: vm: memory: "512MiB" # RAM memory available to the VM vcpu: 1 # number of cores designated to the VM - vcpu_placement: 'static' # options 'auto', 'static', defaults to 'numatune' + vcpu_placement: "static" # options 'auto', 'static', defaults to 'numatune' vcpu_cpuset: [] # list of host CPU numbers the VM can run on - networks: ['default'] # libvirts id of networks this VM is part of + networks: ["default"] # libvirts id of networks this VM is part of disk_size: "12G" # use this to change first disk size - features: ['acpi', 'apic', 'pae'] # vm features available + features: ["acpi", "apic", "pae"] # vm features available # features - serial_console: yes # make a console on serial port 0 available - vnc: no - autostart: yes # should the domain VM start after reboot of the host + serial_console: true # make a console on serial port 0 available + vnc: false + autostart: true # should the domain VM start after reboot of the host # Valid install_types: - install_type: 'base-image' # way to install the VM (this only affects the first run!) + install_type: "base-image" # way to install the VM (this only affects the first run!) # # 1. 'base-image' @@ -41,7 +41,7 @@ libvirt_domain: # a simple image base_image: path: # path to the cloud image for the domain - mode: 'snapshot' # options: snapshot, copy + mode: "snapshot" # options: snapshot, copy extra_disks: [] # - id: 'data-disk' # logical name of the disk (required) @@ -56,7 +56,7 @@ libvirt_domain: # lvm_group: '' # name of volume group (required) # cloud initialisation method - init_mode: 'cloud-config' # options: cloud-config, configdrive (empty will skip any initialisation) + init_mode: "cloud-config" # options: cloud-config, configdrive (empty will skip any initialisation) # # Cloud-Config @@ -67,14 +67,16 @@ libvirt_domain: # see https://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/view/head:/doc/examples/cloud-config-user-groups.txt cloud_config: users: - - name: 'ubuntu' - gecos: 'Ubuntu' - ssh-authorized-keys: [] # required! - shell: '/bin/bash' - sudo: 'ALL=(ALL) NOPASSWD:ALL' - groups: 'adm,audio,cdrom,dialout,floppy,video,plugdev,dip,netdev' # comma separated string! + - name: "ubuntu" + gecos: "Ubuntu" + ssh-authorized-keys: [] # required! + shell: "/bin/bash" + sudo: "ALL=(ALL) NOPASSWD:ALL" + groups: "adm,audio,cdrom,dialout,floppy,video,plugdev,dip,netdev" # comma separated string! bootcmd: [] - timezone: '' # like Europe/Berlin + timezone: "" # like Europe/Berlin + packages: + - python # # ConfigDrive @@ -85,7 +87,8 @@ libvirt_domain: # # all the options intended to show up in the configdrive meta_data.json configdrive: - meta_data: '' + meta_data: + "" # hostname: '{{ libvirt_result_domain_name }}' # username: 'Admin' # groups: 'Administrators' # comma separated string! @@ -94,15 +97,15 @@ libvirt_domain: # authorized_keys: ... # content of the user data (skipped if empty) - user_data: '' + user_data: "" # executed for content of first line # #ps1 => Powershell # rem cmd => Cmd/Batch # #! => Bash (if installed) - # extra file structure inside the configdrive - #extra_files: - # filename: text content + ## extra file structure inside the configdrive + # extra_files: + # filename: text content # libvirt os settings - see: https://libvirt.org/formatdomain.html#elementsOS os: "{{ libvirt_os_virtualized_x86_64 }}" @@ -128,7 +131,7 @@ libvirt_domain: # basic arguments libvirt_domain_groups: "{{ libvirt_domain.groups | default([], true) }}" # names of Ansible nodes/groups used to provision the domain -libvirt_domain_name: "{{ libvirt_domain.name | default('', true) }}" # name/uuid of the domain (empty means new uuid) +libvirt_domain_name: "{{ libvirt_domain.name | default(inventory_hostname, true) }}" # name/uuid of the domain (empty means new uuid) libvirt_domain_title: "{{ libvirt_domain.title | default('', true) }}" # title of the vm libvirt_domain_description: "{{ libvirt_domain.description | default('', true) }}" # description of the vm # note: if you do not provide a domain_id each run will create a new vm! @@ -144,7 +147,8 @@ libvirt_winrm_port: "{{ (libvirt_domain.host_ports | default({}, true)).winrm | # default VM configuration libvirt_vm_memory: "{{ (libvirt_domain.vm | default({}, true)).memory | default('512MiB', true) }}" # RAM memory available to the VM libvirt_vm_vcpu: "{{ (libvirt_domain.vm | default({}, true)).vcpu | default('1', true) }}" # number of cores designated to the VM -libvirt_vm_vcpu_placement: "{{ (libvirt_domain.vm | default({}, true)).vcpu_placement | default('static', true) }}" # options 'auto', 'static', defaults to 'numatune' +# options 'auto', 'static', defaults to 'numatune' +libvirt_vm_vcpu_placement: "{{ (libvirt_domain.vm | default({}, true)).vcpu_placement | default('static', true) }}" libvirt_vm_vcpu_cpuset: "{{ (libvirt_domain.vm | default({}, true)).vcpu_cpuset | default([], true) }}" # list of host CPU numbers the VM can run on libvirt_vm_networks: "{{ (libvirt_domain.vm | default({}, true)).networks | default(['default'], true) }}" # libvirts id of networks this VM is part of libvirt_vm_disk_size: "{{ (libvirt_domain.vm | default({}, true)).disk_size | default('12G', true) }}" # use this to change first disk size @@ -180,7 +184,7 @@ libvirt_extra_disks: "{{ libvirt_domain.extra_disks | default([], true) }}" # cloud initialisation method libvirt_init_mode: "{{ libvirt_domain.init_mode | default('cloud-config', true) }}" # options: cloud-config, configdrive (empty will skip any initialisation) -libvirt_apt_mirror: "{{ libvirt_domain.apt_mirror | default('', true) }}" +libvirt_apt_mirror: "{{ libvirt_domain.apt_mirror | default('', true) }}" # # Cloud-Config @@ -192,20 +196,30 @@ libvirt_apt_mirror: "{{ libvirt_domain.apt_mirror | default('', true) }}" libvirt_cloud_config_users: "{{ (libvirt_domain.cloud_config | default({}, true)).users | default([libvirt_cloud_config_default_user], true) }}" libvirt_cloud_config_default_user: - name: 'ubuntu' - gecos: 'Ubuntu' + name: "ubuntu" + gecos: "Ubuntu" ssh-authorized-keys: [] # required! - shell: '/bin/bash' - sudo: 'ALL=(ALL) NOPASSWD:ALL' - groups: 'adm,audio,cdrom,dialout,floppy,video,plugdev,dip,netdev' # comma separated string! + shell: "/bin/bash" + sudo: "ALL=(ALL) NOPASSWD:ALL" + groups: "adm,audio,cdrom,dialout,floppy,video,plugdev,dip,netdev" # comma separated string! libvirt_cloud_config_bootcmd: "{{ (libvirt_domain.cloud_config | default({}, true)).bootcmd | default([], true) }}" # example bootcmd that enables dhcp for ipv6 on ubuntu 16.04 guests -libvirt_cloud_config_ipv6_dhcp_bootcmd: [ cloud-init-per, once, ipv6-dhcp, "/bin/sh", "-c", "echo iface ens2 inet6 dhcp >> /etc/network/interfaces.d/51-cloud-init-ipv6.cfg" ] +libvirt_cloud_config_ipv6_dhcp_bootcmd: + [ + cloud-init-per, + once, + ipv6-dhcp, + "/bin/sh", + "-c", + "echo iface ens2 inet6 dhcp >> /etc/network/interfaces.d/51-cloud-init-ipv6.cfg", + ] libvirt_cloud_config_timezone: "{{ (libvirt_domain.cloud_config | default({}, true)).timezone | default('', true) }}" +libvirt_cloud_config_packages: "{{ (libvirt_domain.cloud_config | default({}, true)).packages | default([], true) | list }}" + # # ConfigDrive # =========== @@ -217,7 +231,7 @@ libvirt_cloud_config_timezone: "{{ (libvirt_domain.cloud_config | default({}, tr libvirt_configdrive_meta_data: "{{ (libvirt_domain.configdrive | default({}, true)).meta_data | default(libvirt_configdrive_default_meta_data, true) }}" libvirt_configdrive_default_meta_data: - hostname: '{{ libvirt_result_domain_name }}' + hostname: "{{ libvirt_result_domain_name }}" # username: 'Admin' # groups: 'Administrators' # comma separated string! # inject_user_password: True @@ -235,17 +249,17 @@ libvirt_configdrive_user_data: "{{ (libvirt_domain.configdrive | default({}, tru libvirt_configdrive_files: "{{ (libvirt_domain.configdrive | default({}, true)).extra_files | default({}, true) | combine(libvirt_configdrive_base_files) }}" libvirt_configdrive_base_files: - 'openstack/latest/meta_data.json': '{{ libvirt_configdrive_meta_data | to_json }}' - 'openstack/latest/user_data': '{{ libvirt_configdrive_user_data }}' + "openstack/latest/meta_data.json": "{{ libvirt_configdrive_meta_data | to_json }}" + "openstack/latest/user_data": "{{ libvirt_configdrive_user_data }}" # libvirt os settings - see: https://libvirt.org/formatdomain.html#elementsOS libvirt_os_virtualized_x86_64: - type: 'hvm' - type_arch: 'x86_64' + type: "hvm" + type_arch: "x86_64" libvirt_os_virtualized_x86: - type: 'hvm' - type_arch: 'i686' + type: "hvm" + type_arch: "i686" libvirt_os: "{{ libvirt_domain.os | default(libvirt_os_virtualized_x86_64, true) }}" # type: 'hvm' # options 'hvm'*, 'linux', 'exe' @@ -257,12 +271,12 @@ libvirt_os: "{{ libvirt_domain.os | default(libvirt_os_virtualized_x86_64, true) # # use these settings for easily migratable vms (default) libvirt_vm_cpu_migratable: - match: 'exact' # options 'minimum', 'exact', 'strict' - mode: 'custom' # options 'custom', 'host-model', 'host-passthrough' + match: "exact" # options 'minimum', 'exact', 'strict' + mode: "custom" # options 'custom', 'host-model', 'host-passthrough' # # use these settings for fast, supports nested virtualisation libvirt_vm_cpu_fast: - mode: 'host-model' # everything libvirt understands + mode: "host-model" # everything libvirt understands libvirt_vm_cpu: "{{ libvirt_domain.cpu | default(libvirt_vm_cpu_fast, true) }}" # more options: @@ -281,11 +295,11 @@ libvirt_vm_cpu: "{{ libvirt_domain.cpu | default(libvirt_vm_cpu_fast, true) }}" # ssh port foward configuration libvirt_ssh_base_port: 22000 # first host port for forwards to VM ssh libvirt_ssh_guest_port: 22 # guest port for ssh -libvirt_host_ssh_ip_address: "{{ ansible_default_ipv4.address }}" # host ip address where ssh_ports are made available +libvirt_host_ssh_ip_address: "{{ libvirt_host_vars.ansible_default_ipv4.address }}" # host ip address where ssh_ports are made available libvirt_host_ssh_destination_any: "0.0.0.0/0" # bind to any host ip subnet libvirt_host_ssh_destination_ip: "{{ libvirt_host_ssh_ip_address }}" # bind to any host ip subnet libvirt_host_ssh_destination: "{{ libvirt_host_ssh_destination_any }}" # ip subnet that is bound by port forwarding -libvirt_host_accept_all_ports: no # if enabled the firewall is configured to allow all ports of the vm being accessed +libvirt_host_accept_all_ports: false # if enabled the firewall is configured to allow all ports of the vm being accessed libvirt_rdp_base_port: 33890 # first host port for forwards to VM rdp libvirt_rdp_guest_port: 3389 # guest port for rdp @@ -296,13 +310,4 @@ libvirt_winrm_guest_port: 5986 # guest port for winrm (no ssl) # configuration options libvirt_images_path: "/var/lib/libvirt/images" # path on the host, where all the images are stored -# template for the stored facts hash (values are variable/fact names) -libvirt_domain_fact_template: >- - { - u"ssh_port": {{ libvirt_result_ssh_port }}, - u"rdp_port": {{ libvirt_result_rdp_port }}, - u"winrm_port": {{ libvirt_result_winrm_port }}, - u"groups": {{ libvirt_domain_groups }} - } - -ansible_facts_path: '/etc/ansible/facts.d' # path where local Ansible facts are stored & read +ansible_facts_path: "/etc/ansible/facts.d" # path where local Ansible facts are stored & read diff --git a/domain/create/handlers/main.yml b/domain/create/handlers/main.yml index dd2be5a..6df01f0 100644 --- a/domain/create/handlers/main.yml +++ b/domain/create/handlers/main.yml @@ -1,7 +1,6 @@ --- - -- name: wait for remote ports - wait_for: +- name: Wait for remote ports + ansible.builtin.wait_for: host: "{{ item.ip }}" port: >- {{ item.winrm_port @@ -12,32 +11,32 @@ timeout: 360 # seconds become: false delegate_to: 127.0.0.1 - with_items: "{{ libvirt_wait_hosts }}" + loop: "{{ libvirt_wait_hosts }}" # wait_for might not be enough for a successful SSH login, probably due to # https://stackoverflow.com/questions/30576778/ansible-wait-for-for-connecting-machine-to-actually-login#comment60208811_30576778 -- name: check ssh login - command: > - ssh +- name: Check ssh login + ansible.builtin.command: > + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p {{ item.ssh_port }} {{ item.ip }} -l ansible - exit + -- sudo netplan apply register: ssh_test until: ssh_test.rc == 0 retries: 12 - delay: 5 + delay: 5 changed_when: false when: (item.winrm_port | int) <= 0 become: false delegate_to: 127.0.0.1 - with_items: "{{ libvirt_wait_hosts }}" + loop: "{{ libvirt_wait_hosts }}" -- name: check for dns entry - command: host {{ item.name }} +- name: Check for dns entry + ansible.builtin.command: host {{ item.name }} register: host_test until: host_test.rc == 0 retries: 15 delay: 5 changed_when: false - with_items: "{{ libvirt_wait_hosts }}" \ No newline at end of file + loop: "{{ libvirt_wait_hosts }}" diff --git a/domain/create/tasks/autostart.yml b/domain/create/tasks/autostart.yml index 11123f3..d795f77 100644 --- a/domain/create/tasks/autostart.yml +++ b/domain/create/tasks/autostart.yml @@ -1,13 +1,15 @@ --- -- name: autostart | list domains - command: virsh list --autostart --name - changed_when: no +- name: Autostart | List domains + ansible.builtin.command: virsh list --autostart --name + changed_when: false register: libvirt_list_autostart_result -- name: autostart | enable - command: "virsh autostart {{ libvirt_result_domain_name }}" +- name: Autostart | Enable + ansible.builtin.command: "virsh autostart {{ libvirt_result_domain_name }}" + changed_when: true when: libvirt_autostart and (libvirt_result_domain_name not in libvirt_list_autostart_result.stdout_lines) -- name: autostart | disable - command: "virsh autostart {{ libvirt_result_domain_name }} --disable" - when: not libvirt_autostart and (libvirt_result_domain_name in libvirt_list_autostart_result.stdout_lines) +- name: Autostart | Disable + ansible.builtin.command: "virsh autostart {{ libvirt_result_domain_name }} --disable" + changed_when: true + when: falset libvirt_autostart and (libvirt_result_domain_name in libvirt_list_autostart_result.stdout_lines) diff --git a/domain/create/tasks/base_image.yml b/domain/create/tasks/base_image.yml index 3a09bf6..1d419fb 100644 --- a/domain/create/tasks/base_image.yml +++ b/domain/create/tasks/base_image.yml @@ -1,6 +1,6 @@ --- -- name: base_image | copy - command: > +- name: Base Image | Copy + ansible.builtin.command: > cp {{ libvirt_base_image }} {{ libvirt_result_domain_name }}.img @@ -10,8 +10,8 @@ register: libvirt_copy_image_result when: libvirt_base_image_mode == 'copy' -- name: base_image | snapshot - command: > +- name: Base Image | Snapshot + ansible.builtin.command: > qemu-img create -f qcow2 -b {{ libvirt_base_image }} @@ -22,12 +22,13 @@ register: libvirt_snapshot_image_result when: libvirt_base_image_mode == 'snapshot' -- name: base_image | resize - command: > +- name: Base Image | Resize + ansible.builtin.command: > qemu-img resize {{ libvirt_result_domain_name }}.img {{ libvirt_vm_disk_size }} args: chdir: "{{ libvirt_images_path }}" + changed_when: true when: (libvirt_vm_disk_size is defined) and (libvirt_copy_image_result.changed or libvirt_snapshot_image_result.changed) diff --git a/domain/create/tasks/cloud_config.yml b/domain/create/tasks/cloud_config.yml index 4f9af05..bfa8982 100644 --- a/domain/create/tasks/cloud_config.yml +++ b/domain/create/tasks/cloud_config.yml @@ -1,15 +1,17 @@ --- -- name: cloud_config | create - template: +- name: Cloud Config | Create + ansible.builtin.template: dest: "{{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.cloud-config" src: "cloud-config.yml.j2" + mode: "644" register: libvirt_create_cloud_config_result -- name: cloud_config | create image - command: > +- name: Cloud Config | Create image + ansible.builtin.command: > cloud-localds {{ libvirt_result_domain_name }}.cloud-config.img {{ libvirt_result_domain_name }}.cloud-config args: chdir: "{{ libvirt_images_path }}" - when: libvirt_create_cloud_config_result.changed + changed_when: true + when: libvirt_create_cloud_config_result.changed and true diff --git a/domain/create/tasks/configdrive.yml b/domain/create/tasks/configdrive.yml index 7d8e1d6..19868a9 100644 --- a/domain/create/tasks/configdrive.yml +++ b/domain/create/tasks/configdrive.yml @@ -1,20 +1,23 @@ --- - name: ConfigDrive | directories - file: + ansible.builtin.file: path: '{{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.configdrive/{{ item.key | dirname }}' state: directory - with_dict: '{{ libvirt_configdrive_files }}' + mode: "755" + loop: '{{ libvirt_configdrive_files | dict2items }}' - name: ConfigDrive | content - copy: + ansible.builtin.copy: dest: '{{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.configdrive/{{ item.key }}' content: '{{ item.value }}' - with_dict: '{{ libvirt_configdrive_files }}' + mode: "644" + loop: '{{ libvirt_configdrive_files | dict2items }}' register: libvirt_configdrive_result - name: ConfigDrive | iso image - command: > + ansible.builtin.command: > genisoimage -joliet -rock -volid config-2 -o {{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.configdrive.iso -r {{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.configdrive - when: libvirt_configdrive_result.changed + changed_when: true + when: libvirt_configdrive_result.changed and true diff --git a/domain/create/tasks/create_domain.yml b/domain/create/tasks/create_domain.yml index 9ec03a7..26dc176 100644 --- a/domain/create/tasks/create_domain.yml +++ b/domain/create/tasks/create_domain.yml @@ -1,15 +1,18 @@ --- -- name: create_domain | template - template: +- name: Create Domain | Template + ansible.builtin.template: dest: "/tmp/{{ libvirt_result_domain_name }}.xml" src: "machine.xml.j2" + mode: "644" -- name: create_domain | define - command: "virsh define /tmp/{{ libvirt_result_domain_name }}.xml" +- name: Create Domain | Define + ansible.builtin.command: "virsh define /tmp/{{ libvirt_result_domain_name }}.xml" + changed_when: true -- name: create_domain | start - command: "virsh start {{ libvirt_result_domain_name }}" +- name: Create Domain | Start + ansible.builtin.command: "virsh start {{ libvirt_result_domain_name }}" + changed_when: true notify: - - wait for remote ports - - check ssh login - - check for dns entry + - wait for remote ports + - check ssh login + - check for dns entry diff --git a/domain/create/tasks/domain_id.yml b/domain/create/tasks/domain_id.yml index 28a8860..8cab52a 100644 --- a/domain/create/tasks/domain_id.yml +++ b/domain/create/tasks/domain_id.yml @@ -1,25 +1,25 @@ --- -- name: domain_id | check for pollution - assert: +- name: Domain Id | Check for pollution + ansible.builtin.assert: that: > (libvirt_result_domain_name is not defined) or (libvirt_domain_name is not defined) or (libvirt_domain_name != libvirt_result_domain_name) tags: - - facts + - facts -- name: domain_id | create uuid - command: uuidgen - changed_when: no +- name: Domain Id | Create uuid + ansible.builtin.command: uuidgen + changed_when: false register: libvirt_domain_uuid_result when: > (libvirt_domain_name is not defined) or (not libvirt_domain_name) tags: - - facts + - facts -- name: domain_id | extract - set_fact: +- name: Domain Id | Extract + ansible.builtin.set_fact: libvirt_result_domain_name: >- {{ libvirt_domain_name @@ -28,4 +28,4 @@ (libvirt_domain_uuid_result.stdout | trim) }} tags: - - facts + - facts diff --git a/domain/create/tasks/extra_disk.yml b/domain/create/tasks/extra_disk.yml index 3a19a4c..466b0d9 100644 --- a/domain/create/tasks/extra_disk.yml +++ b/domain/create/tasks/extra_disk.yml @@ -1,11 +1,11 @@ --- -- name: create lvm disk - fail: +- name: Create lvm disk + ansible.builtin.fail: msg: 'LVM disk creation is not implemented yet!' when: (disk.type | default('image', true)) == 'lvm' -- name: create image disk - command: > +- name: Create image disk + ansible.builtin.command: > qemu-img create -f {{ disk.image_type | default('qcow2', true) }} {{ libvirt_result_domain_name }}.extra_{{ disk.id }}.img @@ -13,4 +13,5 @@ args: chdir: "{{ libvirt_images_path }}" creates: "{{ libvirt_images_path }}/{{ libvirt_result_domain_name }}.extra_{{ disk.id }}.img" + changed_when: true when: (disk.type | default('image', true)) == 'image' diff --git a/domain/create/tasks/list.yml b/domain/create/tasks/list.yml index 2c29887..d2784a8 100644 --- a/domain/create/tasks/list.yml +++ b/domain/create/tasks/list.yml @@ -1,13 +1,13 @@ --- -- name: list | all domains - command: virsh list --all --name - changed_when: no +- name: List | All domains + ansible.builtin.command: virsh list --all --name + changed_when: false register: libvirt_list_all_result tags: - - facts + - facts -- name: list | extract - set_fact: +- name: List | Extract + ansible.builtin.set_fact: libvirt_all_domains: "{{ libvirt_list_all_result.stdout_lines }}" tags: - - facts + - facts diff --git a/domain/create/tasks/mac_and_ip.yml b/domain/create/tasks/mac_and_ip.yml index 672819e..e9592d8 100644 --- a/domain/create/tasks/mac_and_ip.yml +++ b/domain/create/tasks/mac_and_ip.yml @@ -1,22 +1,28 @@ --- -- name: mac_and_ip | extract mac address - shell: > - virsh dumpxml {{ libvirt_result_domain_name }} - | grep 'mac address' - | cut -f 2 -d "'" - changed_when: no +- name: Mac and Ip | Extract mac address + ansible.builtin.shell: + cmd: > + set -o pipefail && + virsh dumpxml {{ libvirt_result_domain_name }} + | grep 'mac address' + | cut -f 2 -d "'" + executable: "/bin/bash" + changed_when: false register: extract_mac_address_result -- name: mac_and_ip | wait for dhcp ip address - shell: | - until arp -an | grep -q -F {{ extract_mac_address_result.stdout }}; do - sleep 1 - done - arp -an | grep -F {{ extract_mac_address_result.stdout }} | cut -f 2 -d "(" | cut -f 1 -d ")" - changed_when: no +- name: Mac and Ip | Wait for dhcp ip address + ansible.builtin.shell: + cmd: | + set -o pipefail + until arp -an | grep -q -F {{ extract_mac_address_result.stdout }}; do + sleep 1 + done + arp -an | grep -F {{ extract_mac_address_result.stdout }} | cut -f 2 -d "(" | cut -f 1 -d ")" + executable: "/bin/bash" + changed_when: false register: extract_ip_address_result -- name: mac_and_ip | extract facts - set_fact: +- name: Mac and Ip | Extract facts + ansible.builtin.set_fact: libvirt_result_ip_address: "{{ extract_ip_address_result.stdout }}" libvirt_result_mac_address: "{{ extract_mac_address_result.stdout }}" diff --git a/domain/create/tasks/main.yml b/domain/create/tasks/main.yml index 320cbc2..1adb434 100644 --- a/domain/create/tasks/main.yml +++ b/domain/create/tasks/main.yml @@ -1,77 +1,97 @@ --- -- stat: +- name: Stat Base Image + ansible.builtin.stat: path: "{{ libvirt_base_image }}" get_checksum: false # Save time on unneeded hashes... - get_md5: false register: libvirt_base_image_stat_result -- fail: +- name: Fail if missing Base Image + ansible.builtin.fail: msg: "base image '{{ libvirt_base_image }}' does not exist" - when: not libvirt_base_image_stat_result.stat.exists + when: falset libvirt_base_image_stat_result.stat.exists -- include: domain_id.yml -- include: ports.yml +- name: Domain Id + ansible.builtin.include_tasks: domain_id.yml +- name: Ports + ansible.builtin.include_tasks: ports.yml -- include: extra_disk.yml - disk: "{{ item }}" - with_items: "{{ libvirt_extra_disks }}" +- name: Extra Disk + ansible.builtin.include_tasks: extra_disk.yml + vars: + disk: "{{ item }}" + loop: "{{ libvirt_extra_disks | list }}" -- include: base_image.yml +- name: Base Image + ansible.builtin.include_tasks: base_image.yml when: libvirt_install_type == 'base-image' -- include: cloud_config.yml +- name: Cloud Config + ansible.builtin.include_tasks: cloud_config.yml when: libvirt_init_mode == 'cloud-config' -- include: configdrive.yml +- name: Configdrive + ansible.builtin.include_tasks: configdrive.yml when: libvirt_init_mode == 'configdrive' -- include: list.yml +- name: List + ansible.builtin.include_tasks: list.yml when: libvirt_all_domains is not defined -- include: create_domain.yml +- name: Create Domain + ansible.builtin.include_tasks: create_domain.yml when: libvirt_result_domain_name not in libvirt_all_domains -# - include: update.yml +# - name: Update +# ansible.builtin.include_tasks: update.yml # when: libvirt_result_domain_name in libvirt_all_domains -- include: autostart.yml +- name: Autostart + ansible.builtin.include_tasks: autostart.yml -- include: mac_and_ip.yml +- name: Mac and Ip + ansible.builtin.include_tasks: mac_and_ip.yml -- include: port_forward.yml - protocol: tcp - source_ip: "{{ libvirt_host_ssh_destination }}" - source_port: "{{ libvirt_result_ssh_port }}" - destination_ip: "{{ libvirt_result_ip_address }}" - destination_port: "{{ libvirt_ssh_guest_port }}" +- name: Port Forward SSH + ansible.builtin.include_tasks: port_forward.yml + vars: + protocol: tcp + source_ip: "{{ libvirt_host_ssh_destination }}" + source_port: "{{ libvirt_result_ssh_port }}" + destination_ip: "{{ libvirt_result_ip_address }}" + destination_port: "{{ libvirt_ssh_guest_port }}" when: (libvirt_result_ssh_port | int) > 0 -- include: port_forward.yml - protocol: tcp - source_ip: "{{ libvirt_host_ssh_destination }}" - source_port: "{{ libvirt_result_rdp_port }}" - destination_ip: "{{ libvirt_result_ip_address }}" - destination_port: "{{ libvirt_rdp_guest_port }}" +- name: Port Forward RDP + ansible.builtin.include_tasks: port_forward.yml + vars: + protocol: tcp + source_ip: "{{ libvirt_host_ssh_destination }}" + source_port: "{{ libvirt_result_rdp_port }}" + destination_ip: "{{ libvirt_result_ip_address }}" + destination_port: "{{ libvirt_rdp_guest_port }}" when: (libvirt_result_rdp_port | int) > 0 -- include: port_forward.yml - protocol: tcp - source_ip: "{{ libvirt_host_ssh_destination }}" - source_port: "{{ libvirt_result_winrm_port }}" - destination_ip: "{{ libvirt_result_ip_address }}" - destination_port: "{{ libvirt_winrm_guest_port }}" +- name: Port Forward WINRM + ansible.builtin.include_tasks: port_forward.yml + vars: + protocol: tcp + source_ip: "{{ libvirt_host_ssh_destination }}" + source_port: "{{ libvirt_result_winrm_port }}" + destination_ip: "{{ libvirt_result_ip_address }}" + destination_port: "{{ libvirt_winrm_guest_port }}" when: (libvirt_result_winrm_port | int) > 0 -- include: store_facts.yml - -- name: queue wait for remote port - set_fact: - libvirt_wait_hosts: "{{ - libvirt_wait_hosts | default([]) + - [{ - 'ip': libvirt_host_ssh_ip_address, - 'winrm_port': libvirt_result_winrm_port, - 'ssh_port': libvirt_result_ssh_port, - 'name': libvirt_result_domain_name, - }] - }}" +- name: Store Facts + ansible.builtin.include_tasks: store_facts.yml + +- name: Queue wait for remote port + ansible.builtin.set_fact: + libvirt_wait_hosts: | + {{ libvirt_wait_hosts | default([]) + [ + { + 'ip': libvirt_host_ssh_ip_address, + 'winrm_port': libvirt_result_winrm_port, + 'ssh_port': libvirt_result_ssh_port, + 'name': libvirt_result_domain_name, + } + ] }} diff --git a/domain/create/tasks/port_forward.yml b/domain/create/tasks/port_forward.yml index bb60e0b..e216686 100644 --- a/domain/create/tasks/port_forward.yml +++ b/domain/create/tasks/port_forward.yml @@ -1,11 +1,12 @@ --- -- name: port_forward | directory - file: +- name: Port Forward | Directory + ansible.builtin.file: dest: "{{ libvirt_host_qemu_machine_hooks_folder }}/{{ libvirt_result_domain_name }}" state: directory + mode: "755" -- name: port_forward | name - set_fact: +- name: Port Forward | Name + ansible.builtin.set_fact: libvirt_tmp_port_forward_hook_script: >- {{ [ libvirt_host_qemu_machine_hooks_folder, @@ -19,13 +20,14 @@ ] | join('/') }} -- name: port_forward | create - template: +- name: Port Forward | Create + ansible.builtin.template: dest: "{{ libvirt_tmp_port_forward_hook_script }}" src: iptables-port-nat.sh.j2 mode: "0744" register: port_forward_result -- name: port_forward | run - command: "{{ libvirt_tmp_port_forward_hook_script }} start" - when: port_forward_result.changed +- name: Port Forward | Run + ansible.builtin.command: "{{ libvirt_tmp_port_forward_hook_script }} start" + changed_when: true + when: port_forward_result.changed and true diff --git a/domain/create/tasks/ports.yml b/domain/create/tasks/ports.yml index f5d611f..ea4fb8c 100644 --- a/domain/create/tasks/ports.yml +++ b/domain/create/tasks/ports.yml @@ -1,6 +1,6 @@ --- -- name: ports | ssh - set_fact: +- name: Ports | Ssh + ansible.builtin.set_fact: libvirt_result_ssh_port_generated: >- {{ False @@ -28,10 +28,10 @@ libvirt_ssh_base_port }} tags: - - facts + - facts -- name: ports | rdp - set_fact: +- name: Ports | Rdp + ansible.builtin.set_fact: libvirt_result_rdp_port_generated: >- {{ False @@ -59,10 +59,10 @@ libvirt_rdp_base_port }} tags: - - facts + - facts -- name: ports | winrm - set_fact: +- name: Ports | Winrm + ansible.builtin.set_fact: libvirt_result_winrm_port_generated: >- {{ False @@ -90,4 +90,4 @@ libvirt_winrm_base_port }} tags: - - facts + - facts diff --git a/domain/create/tasks/store_facts.yml b/domain/create/tasks/store_facts.yml index 30bb0cb..7f91312 100644 --- a/domain/create/tasks/store_facts.yml +++ b/domain/create/tasks/store_facts.yml @@ -1,39 +1,33 @@ --- -- name: store_facts | facts directory - file: +- name: Store Facts | Facts directory + ansible.builtin.file: path: "{{ ansible_facts_path }}" state: directory - recurse: yes + mode: "755" -- name: store_facts | generated ssh_port - ini_file: +- name: Store Facts | Generated ssh_port + community.general.ini_file: dest: "{{ ansible_facts_path }}/libvirt.fact" section: "facts" option: "ssh_port" value: "{{ libvirt_result_ssh_port }}" + mode: "644" when: libvirt_result_ssh_port_generated | bool -- name: store_facts | generated rdp_port - ini_file: +- name: Store Facts | Generated rdp_port + community.general.ini_file: dest: "{{ ansible_facts_path }}/libvirt.fact" section: "facts" option: "rdp_port" value: "{{ libvirt_result_rdp_port }}" + mode: "644" when: libvirt_result_rdp_port_generated | bool -- name: store_facts | generated winrm_port - ini_file: +- name: Store Facts | Generated winrm_port + community.general.ini_file: dest: "{{ ansible_facts_path }}/libvirt.fact" section: "facts" option: "winrm_port" value: "{{ libvirt_result_winrm_port }}" + mode: "644" when: libvirt_result_winrm_port_generated | bool - -- name: store_facts | store - template: - dest: "{{ ansible_facts_path }}/libvirt_domains.fact" - src: libvirt_domains.j2 - -- name: store_facts | re-read - setup: - filter: ansible_local diff --git a/domain/create/templates/cloud-config.yml.j2 b/domain/create/templates/cloud-config.yml.j2 index 0aaf2ae..26374af 100644 --- a/domain/create/templates/cloud-config.yml.j2 +++ b/domain/create/templates/cloud-config.yml.j2 @@ -15,7 +15,9 @@ users: apt_mirror: {{ libvirt_apt_mirror }} {% endif %} packages: -- python +{% for package in libvirt_cloud_config_packages %} +- {{ package }} +{% endfor %} {# python ensures ansible can manage this host #} {% if libvirt_cloud_config_bootcmd | default([]) %} bootcmd: @@ -45,7 +47,7 @@ fs_setup: - label: '{{ disk.label | default(disk.id, true) }}' filesystem: '{{ disk.fs | default('ext4', true) }}' device: '/dev/vd{{ alpha[vd_index] }}' - partition: none + partition: falsene overwrite: False {% set vd_index = vd_index + 1 %} {% endfor %} diff --git a/domain/create/templates/iptables-port-nat.sh.j2 b/domain/create/templates/iptables-port-nat.sh.j2 index f80159f..901ec58 100644 --- a/domain/create/templates/iptables-port-nat.sh.j2 +++ b/domain/create/templates/iptables-port-nat.sh.j2 @@ -8,7 +8,7 @@ iptables='/sbin/iptables' protocol="{{ protocol }}" source_ip="{{ source_ip }}" source_port="{{ source_port }}" -destination_ip="{{ destination_ip}}" +destination_ip="{{ destination_ip }}" destination_port="{{ destination_port }}" update() { diff --git a/domain/create/templates/libvirt_domains.j2 b/domain/create/templates/libvirt_domains.j2 deleted file mode 100644 index c9d8f90..0000000 --- a/domain/create/templates/libvirt_domains.j2 +++ /dev/null @@ -1,6 +0,0 @@ -{ -{% for x in dict([[libvirt_result_domain_name, libvirt_domain_fact_template]] - + ((ansible_local | default({})).libvirt_domains | default({})).items()) | dictsort %} -{{ x[0] | to_nice_json }}:{{ x[1] | to_nice_json }}{{ '' if loop.last else ',' }} -{% endfor %} -} diff --git a/domain/kill/tasks/images.yml b/domain/kill/tasks/images.yml index a041471..6878c6d 100644 --- a/domain/kill/tasks/images.yml +++ b/domain/kill/tasks/images.yml @@ -1,7 +1,7 @@ --- -- name: delete images - shell: 'rm -rf {{ item }}.*' +- name: Delete Images + ansible.builtin.shell: 'rm -rf {{ item }}.*' args: chdir: "{{ libvirt_images_path }}" removes: "{{ libvirt_images_path }}/{{ item }}.img" - with_items: "{{ libvirt_domain_names }}" + loop: "{{ libvirt_domain_names }}" diff --git a/domain/kill/tasks/main.yml b/domain/kill/tasks/main.yml index 1cbec54..fa4a636 100644 --- a/domain/kill/tasks/main.yml +++ b/domain/kill/tasks/main.yml @@ -1,6 +1,11 @@ --- -- include: shutdown.yml -- include: undefine.yml -- include: images.yml -- include: port_forward.yml -- include: store_facts.yml +- name: Shutdown + ansible.builtin.include_tasks: shutdown.yml +- name: Undefine + ansible.builtin.include_tasks: undefine.yml +- name: Images + ansible.builtin.include_tasks: images.yml +- name: Port Forward + ansible.builtin.include_tasks: port_forward.yml +- name: Store Facts + ansible.builtin.include_tasks: store_facts.yml diff --git a/domain/kill/tasks/port_forward.yml b/domain/kill/tasks/port_forward.yml index c019a33..143d9cd 100644 --- a/domain/kill/tasks/port_forward.yml +++ b/domain/kill/tasks/port_forward.yml @@ -1,8 +1,8 @@ --- # port forward are automatically shutdown on domain shutdown! # the only thing left is to remove the scripts -- name: delete hooks - file: +- name: Delete hooks + ansible.builtin.file: dest: "{{ libvirt_host_qemu_machine_hooks_folder }}/{{ item }}" state: absent - with_items: "{{ libvirt_domain_names }}" + loop: "{{ libvirt_domain_names }}" diff --git a/domain/kill/tasks/shutdown.yml b/domain/kill/tasks/shutdown.yml index 3da7c7e..cb484a0 100644 --- a/domain/kill/tasks/shutdown.yml +++ b/domain/kill/tasks/shutdown.yml @@ -1,34 +1,38 @@ --- -- name: list running domain names - command: virsh list --name - changed_when: no +- name: List running domain names + ansible.builtin.command: virsh list --name + changed_when: false register: libvirt_list_result -- name: extract running domain names - set_fact: +- name: Extract running domain names + ansible.builtin.set_fact: libvirt_running_domains: "{{ libvirt_list_result.stdout_lines }}" -- name: shutdown - shell: > - virsh shutdown "{{ item }}"; - while virsh list | grep -q -F " {{ item }} "; do - sleep 2 - done +- name: Shutdown + ansible.builtin.shell: + cmd: > + set -o pipefail && + virsh shutdown "{{ item }}"; + while virsh list | grep -q -F " {{ item }} "; do + sleep 2 + done + executable: /bin/bash register: libvirt_machine_shutdown_result until: libvirt_machine_shutdown_result.rc == 0 + changed_when: true when: item in libvirt_running_domains - with_items: "{{ libvirt_domain_names }}" + loop: "{{ libvirt_domain_names }}" -# - name: initiate shutdown -# command: "virsh shutdown \"{{ item }}\"" +# - name: Initiate shutdown +# ansible.builtin.command: "virsh shutdown \"{{ item }}\"" # when: item in libvirt_running_domains -# with_items: "{{ libvirt_domain_names }}" +# loop: "{{ libvirt_domain_names }}" -# - name: wait for shutdown -# shell: | +# - name: Wait for shutdown +# ansible.builtin.shell: | # while virsh list | grep -q -F "{{ item }}"; do # sleep 2 # done -# changed_when: no +# changed_when: false # when: item in libvirt_running_domains -# with_items: "{{ libvirt_domain_names }}" +# loop: "{{ libvirt_domain_names }}" diff --git a/domain/kill/tasks/store_facts.yml b/domain/kill/tasks/store_facts.yml index 94607c0..723ba05 100644 --- a/domain/kill/tasks/store_facts.yml +++ b/domain/kill/tasks/store_facts.yml @@ -1,5 +1,6 @@ --- -- name: remaining machines - template: +- name: Remaining machines + ansible.builtin.template: dest: "{{ ansible_facts_path }}/libvirt_domains.fact" src: libvirt_domains.j2 + mode: "644" diff --git a/domain/kill/tasks/undefine.yml b/domain/kill/tasks/undefine.yml index f963e94..5be85aa 100644 --- a/domain/kill/tasks/undefine.yml +++ b/domain/kill/tasks/undefine.yml @@ -1,14 +1,15 @@ --- -- name: list all domain names - command: virsh list --all --name - changed_when: no +- name: List all domain names + ansible.builtin.command: virsh list --all --name + changed_when: false register: libvirt_list_all_result -- name: extract all domain names - set_fact: +- name: Extract all domain names + ansible.builtin.set_fact: libvirt_all_domains: "{{ libvirt_list_all_result.stdout_lines }}" -- name: undefine machine - command: 'virsh undefine "{{ item }}"' +- name: Undefine machine + ansible.builtin.command: 'virsh undefine "{{ item }}"' when: item in libvirt_all_domains - with_items: "{{ libvirt_domain_names }}" + changed_when: true + loop: "{{ libvirt_domain_names }}" diff --git a/domain/list/tasks/main.yml b/domain/list/tasks/main.yml index 5081d1f..669f811 100644 --- a/domain/list/tasks/main.yml +++ b/domain/list/tasks/main.yml @@ -1,15 +1,15 @@ --- -- name: running - command: virsh list --name - changed_when: no +- name: Running + ansible.builtin.command: virsh list --name + changed_when: false register: virsh_list_running_result -- name: all - command: virsh list --all --name - changed_when: no +- name: All + ansible.builtin.command: virsh list --all --name + changed_when: false register: virsh_list_all_result -- name: extract facts - set_fact: +- name: Extract facts + ansible.builtin.set_fact: libvirt_running_domains: "{{ virsh_list_running_result.stdout_lines }}" libvirt_all_domains: "{{ virsh_list_all_result.stdout_lines }}" diff --git a/domain/port_forward/defaults/main.yml b/domain/port_forward/defaults/main.yml index 0a44f77..e18f63c 100644 --- a/domain/port_forward/defaults/main.yml +++ b/domain/port_forward/defaults/main.yml @@ -3,18 +3,20 @@ libvirt_hostname: "{{ groups['libvirt_host'][0] }}" # required manage_name: 'extra' port_forwards: -- guest: # required port of guest - host: # required port of host - protocol: "{{ libvirt_port_forward_protocol }}" - guest_ip: "{{ libvirt_port_forward_guest_ip }}" - host_ip: "{{ libvirt_port_forward_host_destination }}" - host_device: "{{ libvirt_port_forward_host_device }}" + - guest: # required port of guest + host: # required port of host + protocol: "{{ libvirt_port_forward_protocol }}" + guest_ip: "{{ libvirt_port_forward_guest_ip }}" + host_ip: "{{ libvirt_port_forward_host_destination }}" + host_device: "{{ libvirt_port_forward_host_device }}" libvirt_port_forward_protocol: "tcp" libvirt_port_forward_guest_ip: "{{ ansible_default_ipv4.address }}" libvirt_port_forward_destination_all: "0.0.0.0/0" libvirt_port_forward_destination_default_ip: "{{ hostvars[libvirt_hostname].ansible_default_ipv4.address }}" -libvirt_port_forward_host_destination: "{{ hostvars[libvirt_hostname].libvirt_port_forward_host_destination | default(libvirt_port_forward_destination_default_ip, true) }}" +libvirt_port_forward_host_destination: >- + {{ hostvars[libvirt_hostname].libvirt_port_forward_host_destination + | default(libvirt_port_forward_destination_default_ip, true) }} libvirt_port_forward_host_device: "eth0" diff --git a/domain/port_forward/tasks/main.yml b/domain/port_forward/tasks/main.yml index 115880b..291c03b 100644 --- a/domain/port_forward/tasks/main.yml +++ b/domain/port_forward/tasks/main.yml @@ -1,53 +1,64 @@ --- -- name: facts - set_fact: +- name: Setup libvirt host delegate + delegate_to: "{{ libvirt_hostname }}" + block: + - name: Ensure facts of the backup are available + ansible.builtin.setup: + delegate_facts: true + +- name: Facts + ansible.builtin.set_fact: libvirt_port_forward_hooks_folder: "{{ libvirt_host_qemu_machine_hooks_folder }}/{{ ansible_hostname }}" libvirt_port_forward_tmp_args: "{{ lookup('template', '../templates/port_forward_args.json.j2') }}" -- name: file names - set_fact: +- name: File names + ansible.builtin.set_fact: libvirt_port_forward_managed_files: "{{ lookup('template', '../templates/file_names.j2') }}" -- delegate_to: "{{ libvirt_hostname }}" +- name: Run on host + delegate_to: "{{ libvirt_hostname }}" block: - - name: hooks folder - file: + - name: Hooks folder + ansible.builtin.file: dest: "{{ libvirt_port_forward_hooks_folder }}" state: directory + mode: "755" - - name: hook scripts - template: + - name: Hook scripts + ansible.builtin.template: dest: "{{ libvirt_port_forward_hooks_folder }}/{{ libvirt_port_forward_hook_script_name }}" src: 'port_forward.sh.j2' - mode: 700 - with_items: "{{ libvirt_port_forward_tmp_args }}" + mode: "700" + loop: "{{ libvirt_port_forward_tmp_args }}" register: libvirt_port_forward_tmp_hook_scripts_result - - name: list existing hook scripts - shell: > + - name: List existing hook scripts + ansible.builtin.shell: > find {{ libvirt_port_forward_hooks_folder }} -mindepth 1 -name '{{ manage_name }}_*' -type f -printf '%P\n' - changed_when: no + changed_when: false register: libvirt_port_forward_tmp_existing_files - - name: stop unused hook scripts - command: "{{ libvirt_port_forward_hooks_folder }}/{{ item }} stopped" - ignore_errors: yes + - name: Stop unused hook scripts + ansible.builtin.command: "{{ libvirt_port_forward_hooks_folder }}/{{ item }} stopped" + changed_when: true + failed_when: false when: item not in libvirt_port_forward_managed_files - with_items: "{{ libvirt_port_forward_tmp_existing_files.stdout_lines }}" + loop: "{{ libvirt_port_forward_tmp_existing_files.stdout_lines }}" - - name: remove unused hook scripts - file: + - name: Remove unused hook scripts + ansible.builtin.file: dest: "{{ libvirt_port_forward_hooks_folder }}/{{ item }}" state: absent when: item not in libvirt_port_forward_managed_files - with_items: "{{ libvirt_port_forward_tmp_existing_files.stdout_lines }}" + loop: "{{ libvirt_port_forward_tmp_existing_files.stdout_lines }}" - - name: start new hook scripts - command: "{{ item.dest }} start" - when: item.changed - with_items: "{{ libvirt_port_forward_tmp_hook_scripts_result.results }}" + - name: Start new hook scripts + ansible.builtin.command: "{{ item.dest }} start" + when: item.changed and true + changed_when: true + loop: "{{ libvirt_port_forward_tmp_hook_scripts_result.results }}" diff --git a/host/provision/defaults/main.yml b/host/provision/defaults/main.yml index a96bb27..8b72bd8 100644 --- a/host/provision/defaults/main.yml +++ b/host/provision/defaults/main.yml @@ -1,12 +1,13 @@ --- libvirt_host_packages: -- qemu-kvm -- libvirt-bin -- virtinst -- python-libvirt # allow ansible management -- cloud-image-utils # used to convert images -- uuid-runtime # generate machine uuids -- python-configparser # required for ini_file + - qemu-kvm + - libvirt-daemon-system + - virtinst + - python3-libvirt # allow ansible management + - cloud-image-utils # used to convert images + - uuid-runtime # generate machine uuids + # - python-configparser # required for ini_file +libvirt_network_device: eth0 network_up_hooks: -- 'echo 1 > /proc/sys/net/ipv4/conf/eth0/proxy_arp' + - 'echo 1 > /proc/sys/net/ipv4/conf/{{ libvirt_network_device }}/proxy_arp' diff --git a/host/provision/handlers/main.yml b/host/provision/handlers/main.yml index c690d2a..c52b3d5 100644 --- a/host/provision/handlers/main.yml +++ b/host/provision/handlers/main.yml @@ -1,3 +1,5 @@ --- -- name: restart libvirt - service: name=libvirt-bin state=restarted +- name: Restart libvirt + ansible.builtin.service: + name: libvirt-bin + state: restarted diff --git a/host/provision/tasks/main.yml b/host/provision/tasks/main.yml index 1276b1d..8016f11 100644 --- a/host/provision/tasks/main.yml +++ b/host/provision/tasks/main.yml @@ -1,40 +1,47 @@ --- -- name: install packages - apt: - name: "{{ item }}" - update_cache: yes +- name: Install packages + ansible.builtin.apt: + pkg: "{{ libvirt_host_packages | list }}" + update_cache: true state: latest cache_valid_time: 86400 - with_items: "{{ libvirt_host_packages }}" -- name: machine hooks folder - file: +- name: Machine hooks folder + ansible.builtin.file: dest: "{{ libvirt_host_qemu_machine_hooks_folder }}" state: directory + mode: "755" -- name: qemu hook - template: +- name: Qemu hook + ansible.builtin.template: dest: "{{ libvirt_host_qemu_hook }}" src: "qemu_hook.j2" - mode: 700 + mode: "700" notify: - restart libvirt -- name: increase semaphore count - template: +- name: Increase semaphore count + ansible.builtin.template: dest: "/etc/sysctl.d/local.conf" src: "sysctl_local.conf.j2" + mode: "644" -- name: disable audit - lineinfile: +- name: Disable audit + ansible.builtin.lineinfile: dest: "/etc/libvirt/libvirtd.conf" regexp: "^audit_level" line: "audit_level = 0" notify: - restart libvirt -- name: network hook - template: +- name: Network hook + ansible.builtin.template: dest: "{{ network_interface_up_hooks_path }}/libvirt" src: "if_up_libvirt.sh.j2" - mode: 700 + mode: "700" + register: libvirt_provision_network_hook_result + +- name: Initially run network hook + ansible.builtin.command: "{{ network_interface_up_hooks_path }}/libvirt" + changed_when: true + when: libvirt_provision_network_hook_result.changed and true diff --git a/images/ubuntu-cloud/defaults/main.yml b/images/ubuntu-cloud/defaults/main.yml index 53c838a..3a9a28c 100644 --- a/images/ubuntu-cloud/defaults/main.yml +++ b/images/ubuntu-cloud/defaults/main.yml @@ -3,11 +3,12 @@ libvirt_images_ubuntu_cloud_image_distribution: trusty libvirt_images_ubuntu_cloud_image_file: "{{ libvirt_images_ubuntu_cloud_image_distribution }}-server-cloudimg-amd64-disk1.img" -libvirt_images_ubuntu_cloud_image_url: "https://cloud-images.ubuntu.com/{{ libvirt_images_ubuntu_cloud_image_distribution }}/current/{{ libvirt_images_ubuntu_cloud_image_file }}" +libvirt_images_ubuntu_cloud_image_url: >- + https://cloud-images.ubuntu.com/{{ libvirt_images_ubuntu_cloud_image_distribution }}/current/{{ libvirt_images_ubuntu_cloud_image_file }} # checksums and signatures -libvirt_images_ubuntu_cloud_url_base: "{{ libvirt_images_ubuntu_cloud_image_url | dirname }}" +libvirt_images_ubuntu_cloud_url_base: "{{ libvirt_images_ubuntu_cloud_image_url | dirname }}" libvirt_images_ubuntu_cloud_sha256sums: "SHA256SUMS" # used to verify image download libvirt_images_ubuntu_cloud_sha256sums_gpg: "SHA256SUMS.gpg" # used to verify checksums diff --git a/images/ubuntu-cloud/tasks/main.yml b/images/ubuntu-cloud/tasks/main.yml index 68aba1c..ee642c3 100644 --- a/images/ubuntu-cloud/tasks/main.yml +++ b/images/ubuntu-cloud/tasks/main.yml @@ -1,71 +1,77 @@ --- - name: Ensure image path exists - file: + ansible.builtin.file: path: "{{ libvirt_images_path }}" state: directory - recurse: yes + recurse: true -- name: download sums and signature - get_url: +- name: Download sums and signature + ansible.builtin.get_url: url: "{{ libvirt_images_ubuntu_cloud_url_base }}/{{ item }}" dest: "{{ libvirt_images_ubuntu_cloud_tmp_folder }}/{{ item }}" - force: yes - changed_when: no - with_flattened: - - "{{ libvirt_images_ubuntu_cloud_sha256sums }}" - - "{{ libvirt_images_ubuntu_cloud_sha256sums_gpg }}" + force: true + mode: "644" + changed_when: false + loop: + - "{{ libvirt_images_ubuntu_cloud_sha256sums }}" + - "{{ libvirt_images_ubuntu_cloud_sha256sums_gpg }}" -- name: check GPG keys - command: > +- name: Check GPG keys + ansible.builtin.command: > gpg --list-keys {{ libvirt_images_ubuntu_cloud_gpg_keys }} - failed_when: no - changed_when: no + failed_when: false + changed_when: false register: libvirt_images_ubuntu_cloud_gpg_result -- name: import GPG key - command: > +- name: Import GPG key + ansible.builtin.command: > gpg --keyserver {{ libvirt_images_ubuntu_cloud_gpg_key_server }} --recv-keys {{ libvirt_images_ubuntu_cloud_gpg_keys }} + changed_when: true when: libvirt_images_ubuntu_cloud_gpg_result.rc != 0 -- name: check and extract signature - shell: > - gpg - --verify {{ libvirt_images_ubuntu_cloud_sha256sums_gpg }} - {{ libvirt_images_ubuntu_cloud_sha256sums }} - && - cat {{ libvirt_images_ubuntu_cloud_sha256sums }} - | grep {{ libvirt_images_ubuntu_cloud_image_url | basename }} - | cut -f 1 -d " " - args: +- name: Check and extract signature + ansible.builtin.shell: + cmd: > + set -o pipefail && + gpg + --verify {{ libvirt_images_ubuntu_cloud_sha256sums_gpg }} + {{ libvirt_images_ubuntu_cloud_sha256sums }} + && + cat {{ libvirt_images_ubuntu_cloud_sha256sums }} + | grep {{ libvirt_images_ubuntu_cloud_image_url | basename }} + | cut -f 1 -d " " + executable: /bin/bash chdir: "{{ libvirt_images_ubuntu_cloud_tmp_folder }}" - changed_when: no + changed_when: false register: libvirt_images_ubuntu_cloud_sha256_result -- name: store sha256sum - set_fact: +- name: Store sha256sum + ansible.builtin.set_fact: libvirt_images_ubuntu_cloud_image_sha256: "{{ libvirt_images_ubuntu_cloud_sha256_result.stdout }}" -- name: download image disk - get_url: +- name: Download image disk + ansible.builtin.get_url: url: "{{ libvirt_images_ubuntu_cloud_image_url }}" - sha256sum: "{{ libvirt_images_ubuntu_cloud_image_sha256 }}" + checksum: "sha256:{{ libvirt_images_ubuntu_cloud_image_sha256 }}" dest: "{{ libvirt_images_path }}/{{ libvirt_images_ubuntu_cloud_image_dist }}" + mode: "644" register: libvirt_images_ubuntu_cloud_download_result -- name: remove modified image - file: +- name: Remove modified image + ansible.builtin.file: path: "{{ libvirt_images_path }}/{{ libvirt_images_ubuntu_cloud_image_name }}" state: absent - when: libvirt_images_ubuntu_cloud_download_result.changed + when: libvirt_images_ubuntu_cloud_download_result.changed and true -- name: convert the image - command: "qemu-img convert -O qcow2 {{ libvirt_images_ubuntu_cloud_image_dist }} {{ libvirt_images_ubuntu_cloud_image_name }}" +- name: Convert the image + ansible.builtin.command: "qemu-img convert -O qcow2 {{ libvirt_images_ubuntu_cloud_image_dist }} {{ libvirt_images_ubuntu_cloud_image_name }}" args: chdir: "{{ libvirt_images_path }}" creates: "{{ libvirt_images_path }}/{{ libvirt_images_ubuntu_cloud_image_name }}" -- include: store_facts.yml - when: libvirt_images_ubuntu_cloud_download_result.changed +- name: Store Facts + ansible.builtin.include_tasks: store_facts.yml + when: libvirt_images_ubuntu_cloud_download_result.changed and true diff --git a/images/ubuntu-cloud/tasks/store_facts.yml b/images/ubuntu-cloud/tasks/store_facts.yml index ff16c77..2b2c1e2 100644 --- a/images/ubuntu-cloud/tasks/store_facts.yml +++ b/images/ubuntu-cloud/tasks/store_facts.yml @@ -1,17 +1,19 @@ --- -- name: store_facts | facts directory - file: +- name: Store Facts | Facts directory + ansible.builtin.file: path: "{{ ansible_facts_path }}" state: directory - recurse: yes + mode: "755" + recurse: true -- name: "store_facts | ubuntu_{{ libvirt_images_ubuntu_cloud_image_name }}_cloud_image_path" - ini_file: +- name: "Store Facts | Ubuntu {{ libvirt_images_ubuntu_cloud_image_name }}" + community.general.ini_file: dest: "{{ ansible_facts_path }}/libvirt.fact" section: "facts" - option: "ubuntu_{{ libvirt_images_ubuntu_cloud_image_distribution }}_cloud_image_path" + option: "ubuntu_{{ libvirt_images_ubuntu_cloud_image_distribution }}_cloud_image_path" value: "{{ libvirt_images_path }}/{{ libvirt_images_ubuntu_cloud_image_name }}" + mode: "644" -- name: store_facts | re-read - setup: +- name: Store Facts | Re-read + ansible.builtin.setup: filter: ansible_local diff --git a/meta/main.yml b/meta/main.yml index f5f5a3f..7f28ebd 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,110 +1,12 @@ galaxy_info: - author: Andreas Reischuck - description: 'A stash of Ansible roles that allow you to control libvirt virtual machines' + author: "Andreas Reischuck" + role_name: "libvirt" + namespace: "hicknhack-software" + description: "A stash of Ansible roles that allow you to control libvirt virtual machines" company: HicknHack Software GmbH license: MIT - min_ansible_version: 1.8 - platforms: - #- name: EL - # versions: - # - all - # - 5 - # - 6 - # - 7 - #- name: GenericUNIX - # versions: - # - all - # - any - #- name: Fedora - # versions: - # - all - # - 16 - # - 17 - # - 18 - # - 19 - # - 20 - #- name: opensuse - # versions: - # - all - # - 12.1 - # - 12.2 - # - 12.3 - # - 13.1 - # - 13.2 - #- name: Amazon - # versions: - # - all - # - 2013.03 - # - 2013.09 - #- name: GenericBSD - # versions: - # - all - # - any - #- name: FreeBSD - # versions: - # - all - # - 8.0 - # - 8.1 - # - 8.2 - # - 8.3 - # - 8.4 - # - 9.0 - # - 9.1 - # - 9.1 - # - 9.2 - - name: Ubuntu - versions: - # - all - # - lucid - # - maverick - # - natty - # - oneiric - # - precise - # - quantal - # - raring - # - saucy - - trusty - #- name: SLES - # versions: - # - all - # - 10SP3 - # - 10SP4 - # - 11 - # - 11SP1 - # - 11SP2 - # - 11SP3 - #- name: GenericLinux - # versions: - # - all - # - any - #- name: Debian - # versions: - # - all - # - etch - # - lenny - # - squeeze - # - wheezy - # - # Below are all categories currently available. Just as with - # the platforms above, uncomment those that apply to your role. - # - categories: - - cloud - #- cloud:ec2 - #- cloud:gce - #- cloud:rax - #- clustering - #- database - #- database:nosql - #- database:sql - #- development - #- monitoring - #- networking - #- packaging - - system - #- web -dependencies: [] - # List your role dependencies here, one per line. Only - # dependencies available via galaxy should be listed here. - # Be sure to remove the '[]' above if you add dependencies - # to this list. + min_ansible_version: "2.10" + galaxy_tags: + - libvirt + - kvm + - system diff --git a/network/bridge/defaults/main.yml b/network/bridge/defaults/main.yml index dfe9cc6..98f1309 100644 --- a/network/bridge/defaults/main.yml +++ b/network/bridge/defaults/main.yml @@ -2,15 +2,15 @@ libvirt_bridge_path: '/etc/libvirt/ansible/networks' libvirt_bridges: -- name: default - forward: nat - bridge: virbr0 - domain: vm - ip_address: 192.168.122.1 - ip_netmask: 255.255.255.0 - dhcp_start: 192.168.122.2 - dhcp_end: 192.168.122.253 - #ipv6: - ipv6_prefix: 64 - #dhcp6_start: - #dhcp6_end: + - name: default + forward: nat + bridge: virbr0 + domain: vm + ip_address: 192.168.122.1 + ip_netmask: 255.255.255.0 + dhcp_start: 192.168.122.2 + dhcp_end: 192.168.122.253 + # ipv6: + ipv6_prefix: 64 + # dhcp6_start: + # dhcp6_end: diff --git a/network/bridge/tasks/main.yml b/network/bridge/tasks/main.yml index 4b49985..3f7d5e9 100644 --- a/network/bridge/tasks/main.yml +++ b/network/bridge/tasks/main.yml @@ -1,56 +1,59 @@ --- -- name: install packages - apt: - name: "{{ item }}" - update_cache: yes +- name: Install packages + ansible.builtin.apt: + pkg: + - resolvconf + update_cache: true state: latest cache_valid_time: 86400 - with_items: - - resolvconf -- name: create directory - file: +- name: Create directory + ansible.builtin.file: path: "{{ libvirt_bridge_path }}" state: directory + mode: "755" -- name: create config - template: +- name: Create config + ansible.builtin.template: src: config.xml.j2 dest: "{{ libvirt_bridge_path }}/{{ item.name }}.xml" - with_items: "{{ libvirt_bridges }}" + mode: "644" + loop: "{{ libvirt_bridges | list }}" register: configure_result -- name: check states - command: virsh net-info {{ item.item.name }} - failed_when: no - changed_when: no +- name: Check states + ansible.builtin.command: virsh net-info {{ item.item.name }} + failed_when: false + changed_when: false register: check_states_result - with_items: "{{ configure_result.results }}" + loop: "{{ configure_result.results | flatten(levels=1) }}" -- name: stop and undefine existing - shell: > +- name: Stop and undefine existing + ansible.builtin.shell: > virsh net-destroy {{ item[0].item.name }}; virsh net-undefine {{ item[0].item.name }} when: (item[1].rc == 0) and (item[0].changed) - with_together: - - "{{ configure_result.results }}" - - "{{ check_states_result.results }}" + changed_when: true + loop: "{{ configure_result.results | flatten(levels=1) | zip(check_states_result.results | flatten(levels=1)) | list }}" -- name: define and start - shell: > +- name: Define and start + ansible.builtin.shell: > virsh net-define {{ libvirt_bridge_path }}/{{ item.item.name }}.xml && virsh net-autostart {{ item.item.name }} && virsh net-start {{ item.item.name }} - when: item.changed - with_items: "{{ configure_result.results }}" + changed_when: true + when: item.changed and true -- name: add dnsmasq for host - lineinfile: + loop: "{{ configure_result.results | flatten(levels=1) }}" + +- name: Add dnsmasq for host + ansible.builtin.lineinfile: dest: "{{ libvirt_qemu_resolv_conf_head }}" regexp: "^nameserver" line: "nameserver {{ (libvirt_bridges | first).ip_address }}" register: nameserver_result -- name: call resolvconf - command: "resolvconf -u" - when: nameserver_result.changed +- name: Call resolvconf + ansible.builtin.command: "resolvconf -u" + changed_when: true + when: nameserver_result.changed and true diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..afc836d --- /dev/null +++ b/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - name: community.general