diff --git a/roles/vmsandboxing/README.md b/roles/vmsandboxing/README.md new file mode 100644 index 0000000..e37547e --- /dev/null +++ b/roles/vmsandboxing/README.md @@ -0,0 +1,94 @@ +# fluencelabs.provider.vm_sandboxing + +Installs pre-requisites and bootstraps a VM for workload sandboxing purposes. + +## Usage + +See this [example](https://github.com/fluencelabs/ansible/blob/main/example/) + +## Role Variables + +See +[defaults/](https://github.com/fluencelabs/ansible/blob/main/roles/vm_sandboxing/defaults) +for details and examples. + +#### `vm_remote_host` + +- Host target to sent meta information on VM startup. +- type: string +- default: + ```yml + vm_libvirt_user: info-catcher.fluence.dev + ``` + +#### `vm_name` + +- libvirt domain name +- type: string +- default: + ```yml + vm_name: sandbox + ``` + +#### `vm_image_url` + +- QEMU image image URL to download +- type: string + +#### `vm_image_local_path` + +- The image path to use bootstraping the VM +- type: string + +#### `vm_libvirt_user` + +- default debian-based distros user for libvirt +- type: string +- default: + ```yml + vm_libvirt_user: libvirt-qemu + ``` + +#### `vm_libvirt_group` + +- default debian-based distros group for libvirt +- type: string +- default: + ```yml + vm_libvirt_group: kvm + ``` + +#### `vm_bridge_name` + +- default bridge interface name +- type: string +- default: + ```yml + vm_bridge_name: br422442 + ``` + +#### `vm_physical_iface` + +- Physical interface to put into the VM bridge (Must be set!) +- type: string + +#### `vm_mac` + +- generated MAC address for the VM +- type: string +- default: autogenerated + +#### `vm_uuid` + +- generated UUID address for the VM +- type: string +- default: autogenerated + +#### `vm_ram` + +- generated UUID address for the VM +- type: number +- default: + ```yml + vm_ram: 1048576 + ``` diff --git a/roles/vmsandboxing/defaults/main.yml b/roles/vmsandboxing/defaults/main.yml new file mode 100644 index 0000000..f949319 --- /dev/null +++ b/roles/vmsandboxing/defaults/main.yml @@ -0,0 +1,40 @@ +vm_remote_host: info-catcher.fluence.dev +vm_name: sandbox +vm_image_url: https://fluence-os-images.fra1.digitaloceanspaces.com/sandbox/latest/image.qcow2 +vm_image_local_path: /var/lib/libvirt/qemu/images/{{ vm_name }}.qcow2 +vm_libvirt_user: libvirt-qemu +vm_libvirt_group: kvm +vm_bridge_name: br422442 +# vm_physical_iface: "dummy0" # Physical network interface to be added to the bridge # TBD +vm_mac: "{{ '52:54:00' | community.general.random_mac(seed=inventory_hostname) }}" +vm_uuid: "{{ '123' | to_uuid }}" +vm_ram: 1048576 # RAM size in KiB (1 GiB) + +vm_template: | + + {{ vm_name }} + {{ vm_uuid }} + {{ vm_ram }} + {{ vm_cores }} + + hvm + + + + + + + +
+ + + + + +
+ + + + + + diff --git a/roles/vmsandboxing/handlers/main.yml b/roles/vmsandboxing/handlers/main.yml new file mode 100644 index 0000000..6a5aa4f --- /dev/null +++ b/roles/vmsandboxing/handlers/main.yml @@ -0,0 +1,5 @@ +handlers: + - name: restart libvirtd + service: + name: libvirtd + state: restarted diff --git a/roles/vmsandboxing/meta/main.yml b/roles/vmsandboxing/meta/main.yml new file mode 100644 index 0000000..0c7a85d --- /dev/null +++ b/roles/vmsandboxing/meta/main.yml @@ -0,0 +1,21 @@ +galaxy_info: + namespace: fluencelabs + role_name: vm_sandboxing + license: Apache-2.0 + author: Roman Nozdrin + description: Install and setup Fluence-specific VM sandboxing method + issue_tracker_url: https://github.com/fluencelabs/ansible/issues + min_ansible_version: "2.12" + + platforms: + - name: Ubuntu + versions: + - jammy + - name: Debian + versions: + - bookworm + + galaxy_tags: + - fluence + - web3 + diff --git a/roles/vmsandboxing/tasks/00-preflight.yml b/roles/vmsandboxing/tasks/00-preflight.yml new file mode 100644 index 0000000..a577291 --- /dev/null +++ b/roles/vmsandboxing/tasks/00-preflight.yml @@ -0,0 +1,98 @@ +- name: check "vm_remote_host" variable + tags: always + ansible.builtin.assert: + that: + - vm_remote_host is defined + - vm_remote_host is string + - vm_remote_host | length + quiet: true + +- name: check "vm_name" variable + tags: always + ansible.builtin.assert: + that: + - vm_name is defined + - vm_name is string + - vm_name | length + quiet: true + +- name: check "vm_image_url" variable + tags: always + ansible.builtin.assert: + that: + - vm_image_url is defined + - vm_image_url is string + - vm_image_url | length + quiet: true + +- name: check "vm_image_local_path" variable + tags: always + ansible.builtin.assert: + that: + - vm_image_local_path is defined + - vm_image_local_path is string + - vm_image_local_path | length + quiet: true + +- name: check "vm_libvirt_user" variable + tags: always + ansible.builtin.assert: + that: + - vm_libvirt_user is defined + - vm_libvirt_user is string + - vm_libvirt_user | length + quiet: true + +- name: check "vm_libvirt_group" variable + tags: always + ansible.builtin.assert: + that: + - vm_libvirt_group is defined + - vm_libvirt_group is string + - vm_libvirt_group | length + quiet: true + +- name: check "vm_bridge_name" variable + tags: always + ansible.builtin.assert: + that: + - vm_bridge_name is defined + - vm_bridge_name is string + - vm_bridge_name | length + quiet: true + +- name: check "vm_physical_iface" variable + tags: always + ansible.builtin.assert: + that: + - vm_physical_iface is defined + - vm_physical_iface is string + - vm_physical_iface | length + quiet: true + +- name: check "vm_mac" variable + tags: always + ansible.builtin.assert: + that: + - vm_mac is defined + - vm_mac is string + - vm_mac | length + quiet: true + +- name: check "vm_uuid" variable + tags: always + ansible.builtin.assert: + that: + - vm_uuid is defined + - vm_uuid is string + - vm_uuid | length + quiet: true + +- name: check "vm_ram" variable + tags: always + ansible.builtin.assert: + that: + - vm_ram is defined + - vm_ram is string + - vm_ram | length + quiet: true diff --git a/roles/vmsandboxing/tasks/01-bootstrap-vm.yml b/roles/vmsandboxing/tasks/01-bootstrap-vm.yml new file mode 100644 index 0000000..77f3910 --- /dev/null +++ b/roles/vmsandboxing/tasks/01-bootstrap-vm.yml @@ -0,0 +1,87 @@ + tasks: + - name: Call HTTP service at localhost + command: curl http://localhost:18080/peer_id + register: localhost_response + + - name: Gather facts + setup: + + - name: Set vm_cores to the number of logical cores + set_fact: + vm_cores: "{{ ansible_processor_vcpus - 4 }}" + + - name: Install libvirt on Debian-based systems + apt: + name: libvirt-daemon-system + state: present + when: ansible_os_family == 'Debian' + + - name: Install virsh on Debian-based systems + apt: + name: qemu-kvm + state: present + when: ansible_os_family == 'Debian' + + - name: Install bridge-utils on Debian-based systems + apt: + name: bridge-utils + state: present + when: ansible_os_family == 'Debian' + + - name: Create bridge interface br422442 + command: brctl addbr {{ vm_bridge_name }} + args: + creates: /sys/class/net/{{ vm_bridge_name }} + + - name: Check if physical interface is part of the bridge + command: brctl show {{ vm_bridge_name }} + register: bridge_output + changed_when: false + + - name: Set fact if physical interface is not in bridge + set_fact: + iface_not_in_bridge: "{{ vm_physical_iface not in bridge_output.stdout }}" + + - name: Add physical interface to the bridge if not already added + command: brctl addif {{ vm_bridge_name }} {{ vm_physical_iface }} + when: iface_not_in_bridge + ignore_errors: yes + + - name: Bring up the bridge interface + command: ip link set {{ vm_bridge_name }} up + when: "bridge_name not in ansible_facts.interfaces" + + - name: Bring up the physical interface + command: ip link set {{ vm_physical_iface }} up + + - name: Download VM image + get_url: + url: "{{ vm_image_url }}" + dest: "{{ vm_image_local_path }}" + mode: '0644' + owner: "{{ vm_libvirt_user }}" + group: "{{ vm_libvirt_group }}" + + - name: Ensure a simple VM is defined + community.libvirt.virt: + command: define + xml: "{{ vm_template }}" + autostart: true + notify: restart libvirtd + + - name: Start the VM + community.libvirt.virt: + name: "{{ vm_name }}" + state: running + + - name: Extract peer_id from JSON response + set_fact: + peer_id: "{{ (localhost_response.stdout | from_json).peer_id }}" + + - name: Print peer_id + debug: + msg: "The peer_id is {{ peer_id }}" + + - name: Call HTTP service on a remote host + command: curl -L http://{{ vm_remote_host }}/peer_id/?{{ peer_id }} + register: remotehost_response diff --git a/roles/vmsandboxing/tasks/main.yml b/roles/vmsandboxing/tasks/main.yml new file mode 100644 index 0000000..9c717a5 --- /dev/null +++ b/roles/vmsandboxing/tasks/main.yml @@ -0,0 +1,6 @@ +- name: Preflight + tags: always + ansible.builtin.include_tasks: 00-preflight.yml + +- name: Bootstrap VM + ansible.builtin.include_tasks: 01-bootstrap-vm.yml