Browse Source

v0.4-alpha

master
Doug Le Tough 1 year ago
parent
commit
d1c98f0a0f
3 changed files with 85 additions and 32 deletions
  1. +17
    -0
      README.md
  2. +1
    -1
      kvm_base.xml
  3. +67
    -31
      virt_vm.py

+ 17
- 0
README.md View File

@ -67,8 +67,15 @@ The module needs to access _XML_ domain files. These files will be searched in `
## Limitations
This module is **not** a complete implementation of _libvirt_ and some _libvirt_ parameters are not available.
This module does **not** make any constitency ckeck on parameters. It's up to users to provide a consistent configuration to prevent failed module run or inconsistent virtual machine state.
Also note that some operations such as upgrading `max_memory` can not be done on a live system.
These operations will be tried but, as they need a full reboot of guest system, will not be forced. Rebooting guest OS when needed must be done manually and is user responsability.
[Registering a variable](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables) may be useful for debugging purpose (especially the `live_settings` dict that will show what has been succesfully, or not, applied to the live guest O.S).
## Known bugs
Most bugs are unknown.
@ -76,6 +83,8 @@ Please, send reports or pull requests to [contact at mcos.nc](/dev/null)
## Parameters
Due to complex combinations of parameters, all parameters are mandatory:
| var | object | type |
@ -87,6 +96,8 @@ Due to complex combinations of parameters, all parameters are mandatory:
| `machine_type` | Virtual machine type (see [documentation(https://libvirt.org/formatdomaincaps.html)]) | **str** |
| `vcpus` | Max number of CPUs used by virtual machine | **int** |
| `cpu_set` | Set of CPUs used by virtual machine (see [documentation](https://libvirt.org/formatdomaincaps.html)) | **str** |
| `memory_slots` | Number of memory slots for **guest** O.S. | **int** |
| `max_memory` | Maximum of RAM allocation for **guest** O.S. Expressed in _KiB. | **int** |
| `memory` | RAM size available for **guest** O.S. Expressed in _KiB. | **int** |
| `mac_addr` | _MAC_ address for **guest** interface. This _MAC_ address can be generated and will be used by **guest O.S** | **str** |
| `spice_password` | Password to connect via _spice_ protocol to domain | **str** |
@ -124,6 +135,8 @@ kvm_vms:
machine_type: pc-q35-rhel7.6.0
vcpus: 2
cpu_set: 1-2
memory_slots: 16
max_memory: 12582912
memory: 2097152
mac_addr: '00:71:37:05:00:01'
spice_password: GcwpZqi7zwSqRWZJcgOl
@ -139,6 +152,8 @@ kvm_vms:
machine_type: pc-q35-rhel7.6.0
vcpus: 1
cpu_set: 3
memory_slots: 16
max_memory: 12582912
memory: 1048576
mac_addr: '00:71:37:05:00:02'
spice_password: M9SsdsuC8t7ZmN7qtsHI
@ -192,6 +207,8 @@ kvm_vms:
machine_type: "{{ item.machine_type }}"
vcpus: "{{ item.vcpus }}"
cpu_set: "{{ item.cpu_set }}"
memory_slots: "{{ item.memory_slots }}"
max_memory: "{{ item.max_memory }}"
memory: "{{ item.memory }}"
mac_addr: "{{ item.mac_addr }}"
spice_password: "{{ item.spice_password }}"


+ 1
- 1
kvm_base.xml View File

@ -2,7 +2,7 @@
<name></name>
<uuid></uuid>
<description></description>
<memory unit='KiB'>15728640</memory>
<memory unit='KiB'></memory>
<currentMemory unit='KiB'></currentMemory>
<vcpu placement='static' cpuset=''></vcpu>
<os>


+ 67
- 31
virt_vm.py View File

@ -37,7 +37,7 @@ class VirtVM:
def _set_xml_memory(self, element):
"""Set VM memory
"""
element.text = str(self.params['memory'])
element.text = str(self.params['max_memory'])
def _set_xml_current_memory(self, element):
"""Set VM current memory.
@ -80,21 +80,18 @@ class VirtVM:
self.params['spice_interface'])
def get_virt_domain(self):
"""Get libvirt.virDomain object from UUID and keep a reference to it in self.vir_domain
"""Get libvirt.virDomain object from UUID and keep a reference to it in self.vir_domain. Also get XML from domain XML file.
:return: True if operation succeeded, False otherwise.
:return: True if operation succeeded, False otherwise, meaning that domain does not exist on system.
:rtype: bool
"""
try:
# with libvirt.open(self.vir_connection) as connect:
# self.vir_domain = connect.lookupByUUIDString(self.params['uuid'])
with libvirt.open(self.vir_connection) as connect:
self.vir_domain = connect.lookupByUUIDString(self.params['uuid'])
with open(os.path.join(
self.params['libvirt_qemu_conf_path'],
'{}.xml'.format(self.params['name']))) as actual_xml_file:
self.xml_actual_root = etree.parse(actual_xml_file).getroot()
# self.xml_actual_root = etree.fromstring(
# self.vir_domain.XMLDesc(
# flags=libvirt.VIR_DOMAIN_XML_SECURE))
return True
except Exception as e:
return False
@ -175,13 +172,15 @@ class VirtVM:
:return: True if no error encountered. False otherwise
:rtype: bool
"""
result = 'unchanged'
try:
autostart = self.vir_domain.autostart()
if self.params['auto_start'] != autostart:
self.vir_domain.setAutostart(self.params['auto_start'])
result = 'changed'
except Exception as e:
return False
return True
result = 'error'
return result
def _set_state(self):
"""Set domain state (Running or destroyed).
@ -189,52 +188,85 @@ class VirtVM:
:return: True if no error encountered. False otherwise
:rtype: bool
"""
result = 'unchanged'
active = self.vir_domain.isActive()
xml = self.vir_domain.XMLDesc(flags=libvirt.VIR_DOMAIN_XML_SECURE)
try:
if self.params['active'] != active and self.params['active']:
with libvirt.open(self.vir_connection) as connect:
connect.createXML(xml)
result = 'changed'
elif self.params['active'] != active and not self.params['active']:
self.vir_domain.destroy()
result = 'changed'
except Exception as e:
return False
return True
result = 'error'
return result
def _set_vcpus_map(self):
# VIR_VCPU_OFFLINE = 0
# VIR_VCPU_RUNNING = 1
# VIR_VCPU_BLOCKED = 2
"""Set vcpus map for domain
:return: True if no error encountered. False otherwise
:rtype: bool
"""
result = 'unchanged'
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE
state = libvirt.VIR_VCPU_RUNNING
if self.vir_domain.isActive():
try:
vpcus = self.vir_domain.vcpusFlags()
if vpcus != self.params['vcpus']:
self.vir_domain.setGuestVcpus(self.params['vcpus'], libvirt.VIR_VCPU_RUNNING)
self.vir_domain.setGuestVcpus(self.params['vcpus'], state, flags)
result = 'changed'
except Exception as e:
return False
return True
result = 'error'
return result
def _set_vcpus(self):
"""Set number of vcpus for domain
:rtype: bool
"""
result = 'unchanged'
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE
if self.vir_domain.isActive():
try:
vpcus = self.vir_domain.vcpusFlags()
if vpcus != self.params['vcpus']:
self.vir_domain.setVcpus(self.params['vcpus'])
self.vir_domain.setVcpusFlags(self.params['vcpus'], flags)
result = 'changed'
except Exception as e:
return False
return True
def get_memory(self):
pass
result = 'error'
return result
def _set_memory(self):
try:
maxmem = self.vir_domain.maxMemory()
if maxmem != self.params['memory']:
self.vir_domain.setMaxMemory(self.params['memory'])
except Exception as e:
return False
return True
"""Set available memory amount for domain
:rtype: bool
"""
result = 'unchanged'
flags = libvirt.VIR_DOMAIN_AFFECT_LIVE
if self.vir_domain.isActive():
try:
stats = self.vir_domain.memoryStats()
if stats['actual'] != self.params['memory']:
self.vir_domain.setMemoryFlags(self.params['memory'], flags)
result = 'changed'
except Exception as e:
result = 'error'
return result
def apply_live_settings(self):
results = {}
if self.get_virt_domain():
settings = {'autostart': self._set_autostart,
'state': self._set_state,
'vcpus_map': self._set_vcpus_map,
'vcpus': self._set_vcpus,
'memory': self._set_memory, }
for setting in settings:
results[setting] = settings[setting]()
return results
def main():
module = AnsibleModule(
@ -247,6 +279,8 @@ def main():
machine_type = dict(required=True),
vcpus = dict(required=True, type='int'),
cpu_set = dict(required=True),
memory_slots = dict(required=True, type='int'),
max_memory = dict(required=True, type='int'),
memory = dict(required=True, type='int'),
mac_addr = dict(required=True, type='str'),
spice_password = dict(required=True, no_log=True),
@ -297,6 +331,8 @@ def main():
result['defined'] = True
result['changed'] = True
live_settings = virt_vm.apply_live_settings()
result['live_settings'] = live_settings
# Eventually, we have succeed !
module.exit_json(**result)


Loading…
Cancel
Save