def disk_set(vm_hostname, size): """Change the disk size of a VM Currently only increasing the disk is implemented. Size argument is allowed as text, but it must always be in GiBs without a decimal place. The plus (+) and minus (-) prefixes are allowed to specify a relative difference in the size. Of course, minus is going to error out. """ with ExitStack() as es: vm = es.enter_context(_get_vm(vm_hostname)) current_size_gib = vm.dataset_obj['disk_size_gib'] if size.startswith('+'): new_size_gib = current_size_gib + parse_size(size[1:], 'g') elif size.startswith('-'): new_size_gib = current_size_gib - parse_size(size[1:], 'g') else: new_size_gib = parse_size(size, 'g') if new_size_gib == vm.dataset_obj['disk_size_gib']: raise Warning('Disk size is the same.') _check_defined(vm) vm.hypervisor.vm_set_disk_size_gib(vm, new_size_gib) vm.dataset_obj['disk_size_gib'] = new_size_gib vm.dataset_obj.commit()
def mem_set(vm_hostname, size, offline=False): """Change the memory size of a VM Size argument is a size unit, which defaults to MiB. The plus (+) and minus (-) prefixes are allowed to specify a relative difference in the size. Reducing memory is only allowed while the VM is powered off. """ with ExitStack() as es: vm = es.enter_context(_get_vm(vm_hostname)) _check_defined(vm) if size.startswith('+'): new_memory = vm.dataset_obj['memory'] + parse_size(size[1:], 'm') elif size.startswith('-'): new_memory = vm.dataset_obj['memory'] - parse_size(size[1:], 'm') else: new_memory = parse_size(size, 'm') if new_memory == vm.dataset_obj['memory']: raise Warning('Memory size is the same.') if offline and not vm.is_running(): log.info( '"{}" is already powered off, ignoring --offline.'.format( vm.fqdn) ) offline = False if offline: vm.shutdown() vm.set_memory(new_memory) if offline: vm.start()
def memory_free(self): meminfo = self.meminfo() if 'MemAvailable' in meminfo: kib_free = parse_size(meminfo['MemAvailable'], 'K') # MemAvailable might not be present on old systems elif 'MemFree' in meminfo: kib_free = parse_size(meminfo['MemFree'], 'K') else: raise VMError('/proc/meminfo contains no parsable entries') return round(float(kib_free) / 1024, 2)
def from_running(cls, hypervisor, vm, domain): xml = domain.XMLDesc() tree = ElementTree.fromstring(xml) self = cls(hypervisor, vm) self._domain = domain self.uuid = domain.UUIDString() self.hugepages = tree.find('memoryBacking/hugepages') is not None self.num_nodes = max(len(tree.findall('cpu/numa/cell')), 1) self.max_cpus = domain.vcpusFlags(VIR_DOMAIN_VCPU_MAXIMUM) self.mem_hotplug = tree.find('maxMemory') is not None memballoon = tree.find('devices/memballoon') if memballoon is not None and \ memballoon.attrib.get('model') == 'virtio': self.mem_balloon = True # maxMemory() returns the current memory, even if a maxMemory node is # present. if not self.mem_hotplug: self.max_mem = domain.maxMemory() else: self.max_mem = parse_size( tree.find('maxMemory').text + tree.find('maxMemory').attrib['unit'], 'M', ) self.current_memory = parse_size( tree.find('memory').text + tree.find('memory').attrib['unit'], 'M', ) self.mac_address = tree.find('devices/interface/mac').attrib['address'] if self.num_nodes > 1: self.numa_mode = self.NUMA_SPREAD elif re.search(r'placement=.?auto', xml): self.numa_mode = self.NUMA_AUTO # Domain is unbound if it is allowed to run on all available cores. elif all(all(p for p in pcpus) for pcpus in domain.vcpuPinInfo()): self.numa_mode = self.NUMA_UNBOUND else: log.warning('Cannot determine NUMA of "{}" for KVM.'.format( vm.fqdn)) self.numa_node = self.NUMA_UNKNOWN return self
def _get_disk_vm(): return parse_size( self.vm.run( "df -h / | tail -n+2 | awk '{ print $2 }'").strip(), 'G')