-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #152 from redhatci/kvirt_cluster
Add kvirt VM role
- Loading branch information
Showing
7 changed files
with
353 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
# kvirt_vm role | ||
|
||
This role allows the deployment of Kubevirt virtual machines. In order to execute the role a running OpenShift cluster and its credentials are required. i.e. through the KUBECONFIG environment variable. | ||
|
||
The role is aimed for deployment of virtual nodes for OCP deployments, so only the root disk is created. | ||
|
||
```shell | ||
export KUBECONFIG=<path_kubeconfig> | ||
``` | ||
|
||
Main tasks: | ||
- Validate the storage class | ||
- Check the required operators (CNV) | ||
- Create the VMs and set it to the desired state | ||
|
||
This role has been tested only in x86_64 architectures. | ||
|
||
# Role variables | ||
| Variable | Required | Type | Default | Description | ||
| ----------------------------- | --------- | ------- | --------- | ----------- | ||
| kvirt_vm_config_file | Yes | String | Undefined | The configuration file with the VM's settings | ||
|
||
## VM configs | ||
| Variable | Default | Required | Description | ||
| ----------------------------- | ----------------------------- | ----------- | --------------------------------- | ||
| vms_settings | | yes | A list with the settings for each VM | ||
| name | | yes | VM name | ||
| force | false | no | Destroy the VM if already | ||
| namespace | default | no | VM namespace | ||
| storage_class | <default> | no | Root disk storage class | ||
| memory | 8Gi | no | VM memory | ||
| disk_mode | ReadWriteOnce | no | VM disk volume mode | ||
| disk_size | 60Gi | no | Root disk size | ||
| os | rhcos | no | VM Operating system annotation | ||
| cpu_cores | 8 | no | VM CPU cores | ||
| cpu_sockets | 1 | no | VM CPU sockets | ||
| cpu_threads | 1 | no | VM CPU threads | ||
| network_interface_multiqueue | true | no | Enable NIC multiqueue | ||
| running | false | no | Set the initial VM power state | ||
| node_selector | | no | Configure nodes selector | ||
| interfaces | virtio/masquerade | no | Network interface definitions | ||
| networks | Pod network | no | VM network definitions | ||
|
||
## Usage examples | ||
|
||
See below for some examples of how to use the kvirt_vm role to create a VM. | ||
|
||
Deploy a VM with custom configs | ||
|
||
```yaml | ||
- name: "Create a kvirt VM" | ||
vars: | ||
vms_config_file: /path/to/vms-config-file.yaml | ||
ansible.builtin.include_role: | ||
name: redhatci.ocp.kvirt_vm | ||
``` | ||
Three VMs with default settings | ||
```yaml | ||
--- | ||
vm_configs: | ||
- name: master-0 | ||
- name: master-1 | ||
- name: master-2 | ||
``` | ||
Generic VM definition | ||
```yaml | ||
--- | ||
vm_configs: | ||
- name: test | ||
force: true | ||
namespace: myns | ||
memory: 8Gi | ||
disk_mode: ReadWriteOnce | ||
disk_size: 60Gi | ||
os: rhcos | ||
cpu_cores: 8 | ||
cpu_sockets: 1 | ||
cpu_threads: 1 | ||
network_interface_multiqueue: true | ||
running: false | ||
node_selector: | ||
kubernetes.io/hostname: master-1 | ||
interfaces: | ||
- masquerade: {} | ||
model: virtio | ||
name: default | ||
networks: | ||
- name: default | ||
pod: {} | ||
ansible.builtin.include_role: | ||
name: redhatci.ocp.kvirt_vm | ||
``` | ||
VM config file with SRIOV settings | ||
```yaml | ||
--- | ||
vm_configs: | ||
- name: master-1 | ||
interfaces: | ||
- macAddress: "54:54:00:00:21:20" | ||
name: sriov_resource_name_0 | ||
sriov: {} | ||
- macAddress: "54:54:00:00:21:21" | ||
name: sriov_resource_name_1 | ||
sriov: {} | ||
networks: | ||
- multus: | ||
networkName: sriov-network-name-0 | ||
name: sriov_resource_name_0 | ||
- multus: | ||
networkName: sriov-network-name-1 | ||
name: sriov_resource_name_1 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
kvirt_vm_api_version: kubevirt.io/v1 | ||
kvirt_vm_namespace: default | ||
kvirt_vm_memory: 8Gi | ||
kvirt_vm_disk_mode: ReadWriteOnce | ||
kvirt_vm_disk_size: 60Gi | ||
kvirt_vm_os: rhcos | ||
kvirt_vm_cpu_cores: 8 | ||
kvirt_vm_cpu_sockets: 1 | ||
kvirt_vm_cpu_threads: 1 | ||
kvirt_vm_network_interface_multiqueue: true | ||
kvirt_vm_running: false | ||
kvirt_vm_force: false | ||
kvirt_vm_interfaces: | ||
- masquerade: {} | ||
model: virtio | ||
name: default | ||
kvirt_vm_networks: | ||
- name: default | ||
pod: {} | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
--- | ||
- name: Create the VM Namespace for {{ vm.name }} | ||
community.kubernetes.k8s: | ||
definition: | ||
apiVersion: v1 | ||
kind: Namespace | ||
metadata: | ||
name: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
labels: | ||
security.openshift.io/scc.podSecurityLabelSync: "false" | ||
pod-security.kubernetes.io/enforce: "baseline" | ||
pod-security.kubernetes.io/enforce-version: "latest" | ||
|
||
- name: Create the VM {{ vm.name }} | ||
community.kubernetes.k8s: | ||
definition: "{{ lookup('template', 'templates/vm-template.yml.j2') }}" | ||
|
||
- name: Wait for VM to be in desired state {{ vm.name }} | ||
vars: | ||
state: |- | ||
{%- if vm.running | default(kvirt_vm_running) %} | ||
Running{%- else %} | ||
Stopped{%- endif %} | ||
community.kubernetes.k8s_info: | ||
api: "{{ vm.api_version | default(kvirt_vm_api_version) }}" | ||
kind: VirtualMachine | ||
name: "{{ vm.name }}" | ||
namespace: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
register: info | ||
until: | ||
- info.resources is defined | ||
- info.resources[0].status.printableStatus == state | ||
retries: 60 | ||
delay: 5 | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--- | ||
- name: "Delete VM {{ vm.name }}" | ||
community.kubernetes.k8s: | ||
kind: VirtualMachine | ||
api_version: "{{ vm.api_version | default(kvirt_vm_api_version) }}" | ||
name: "{{ vm.name }}" | ||
namespace: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
state: absent | ||
|
||
- name: Wait for VirtualMachine to be deleted | ||
community.kubernetes.k8s_info: | ||
api: "{{ vm.api_version | default(kvirt_vm_api_version) }}" | ||
kind: VirtualMachine | ||
name: "{{ vm.name }}" | ||
namespace: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
register: info | ||
until: | ||
- info.resources is defined | ||
- info.resources | length == 0 | ||
retries: 60 | ||
delay: 5 | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
--- | ||
- name: Run validations | ||
ansible.builtin.include_tasks: validations.yml | ||
|
||
- name: Delete VM | ||
ansible.builtin.include_tasks: delete-vm.yml | ||
when: vm.force | default(kvirt_vm_force) | bool | ||
loop: "{{ vm_configs }}" | ||
loop_control: | ||
loop_var: vm | ||
label: "{{ vm.name }}" | ||
|
||
- name: Create the VM | ||
ansible.builtin.include_tasks: create-vm.yml | ||
loop: "{{ vm_configs }}" | ||
loop_control: | ||
loop_var: vm | ||
label: "{{ vm.name }}" | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
--- | ||
- name: Check VM config file | ||
ansible.builtin.stat: | ||
path: "{{ kvirt_vm_config_file }}" | ||
register: vms_conf_file_stat | ||
|
||
- name: Fail if VM config file is not found | ||
ansible.builtin.fail: | ||
msg: "VM config file {{ kvirt_vm_config_file }} not found" | ||
when: not vms_conf_file_stat.stat.exists | ||
|
||
- name: Fail VM config file is empty | ||
ansible.builtin.fail: | ||
msg: "VM config file {{ kvirt_vm_config_file }} is empty" | ||
when: vms_conf_file_stat.stat.size == 0 | ||
|
||
- name: Load VM config file | ||
ansible.builtin.include_vars: | ||
file: "{{ kvirt_vm_config_file }}" | ||
when: vms_conf_file_stat.stat.exists | ||
|
||
- name: Fail if VM config file does not contain vm_configs | ||
ansible.builtin.fail: | ||
msg: "VM config file {{ kvirt_vm_config_file }} does not contain vm_configs" | ||
when: vm_configs is not defined | ||
|
||
- name: Fail if not all VMs have a name | ||
ansible.builtin.fail: | ||
msg: "At least a VM in config file {{ kvirt_vm_config_file }} does not contain a name" | ||
when: vm_configs | selectattr('name', 'undefined') | list | length > 0 | ||
|
||
- name: "Get Storage Classes" | ||
community.kubernetes.k8s_info: | ||
api_version: v1 | ||
kind: StorageClass | ||
register: sc | ||
no_log: true | ||
|
||
- name: "Fail when there is no storage class available" | ||
ansible.builtin.fail: | ||
msg: "A storage class does not exists" | ||
when: | ||
- sc.resources | length == 0 | ||
|
||
- name: "Fail when defined storage class does not exist" | ||
vars: | ||
query_sc_name: 'resources[*].metadata.name' | ||
query_results: "{{ sc | json_query(query_sc_name) }}" | ||
ansible.builtin.fail: | ||
msg: "The defined storage class does not exist" | ||
when: | ||
- kvirt_cluster_storage_class is defined | ||
- kvirt_cluster_storage_class not in query_results | ||
|
||
- name: "Fail when no default storage class" | ||
vars: | ||
query_default_sc: 'resources[*].metadata.annotations."storageclass.kubernetes.io/is-default-class"' | ||
query_results: "{{ sc | json_query(query_default_sc) }}" | ||
ansible.builtin.fail: | ||
msg: "No default storage class was found" | ||
when: | ||
- sc is defined | ||
- "not('true' in query_results)" | ||
- kvirt_cluster_storage_class is undefined | ||
|
||
- name: "Check if the CNV CRD is present" | ||
community.kubernetes.k8s_info: | ||
kind: CustomResourceDefinition | ||
name: kubevirts.kubevirt.io | ||
register: kvirt_crd | ||
no_log: true | ||
|
||
- name: "Fail if CNV CRD is not present" | ||
fail: | ||
msg: "CRDs are not present" | ||
when: kvirt_crd.resources | list | count == 0 | ||
... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
apiVersion: "{{ vm.api_version | default(kvirt_vm_api_version) }}" | ||
kind: "VirtualMachine" | ||
metadata: | ||
name: "{{ vm.name }}" | ||
namespace: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
spec: | ||
dataVolumeTemplates: | ||
- apiVersion: cdi.kubevirt.io/v1beta1 | ||
kind: DataVolume | ||
metadata: | ||
annotations: | ||
cdi.kubevirt.io/storage.bind.immediate.requested: "true" | ||
name: os-disk-{{ vm.namespace | default(kvirt_vm_namespace) }}-{{ vm.name }} | ||
spec: | ||
accessModes: [ "{{ vm.disk_mode | default(kvirt_vm_disk_mode) }}" ] | ||
{% if storage_class is defined %} | ||
storageClassName: "{{ vm.storage_class | default(kvirt_vm_storage_class) }}" | ||
{% endif %} | ||
source: | ||
blank: {} | ||
storage: | ||
resources: | ||
requests: | ||
storage: "{{ vm.disk_size | default(kvirt_vm_disk_size) }}" | ||
running: {{ vm.running | default(kvirt_vm_running) }} | ||
template: | ||
metadata: | ||
annotations: | ||
vm.kubevirt.io/os: "{{ vm.os | default(kvirt_vm_os) }}" | ||
labels: | ||
kubevirt.io/domain: "{{ vm.namespace | default(kvirt_vm_namespace) }}" | ||
spec: | ||
{% if node_selector is defined %} | ||
nodeSelector: {{ vm.node_selector }} | ||
{% endif %} | ||
architecture: amd64 | ||
domain: | ||
cpu: | ||
cores: {{ vm.cpu_cores | default(kvirt_vm_cpu_cores) }} | ||
sockets: {{ vm.cpu_sockets | default(kvirt_vm_cpu_sockets) }} | ||
threads: {{ vm.cpu_threads | default(kvirt_vm_cpu_threads) }} | ||
devices: | ||
disks: | ||
- disk: | ||
bus: virtio | ||
name: rootdisk | ||
interfaces: {{ vm.interfaces | default(kvirt_vm_interfaces) }} | ||
networkInterfaceMultiqueue: {{ vm.network_interface_multiqueue | default(kvirt_vm_network_interface_multiqueue) }} | ||
rng: {} | ||
features: | ||
acpi: {} | ||
smm: | ||
enabled: true | ||
firmware: | ||
bootloader: | ||
efi: {} | ||
memory: | ||
guest: "{{ vm.memory | default(kvirt_vm_memory)}}" | ||
resources: {} | ||
networks: {{ vm.networks | default(kvirt_vm_networks) }} | ||
volumes: | ||
- dataVolume: | ||
name: os-disk-{{ vm.namespace | default(kvirt_vm_namespace) }}-{{ vm.name }} | ||
name: rootdisk |