def run_machine(self, machine_name, preset=False): if isinstance(machine_name, libvirt.virDomain): # Processing domain object itself try: self.machine_name.create() except Exception as e: error = 'Unknown error while trying to start machine by domain object: %s' % e print (error) return (False, error) else: self._prepare_database() return (True, 'Machine started') # Simple approach -> start by reading configuration file folder = self.PRESETS if preset else self.IMAGES path = safe_join(folder, machine_name) try: with open(safe_join(path, self.CONFIG_NAME)) as f: f = f.read() except IOError: return (False, 'Cannot open config name for %s machine' % machine_name) machines = self._get_online_machines() try: self.connection.createXML(f, 0) except libvirt.libvirtError as e: return (False, str(e)) except Exception: return (False, 'Cannot run machine, but config file was found') else: # TODO: improve this algorithm cnt = 0 while machines == self._get_online_machines() and cnt < 5: cnt += 1 sleep(2) self._prepare_database() return (True, 'Machine started')
def _get_xml_info(self, machine_name, presets=False): source = self.IMAGES if not presets else self.PRESETS path = safe_join(source, machine_name) # Maybe this code is too indian-styled try: with open(safe_join(path, self.CONFIG_NAME)) as f: dom = minidom.parse(f) except IOError: type = 'unknown' memory = -1 cpu = '?' else: cpu = dom.getElementsByTagName('vcpu')[0].childNodes[0].data type = dom.getElementsByTagName('ajptype')[0].childNodes[0].data memory = int(dom.getElementsByTagName('memory')[0]. childNodes[0].data)/1024 # In MB finally: if not type: type = 'not specified' if not memory: memory = 0 if not cpu: cpu = '?' return (type, cpu, memory)
def get_presets_list(self): presets = [] try: presets_list = self.db.lrange("presets", 0, -1) except Exception: pass else: if presets_list: for element in presets_list: try: element = json.loads(element) except ValueError: continue else: presets.append(element) print ('Cached presets: %s' % presets) return presets # If not cache for directory in os.listdir(self.PRESETS): path = safe_join(self.PRESETS, directory) try: with open(safe_join(path, self.CONFIG_NAME)) as f: dom = minidom.parse(f) #import pdb; pdb.set_trace() except IOError: continue else: name = dom.getElementsByTagName('name')[0].childNodes[0].data # Get name of the VM try: with open(safe_join(path, self.DESCRIPTION_NAME)) as f: description = f.read() except IOError: continue else: presets.append({'name': name, 'description': description}) if presets: for preset in presets: item = json.dumps(preset) self.db.rpush('presets', item) else: self.db.rpush('presets', 'Empty') self.db.expire('presets', 600) print ('presets: ' + str(presets)) return presets
def _prepare_database(self, soft=False): # aka drop cache # Set flags in DB and also prepare list of preset domains print ('Cache dropped') if not soft: self.db.expire('copy', 0) self.db.set('provider', 'kvm') self.KVM_PATH = self.pg.KVM_PATH self.PRESETS = safe_join(self.KVM_PATH, self.pg.PRESETS) self.IMAGES = safe_join(self.KVM_PATH, self.pg.IMAGES) self.CONFIG_NAME = self.pg.CONFIG_NAME self.VMIMAGE_NAME = self.pg.VMIMAGE_NAME self.DESCRIPTION_NAME = self.pg.DESCRIPTION_NAME self.VMMANAGER_PATH = self.pg.VMMANAGER_PATH # Cleaning cache lists self.db.expire('online', 0) self.db.expire('offline', 0) self.db.expire('presets', 0)
def get_storage_info(self, machine): """ Calculating storage info (total, free, used) for new VM: We are getting all storage info and then calculate how much space you need to copy selected VM. FIXME: we are calculating info only for presets, this should be fixed for cloning non-preset machines. """ provider = self.db.io.get('provider') # TODO: optimize next, or maybe move it to VM provider. if provider == 'kvm': root = self.pg.KVM_PATH elif provider == 'xen': root = self.pg.XEN_PATH else: raise NotImplementedError path = safe_join(root, self.pg.IMAGES) preset_path = safe_join(root, self.pg.PRESETS) total, used, free = get_storage_info(path) preset_storage = calculate_flat_folder_size(safe_join(preset_path, machine)) return (total, used, free, preset_storage)
def _define_machines(self): """ Adding VM into Libvirt. Also refreshing changed config files. """ # Clearing all defined domains: #online = self._get_online_machines() # We cannot undefine running domain. So ignoring. offline = self._get_offline_machines() map(lambda x: x.undefine(), map(self.connection.lookupByName, offline)) # Find preset's name & image name of the machine and add it into libvirt for category in [self.IMAGES, self.PRESETS]: # Scanning both images and presets for directory in os.listdir(category): directory_ = safe_join(category, directory) # Building full path if not os.path.isdir(directory_): continue try: with open(safe_join(directory_, self.CONFIG_NAME)) as f: f = f.read() self.connection.defineXML(f) # vice versa -> undefine_XML except Exception as e: print (e) continue
def _clone(self, id, preset_name, machine_name, session, force=False): print ('cloning') if self.db.get('copy'): print ('Copy operation in progress') return {'answer': False, 'message': 'Copy operation already in progress'} self.db.set('copy', session) # Path preparations src = safe_join(self.PRESETS, preset_name) dst = safe_join(self.IMAGES, machine_name) if not os.path.exists(dst): os.makedirs(dst) else: if not force and os.path.\ exists(self.CONFIG_NAME) or os.path.\ exists(self.VMIMAGE_NAME) or os.path.\ exists(self.DESCRIPTION_NAME): return {'answer': False, 'message': 'Folder exists, use force to rewrite content'} # Prepare XML file additional_images = [] # File images (as additional partition files) with open(safe_join(src, self.CONFIG_NAME)) as f: # Now we are updating info in memory copy of preset's config file dom = minidom.parse(f) # <TOTAL_MADNESS> dom.getElementsByTagName('name')[0].childNodes[0].data = machine_name dom.getElementsByTagName('uuid')[0].childNodes[0].data = generate_uuid() for num, tag in enumerate(dom.getElementsByTagName('interface')): if tag.attributes.get('type').value == 'network': dom.getElementsByTagName('interface')[num].getElementsByTagName('mac')[0].attributes.get('address').value = generate_mac() # Change path of the images in config # Add to list of images additional disks for num, element in enumerate(dom.getElementsByTagName('disk')): if element.attributes.get('device').value == 'disk': path = element.getElementsByTagName('source')[0].attributes.get('file').value image_name = os.path.basename(path) if image_name != 'image.img': additional_images.append(image_name) dom.getElementsByTagName('disk')[num].\ getElementsByTagName('source')[0].\ attributes.get('file').value = safe_join(dst, image_name) # Write to file dom.writexml(open(safe_join(dst, self.CONFIG_NAME), 'w'), encoding='utf-8') # </TOTAL_MADNESS> # XML ready # Finding libvirt group name import grp try: groupinfo = grp.getgrnam('libvirt') gid = groupinfo.gr_gid except Exception as e: print ('Error while trying to determine libvirt\'s group: %s' % e) raise for file in [self.DESCRIPTION_NAME, self.VMIMAGE_NAME] + additional_images: try: shutil.copy2(safe_join(src, file), dst) except OSError as exc: # python >2.5 print ('Exception') if exc.errno == 28: return {'answer': False, 'message': 'No space left on device'} print (exc.errno) else: os.chown(safe_join(dst, file), -1, gid) # appending libvirt permissions to files os.chown(dst, -1, gid) # appending libvirt group to folder self.db.expire('copy', 0) # Drop cache: self._prepare_database(soft=True) # Prepare message to client print ('Files copied!') message = 'Sucessfully copied' return {'answer': True, 'message': message}