Skip to content

Commit

Permalink
Merge pull request #17 from andreygubarev/feature-simple-platforms-api
Browse files Browse the repository at this point in the history
feature simple platforms api
  • Loading branch information
andreygubarev authored Jun 17, 2023
2 parents c7953f2 + 6c168cc commit bff0d4f
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 105 deletions.
98 changes: 64 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ driver:
name: molecule-qemu
platforms:
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
vm_network: vmnet-shared
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_mode: vmnet-shared
provisioner:
name: ansible
inventory:
Expand All @@ -53,8 +53,31 @@ verifier:
name: testinfra
```
Full list of supported options:
```yaml
platforms:
- name: debian-bullseye-arm64

image_arch: aarch64 # optional, default is x86_64
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_format: qcow2 # optional, default is qcow2

network_mode: vmnet-shared # optional, default is user
network_ssh_port: 2222 # optional, default is 22
network_ssh_user: root # optional, default is root

vm_cpus: 1 # optional, default is 1
vm_memory: 512 # optional, default is 512
vm_disk: 8G # optional, default is 8G
```
### Dependencies
Driver depends on:
* QEMU (tested with 8.0.2)
* mkisofs (tested with 3.02a09)
Install QEMU and CDRTools on macOS:
```bash
Expand All @@ -73,29 +96,29 @@ apt-get install mkisofs qemu-system-x86 qemu-utils

This is the default network mode. It uses QEMU's user networking mode.

Mode is selected by setting `vm_network: user` in `molecule.yml`. This is the default mode. SSH port is forwarded to the host and must be unique for each platform (use `ssh_port` option to set it). Example:
Mode is selected by setting `network_mode: user` in `molecule.yml`. This is the default mode. SSH port is forwarded to the host and must be unique for each platform (use `network_ssh_port` option to set it). Example:

```yaml
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
vm_network: user # this is the default
ssh_port: 2022
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_mode: user
network_ssh_port: 2222
```
### `vmnet-shared` network mode

This mode uses QEMU's `vmnet-shared` networking mode. It requires `vmnet.framework` to be installed on the host. This mode is only supported on MacOS. It requires *passwordless* `sudo` access for current user.

Mode is selected by setting `vm_network: vmnet-shared` in `molecule.yml`. Example:
Mode is selected by setting `network_mode: vmnet-shared` in `molecule.yml`. Example:

```yaml
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
vm_network: vmnet-shared
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_mode: vmnet-shared
```

# Examples
Expand All @@ -106,38 +129,46 @@ See [tests](https://github.com/andreygubarev/molecule-qemu/tree/main/tests/molec

```yaml
platforms:
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
- name: debian-bullseye-amd64
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_ssh_port: 2222
- name: debian-bullseye-arm64
image_arch: aarch64
ssh_port: 10000
- name: debian-bullseye-amd64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: x86_64
ssh_port: 10001
- name: ubuntu-focal-arm64
image: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img
network_ssh_port: 2223
- name: ubuntu-focal-amd64
image_url: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
image_checksum: sha256:https://cloud-images.ubuntu.com/focal/current/SHA256SUMS
network_ssh_port: 2224
- name: ubuntu-focal-arm64
image_arch: aarch64
ssh_port: 10002
- name: ubuntu-focal-amd64
image: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-amd64.img
image_url: https://cloud-images.ubuntu.com/focal/current/focal-server-cloudimg-arm64.img
image_checksum: sha256:https://cloud-images.ubuntu.com/focal/current/SHA256SUMS
image_arch: x86_64
ssh_port: 10003
- name: ubuntu-jammy-arm64
image: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-arm64.img
network_ssh_port: 2225
- name: ubuntu-jammy-amd64
image_url: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
image_checksum: sha256:https://cloud-images.ubuntu.com/jammy/current/SHA256SUMS
network_ssh_port: 2226
- name: ubuntu-jammy-arm64
image_arch: aarch64
ssh_port: 10004
- name: ubuntu-jammy-amd64
image: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
image_url: https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-arm64.img
image_checksum: sha256:https://cloud-images.ubuntu.com/jammy/current/SHA256SUMS
image_arch: x86_64
ssh_port: 10005
network_ssh_port: 2227
```

# Troubleshooting

Molecule working directory is: `~/.cache/molecule/<role-name>/<scenario-name>`.
QEMU images caches is: `~/.cache/molecule/.qemu`.

# Cloud Images URLs

For convenience, here are the URLs for the cloud images used in the examples above.
Expand All @@ -156,7 +187,6 @@ For convenience, here are the URLs for the cloud images used in the examples abo
* https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img



# Reference

* [Ansible](https://www.ansible.com/)
Expand Down
67 changes: 35 additions & 32 deletions molecule_qemu/playbooks/create.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
molecule_scenario_name: "{{ lookup('env', 'MOLECULE_SCENARIO_NAME') }}"
molecule_project_name: "{{ lookup('env', 'MOLECULE_PROJECT_DIRECTORY') | basename }}"
qemu_cap_hvf: false
qemu_vm_image_arch: "x86_64"
qemu_vm_image_format: "qcow2"
qemu_vm_memory: "1024"
qemu_vm_cpus: "2"
qemu_vm_disk: "4G"
qemu_vm_network: "user"
qemu_image_arch: "x86_64"
qemu_image_format: "qcow2"
qemu_vm_memory: "512"
qemu_vm_cpus: "1"
qemu_vm_disk: "8G"
qemu_network_mode: "user"
qemu_timeout_arp: 120
qemu_timeout_ssh: 600

environment:
http_proxy: "{{ lookup('ansible.builtin.env', 'http_proxy') | default(omit) }}"
Expand All @@ -30,19 +32,20 @@
"instance": "molecule-{{ molecule_project_name }}-{{ molecule_scenario_name }}-{{ item.name }}",
"name": "{{ item.name }}",

"image": "{{ item.image }}",
"image_arch": "{{ item.image_arch | default(qemu_image_arch) }}",
"image_url": "{{ item.image_url }}",
"image_checksum": "{{ item.image_checksum | default(omit) }}",
"image_arch": "{{ item.image_arch | default(qemu_vm_image_arch) }}",
"image_format": "{{ item.image_format | default(qemu_vm_image_format) }}",
"image_format": "{{ item.image_format | default(qemu_image_format) }}",

"ssh_port": "{{ item.ssh_port | default(22) }}",
"ssh_user": "{{ item.ssh_user | default('root') }}",
"network_mode": "{{ item.network_mode | default(qemu_network_mode) }}",
"network_mac": "{{ '52:54:00' | community.general.random_mac() | regex_replace('(^|:)0([0-9A-Fa-f])', '\\1\\2') }}",

"network_ssh_port": "{{ item.network_ssh_port | default(22) }}",
"network_ssh_user": "{{ item.network_ssh_user | default('root') }}",

"vm_cpus": "{{ item.vm_cpus | default(qemu_vm_cpus) }}",
"vm_memory": "{{ item.vm_memory | default(qemu_vm_memory) }}",
"vm_disk": "{{ item.vm_disk | default(qemu_vm_disk) }}",
"vm_network": "{{ item.vm_network | default(qemu_vm_network) }}",
"vm_network_mac": "{{ '52:54:00' | community.general.random_mac(seed=(molecule_project_name + molecule_scenario_name + item.name) | to_json | hash('md5')) | regex_replace('(^|:)0([0-9A-Fa-f])', '\\1\\2') }}",

"path_disk": "{{ molecule_ephemeral_directory }}/run/{{ item.name }}.qcow2",
"path_pid": "{{ molecule_ephemeral_directory }}/run/{{ item.name }}.pid",
Expand Down Expand Up @@ -71,7 +74,7 @@
ansible.builtin.assert:
that:
- item.image_arch in ['x86_64', 'aarch64']
- item.vm_network in ['user', 'vmnet-shared']
- item.network_mode in ['user', 'vmnet-shared']
fail_msg: "Molecule instance {{ item.name }} configuration is not supported"
success_msg: "Molecule instance {{ item.name }} configuration is supported"
loop: "{{ molecule_instances }}"
Expand All @@ -81,21 +84,21 @@
- name: Assert VMs network configuration
ansible.builtin.assert:
that:
- molecule_instances | map(attribute='vm_network') | list | unique | length == 1
- molecule_instances | map(attribute='network_mode') | list | unique | length == 1
fail_msg: "Network modes are mutually exclusive"
success_msg: "Network modes are configured properly"

- name: Set QEMU network
ansible.builtin.set_fact:
qemu_vm_network: "{{ molecule_instances | map(attribute='vm_network') | list | unique | first }}"
qemu_network_mode: "{{ molecule_instances | map(attribute='network_mode') | list | unique | first }}"

- name: Assert VMs ssh configuration
ansible.builtin.assert:
that:
- molecule_instances | map(attribute='ssh_port') | list | unique | length == molecule_instances | length
- molecule_instances | map(attribute='network_ssh_port') | list | unique | length == molecule_instances | length
fail_msg: "Molecule instances SSH are not properly configured for 'user' network"
success_msg: "Molecule instances SSH are properly configured for 'user' network"
when: qemu_vm_network == 'user'
when: qemu_network_mode == 'user'

### capabilities ##########################################################

Expand Down Expand Up @@ -152,7 +155,7 @@
checksum: "{{ item[1] }}"
dest: "{{ molecule_driver_directory }}/images/{{ item[0] | basename }}"
mode: "0644"
loop: "{{ molecule_instances | map(attribute='image') | zip(molecule_instances | map(attribute='image_checksum')) | list | unique }}"
loop: "{{ molecule_instances | map(attribute='image_url') | zip(molecule_instances | map(attribute='image_checksum')) | list | unique }}"
loop_control:
label: "{{ item[0] | basename }}"
register: images
Expand Down Expand Up @@ -218,7 +221,7 @@
ansible.builtin.command: >
qemu-img create
-f qcow2
-o backing_file={{ images_cache[item.image] }},backing_fmt={{ item.image_format }}
-o backing_file={{ images_cache[item.image_url] }},backing_fmt={{ item.image_format }}
{{ item.path_disk }}
{{ item.vm_disk }}
args:
Expand All @@ -229,7 +232,7 @@

- name: Launch VMs as priviliged user
ansible.builtin.set_fact:
qemu_privileged: "{{ (qemu_vm_network == 'vmnet-shared') | bool }}"
qemu_privileged: "{{ (qemu_network_mode == 'vmnet-shared') | bool }}"

- name: Launch VMs
become: "{{ qemu_privileged }}"
Expand All @@ -241,11 +244,11 @@
-hda {{ item.path_disk }}
-m {{ item.vm_memory }}
-smp {{ item.vm_cpus }}
{% if item.vm_network == 'vmnet-shared' %}
-nic vmnet-shared,model=virtio-net-pci,mac={{ item.vm_network_mac }}
{% if item.network_mode == 'vmnet-shared' %}
-nic vmnet-shared,model=virtio-net-pci,mac={{ item.network_mac }}
{% endif %}
{% if item.vm_network == 'user' %}
-nic user,model=virtio-net-pci,hostfwd=tcp::{{ item.ssh_port }}-:22
{% if item.network_mode == 'user' %}
-nic user,model=virtio-net-pci,hostfwd=tcp::{{ item.network_ssh_port }}-:22
{% endif %}
-display none
-daemonize
Expand Down Expand Up @@ -289,14 +292,14 @@
### qemu network: vmnet-shared ############################################

- name: Configure QEMU network (vmnet-shared)
when: qemu_vm_network == 'vmnet-shared'
when: qemu_network_mode == 'vmnet-shared'
block:
- name: Get IPv4 addresses from ARP table (vmnet-shared)
ansible.builtin.shell: |
set -o pipefail
arp -an | grep -i '{{ item.vm_network_mac }}' | awk '{print $2}' | sed 's/[()]//g'
arp -an | grep -i '{{ item.network_mac }}' | awk '{print $2}' | sed 's/[()]//g'
until: molecule_instances_arp.stdout | length > 0
retries: 30
retries: "{{ qemu_timeout_arp }}"
delay: 1
loop: "{{ molecule_instances }}"
loop_control:
Expand All @@ -317,9 +320,9 @@
- name: Wait for SSH
ansible.builtin.wait_for:
host: "{{ molecule_instances_ipv4[item.name] }}"
port: "{{ item.ssh_port }}"
port: "{{ item.network_ssh_port }}"
delay: 30
timeout: "{{ 600 * molecule_instances | length }}"
timeout: "{{ qemu_timeout_ssh }}"
search_regex: "OpenSSH"
loop: "{{ molecule_instances }}"
loop_control:
Expand All @@ -333,8 +336,8 @@
"instance": "{{ item.instance }}",
"name": "{{ item.name }}",
"address": "{{ molecule_instances_ipv4[item.name] }}",
"user": "{{ item.ssh_user }}",
"port": "{{ item.ssh_port }}",
"user": "{{ item.network_ssh_user }}",
"port": "{{ item.network_ssh_port }}",
"identity_file": "{{ ssh_keypair.filename }}",
"pidfile": "{{ item.path_pid }}",
"diskfile": "{{ item.path_disk }}",
Expand Down
6 changes: 3 additions & 3 deletions tests/molecule/default/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ driver:
name: molecule-qemu
platforms:
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
ssh_port: 2022
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_ssh_port: 2222
provisioner:
name: ansible
verifier:
Expand Down
13 changes: 7 additions & 6 deletions tests/molecule/network-shared/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ driver:
name: molecule-qemu
platforms:
- name: debian-bullseye-amd64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: x86_64
vm_network: vmnet-shared
network_mode: vmnet-shared
vm_memory: 2048
vm_cpus: 2
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
vm_network: vmnet-shared
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_mode: vmnet-shared
provisioner:
name: ansible
verifier:
Expand Down
11 changes: 5 additions & 6 deletions tests/molecule/network-user/molecule.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@ driver:
name: molecule-qemu
platforms:
- name: debian-bullseye-amd64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-amd64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: x86_64
ssh_port: 10000
network_ssh_port: 2222
- name: debian-bullseye-arm64
image: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
image_arch: aarch64
ssh_port: 10001
image_url: https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-genericcloud-arm64.qcow2
image_checksum: sha512:https://cloud.debian.org/images/cloud/bullseye/latest/SHA512SUMS
network_ssh_port: 2223
provisioner:
name: ansible
verifier:
Expand Down
Loading

0 comments on commit bff0d4f

Please sign in to comment.