def start(self, job_id): """Start virtual machine. Async command. TO-DO : read config from extended database :param job_id: unique id of the async job """ self.logger.info('Start vm : %s' % self._id) if self.get_state() == 'Running': raise ClskObjectError('Virtual machine is already running.') VirtualMachine.start(self, job_id) # get virtual machine extended device from db if they are configured info = self.info(cache=False) # get vm id vm_id = info['id'] try: vm = self.db_manager.get_vm(vm_id) if vm: devices = vm['devices'] self.append_device(devices) except (QueryError, TransactionError) as ex: raise ClskObjectError(ex)
def list_tenants(self): '''List all tenants tenant syntax: <cloudsatck_id>.<domain_path>.<account> Ex. clsk42.ROOT/CSI/DC.test1 ''' params = {'command':'listAccounts', 'listall':'true'} tenants_list = [] try: response = self._api_client.send_api_request(params) res = json.loads(response)['listaccountsresponse'] if len(res) > 0: accounts = res['account'] for account in accounts: domain_path = self.get_domain_path(account['domainid']) #domain = account['domain'] #if domain != 'ROOT': # domain = "ROOT/%s" % domain tenant = "%s.%s.%s" % (self.clsk_instance.name, domain_path, account['name']) tenants_list.append(tenant) else: return [] except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex) return tenants_list
def list_volumes(self): '''List storage pool volumes.''' params = {'command':'listVolumes', 'listall':'true', 'zoneid':self._data['zoneid'], } try: response = self._api_client.send_api_request(params) res = json.loads(response)['listvolumesresponse'] if len(res) > 0: data = res['volume'] else: return [] except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex) volumes = [] for item in data: # create Volume instance volume = VolumeExt(self.clsk_instance, data=item) volumes.append(volume) return volumes
def list_virtual_machines(self): '''List all virtual machines.''' params = { 'command': 'listVirtualMachines', 'listall': True, 'networkid': self._id, } try: response = self._api_client.send_api_request(params) res = json.loads(response)['listvirtualmachinesresponse'] if len(res) > 0: data = res['virtualmachine'] else: return [] except KeyError as ex: self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex) vms = [] for item in data: # create Account instance vm = VirtualMachineExt(self.clsk_instance, data=item) vms.append(vm) return vms
def list_routers(self): '''List all routers''' params = {'command':'listRouters', 'listAll':'true' } try: response = self._api_client.send_api_request(params) res = json.loads(response)['listroutersresponse'] if len(res) > 0: data = res['router'] else: return [] except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex) vms = [] for item in data: # create Account instance vm = VirtualRouterExt(self.clsk_instance, data=item) vms.append(vm) return vms
def change_graphics_password(self, password): """"Append additionale devices not supported from cloudstack using low level api like libvirt or vpshere api. :param devices: litst with additional devices : spice_graphics, vlc_graphics, video_cirrus, video_qxl, virtio_serial, usb_redirect, sound_card, """ self.logger.info('Change password to vm : %s' % self._id) info = self.info(cache=True) if self.get_state() != 'Running': raise ClskObjectError('Virtual machine is not running.') # get hypervisor name hostname = info['hostname'] # get vm internal name vm_internal_name = info['instancename'] # get vm id vm_id = info['id'] # get vm hypervisor hypervisor = info['hypervisor'] # KVM hypervisor if hypervisor == 'KVM': '''TO-DO : gestire meglio le operazioni: se una delle due fallisce l'altra potrebbe andare a termine senza rendersene conto''' # change password of libvirt domain try: # get connection to qemu server qemu_conn = self.clsk_instance.get_hypervisor_conn( 'qemu', hostname) # create instance of VirtDomain virt_domain = VirtDomain(qemu_conn, name=vm_internal_name) # change graphics password virt_domain.change_graphics_password(password) # delete vm manager instance del virt_domain # release libvirt connection self.clsk_instance.release_hypervisor_conn( 'qemu', hostname, qemu_conn) except (ApiManagerError, VirtDomainError) as ex: self.logger.error('Error changing libvirt domain password') raise ClskObjectError(ex) # save password on db try: self.db_manager.update_graphic_password(vm_id, 'test') except (QueryError, TransactionError) as ex: self.logger.error('Error saving libvirt domain password to db') raise ClskObjectError(ex) # other hypervisor else: self.logger.debug( 'Hypervisor %s doesn\'t support graphic device change password' % (hypervisor))
def create_private_network(self, name, displaytext, networkoffering_id, zone_id, domain_id=None, domain=None, account=None, networkdomain=None, physicalnetworkid=None): '''Create private network. ''' params = {'command':'createNetwork', 'name':name, 'displaytext':displaytext, 'networkofferingid':networkoffering_id, 'zoneid':zone_id, 'acltype':'Account', } if domain: params['domainid'] = self.get_domain_id(domain) elif domain_id: params['domainid'] = domain_id if account: params['account'] = account if physicalnetworkid: params['physicalnetworkid'] = physicalnetworkid if networkdomain: params['networkdomain'] = networkdomain try: self._api_client.set_timeout(120) response = self._api_client.send_api_request(params) res = json.loads(response)['createnetworkresponse'] if len(res) > 0: data = res['network'] else: return None # create network net = NetworkExt(self.clsk_instance, data=data) self.logger.debug('Private cloudstack network was created: %s' % name) return net except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex)
def list_networks(self, zone_id=None, domain=None, domain_id=None, account=None, net_id=None): '''List network. :param zone_id: [optional] id of the zone :param domain_id: [optional] id of the domain :param domain: [optional] name of the domain :param account: [optional] name of the account :param net_id: [optional] id of the network ''' params = {'command':'listNetworks', 'listall':'true'} if zone_id: params['zoneid'] = zone_id if domain_id: params['domainid'] = domain_id if domain: params['domainid'] = self.get_domain_id(domain) if account: params['account'] = account if net_id: params['id'] = net_id try: response = self._api_client.send_api_request(params) res = json.loads(response)['listnetworksresponse'] if len(res) > 0: data = res['network'] else: return [] except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex) networks = [] for item in data: # create Account instance network = NetworkExt(self.clsk_instance, data=item) networks.append(network) return networks
def list_volumes(self, zone_id=None, domain=None, domain_id=None, account=None, vol_id=None): '''List volumes. :param zone_id: [optional] id of the zone :param domain_id: [optional] id of the domain :param domain: [optional] name of the domain :param account: [optional] name of the account :param vole_id: [optional] id of the volume ''' params = {'command':'listVolumes', 'listall':'true'} if zone_id: params['zoneid'] = zone_id if domain: params['domainid'] = self.get_domain_id(domain) if domain_id: params['domainid'] = domain_id if account: params['account'] = account if vol_id: params['id'] = vol_id try: response = self._api_client.send_api_request(params) res = json.loads(response)['listvolumesresponse'] if len(res) > 0: data = res['volume'] else: return [] except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex) volumes = [] for item in data: # create Network instance volume = VolumeExt(self.clsk_instance, data=item) volumes.append(volume) return volumes
def config(self): """Describe virtual machine configuration.""" self.logger.info('Get configuration for vm : %s' % self._id) info = self.info(cache=True) if self.get_state() != 'Running': raise ClskObjectError('Virtual machine is not running.') # get hypervisor name hostname = info['hostname'] # get vm internal name vm_internal_name = info['instancename'] # get vm hypervisor hypervisor = info['hypervisor'] # KVM hypervisor if hypervisor == 'KVM': try: # get connection to qemu server qemu_conn = self.clsk_instance.get_hypervisor_conn( 'qemu', hostname) # create instance of VirtDomain virt_domain = VirtDomain(qemu_conn, name=vm_internal_name) # get domain info info = virt_domain.info() # delete vm manager instance del virt_domain # release libvirt connection self.clsk_instance.release_hypervisor_conn( 'qemu', hostname, qemu_conn) return info except (ApiManagerError, VirtDomainError) as ex: self.logger.error('Error reading libvirt domain configuration') raise ClskObjectError(ex) # other hypervisor else: return None
def get_storagepool_info(self): '''List all storage pools.''' params = {'command': 'listStoragePools', 'name': self._data['storage']} try: response = self._api_client.send_api_request(params) res = json.loads(response)['liststoragepoolsresponse'] if len(res) > 0: data = res['storagepool'][0] pool_info = { 'type': data['type'], 'state': data['state'], 'path': data['path'], 'ipaddress': data['ipaddress'] } return pool_info else: return None except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex)
def list_storagepools(self, zoneid=None, name=None): '''List all storage pools.''' params = {'command':'listStoragePools'} if zoneid: params['zoneid'] = zoneid if name: params['name'] = name try: response = self._api_client.send_api_request(params) res = json.loads(response)['liststoragepoolsresponse']['storagepool'] data = res except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex) storagepools = [] for item in data: # create StoragePool instance storagepool = StoragePoolExt(self.clsk_instance, data=item) storagepools.append(storagepool) return storagepools
def list_virtual_machines(self, domain=None, account=None, vm_id=None): '''List all virtual machines.''' params = {'command':'listVirtualMachines', 'listall':'true', } if domain: try: params['domainid'] = self.get_domain_id(domain) except ApiError as ex: raise ClskObjectError(ex) if account: params['account'] = account if vm_id: params['id'] = vm_id try: response = self._api_client.send_api_request(params) res = json.loads(response)['listvirtualmachinesresponse'] if len(res) > 0: data = res['virtualmachine'] else: return [] except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex) vms = [] for item in data: # create Account instance vm = VirtualMachineExt(self.clsk_instance, data=item) vms.append(vm) return vms
def stop(self, job_id): """Stop virtual machine. Async command. read config from extended database TO-DO : read config from extended database :param job_id: unique id of the async job """ self.logger.info('Stop vm : %s' % self._id) if self.get_state() != 'Running': raise ClskObjectError('Virtual machine is not running.') VirtualMachine.stop(self, job_id)
def destroy(self, job_id): """Destroy virtual machine. Async command.""" self.logger.info('Destroy vm : %s' % self._id) VirtualMachine.destroy(self, job_id) # remove virtual machine extended device from db if they are configured info = self.info(cache=True) # get vm id vm_id = info['id'] try: vm = self.db_manager.get_vm(vm_id) if vm: self.db_manager.delete_vm(vm_id) except (QueryError, TransactionError) as ex: raise ClskObjectError(ex)
def update(self, job_id, devices): """Update virtual machine. Async command. TO-DO : read config from extended database :param job_id: unique id of the async job """ self.logger.info('Update vm : %s' % self._id) # get virtual machine extended device from db if they are configured info = self.info(cache=True) # get vm id vm_id = info['id'] try: vm = self.db_manager.get_vm(vm_id) if vm: # remove old config self.db_manager.delete_vm(vm_id) # append new devices self.append_device(devices) except (QueryError, TransactionError) as ex: raise ClskObjectError(ex)
def list_volume(self): """List virtual machine volume. TODO: extend to other hypervisor """ # get qemu disk info #disks = self.config()['devices']['disk'] # get cloudstack volume info params = { 'command': 'listVolumes', 'listall': 'true', 'virtualmachineid': self._id } try: response = self._api_client.send_api_request(params) res = json.loads(response)['listvolumesresponse'] if len(res) > 0: vols = res['volume'] volumes = [] for vol in vols: # create VolumeExt object volume_obj = VolumeExt(self.clsk_instance, data=vol) # get volume type vol_type = vol['type'] # create base volume = { 'id': vol['id'], 'name': vol['name'], 'offering': get_attrib(vol, 'diskofferingdisplaytext', ''), 'size': vol['size'], 'storage': vol['storage'], 'type': vol_type, 'deviceid': vol['deviceid'], 'attached': get_attrib(vol, 'attached', '') } """ # set extended info to ROOT volume if self._data['hypervisor'] == 'KVM' and vol_type == 'ROOT': volume['source'] = {} # get storage pool connection info pool_info = volume_obj.get_storagepool_info() volume['source']['type'] = pool_info['type'] volume['source']['path'] = pool_info['path'] volume['source']['ipaddress'] = pool_info['ipaddress'] # find qemu root disk for disk in disks: if (disk['alias']['name'] == 'ide0-0-0' and disk['target']['dev'] == 'hda' or disk['alias']['name'] == 'virtio-disk0' and disk['target']['dev'] == 'vda'): volume['source']['file'] = disk['source']['file'].split('/')[-1] """ # append volume volumes.append(volume) return volumes else: return [] except KeyError as ex: raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: raise ClskObjectError(ex)
def create_vm(self, job_id, name, displayname, serviceofferingid, templateid, zoneid, domain, account, hypervisor, networkids, devices=None, hostid=None, diskofferingid=None, size=None, keyboard='it'): """Create virtual machine. Async command. TO-DO : extend to support vmware virtual machine :param job_id: unique id of the async job :param name: host name for the virtual machine :param displayname: an optional user generated name for the virtual machine :param serviceofferingid: the ID of the service offering for the virtual machine :param templateid: the: ID of the template for the virtual machine :param zoneid: availability zone for the virtual machine :param domain: an optional domain for the virtual machine. If the account parameter is used, domain must also be used. :param account: an optional account for the virtual machine. Must be used with domainId. :param projectid: Deploy vm for the project :param diskofferingid: the ID of the disk offering for the virtual machine. If the template is of ISO format, the diskOfferingId is for the root disk volume. Otherwise this parameter is used to indicate the offering for the data disk volume. If the templateId parameter passed is from a Template object, the diskOfferingId refers to a DATA Disk Volume created. If the templateId parameter passed is from an ISO object, the diskOfferingId refers to a ROOT Disk Volume created. :param hostid: destination Host ID to deploy the VM to - parameter available for root admin only :param hypervisor: the hypervisor on which to deploy the virtual machine :param networkids: list of network ids used by virtual machine. Can't be specified with ipToNetworkList parameter :param keyboard: an optional keyboard device type for the virtual machine. valid value can be one of de,de-ch,es,fi,fr, fr-be,fr-ch,is,it,jp,nl-be,no,pt,uk,us :param keypair: name of the ssh key pair used to login to the virtual machine :param size: the arbitrary size for the DATADISK volume. Mutually exclusive with diskOfferingId :param startvm: true if network offering supports specifying ip ranges; defaulted to true if not specified :param devices: dict with additional devices : {'spice_graphics':''} spice_graphics, vnc_graphics, rdp_graphics, video_cirrus, video_qxl, virtio_serial, usb_redirect, sound_card_ac97, sound_card_es1370, sound_card_sb16, sound_card_ich6 """ self.logger.info('Create new extended virtual machine - START') # get domain id domainid = self.get_domain_id(domain) # create vm with cloudstack api params = {'command':'deployVirtualMachine', 'name':name, 'displayname':displayname, 'serviceofferingid':serviceofferingid, 'templateid':templateid, 'zoneid':zoneid, 'domainid':domainid, 'account':account, 'hypervisor':hypervisor, 'networkids':networkids, 'keyboard':keyboard, 'startvm':'true', } # the ID of the disk offering for the virtual machine. If the template # is of ISO format, the diskOfferingId is for the root disk volume. # Otherwise this parameter is used to indicate the offering for # the data disk volume if diskofferingid != None: params['diskofferingid'] = diskofferingid # the arbitrary size for the DATADISK volume. Mutually exclusive with # diskOfferingId if size != None: params['size'] = size # destination Host ID to deploy the VM to if hostid != None: params['hostid'] = hostid try: response = self._api_client.send_api_request(params) res = json.loads(response) clsk_job_id = res['deployvirtualmachineresponse']['jobid'] data = self._api_client.query_async_job(job_id, clsk_job_id)['virtualmachine'] # create virtualmachine object vm = VirtualMachineExt(self.clsk_instance, data=data) self.logger.debug('Default cloudstack virtual machine was created: %s' % name) except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex) # append devices vm.append_device(devices) self.logger.info('Create new extended virtual machine - STOP') return vm
def create_external_network(self, name, displaytext, networkoffering_id, zone_id, gateway, netmask, startip, endip, vlan, domain_id=None, domain=None, account=None, networkdomain=None, shared=False, physicalnetworkid=None): '''Create diretc network for the account :param shared: True set network shared for all account in the domain. False set network isolated to account. :param gateway: 10.102.221.129 :param netmask: 255.255.255.240 :param startip: 10.102.221.130 :param endip: 10.102.221.142 :param vlan: 329 ''' params = {'command':'createNetwork', 'name':name, 'displaytext':displaytext, 'networkofferingid':networkoffering_id, 'zoneid':zone_id, 'gateway':gateway, 'netmask':netmask, 'startip':startip, 'endip':endip, 'vlan':vlan, } # set shared status of the network if shared: params['acltype'] = 'Domain' else: params['acltype'] = 'Account' if domain: params['domainid'] = self.get_domain_id(domain) elif domain_id: params['domainid'] = domain_id if account: params['account'] = account if physicalnetworkid: params['physicalnetworkid'] = physicalnetworkid if networkdomain: params['networkdomain'] = networkdomain try: self._api_client.set_timeout(120) response = self._api_client.send_api_request(params) res = json.loads(response)['createnetworkresponse'] if len(res) > 0: data = res['network'] else: return None # create network net = NetworkExt(self.clsk_instance, data=data) self.logger.debug('Hybrid cloudstack network was created: %s' % name) return net except KeyError as ex : self.logger.error('Error parsing json data: %s' % ex) raise ClskObjectError('Error parsing json data: %s' % ex) except ApiError as ex: self.logger.error(ex) raise ClskObjectError(ex)
def append_device(self, devices): """"Append additionale devices not supported from cloudstack using low level api like libvirt or vpshere api. :param devices: litst with additional devices : spice_graphics, vlc_graphics, video_cirrus, video_qxl, virtio_serial, usb_redirect, sound_card, """ self.logger.info('Append device to vm : %s' % self._id) info = self.info(cache=True) if self.get_state() != 'Running': raise ClskObjectError('Virtual machine is not running.') # get hypervisor name hostname = info['hostname'] # get vm internal name vm_internal_name = info['instancename'] # get vm id vm_id = info['id'] # get vm hypervisor hypervisor = info['hypervisor'] # KVM hypervisor if hypervisor == 'KVM': '''TO-DO : gestire meglio le operazioni: se una delle due fallisce l'altra potrebbe andare a termine senza rendersene conto''' # append device to libvirt domain try: # get connection to qemu server qemu_conn = self.clsk_instance.get_hypervisor_conn( 'qemu', hostname) # create instance of VirtDomain virt_domain = VirtDomain(qemu_conn, name=vm_internal_name) # append extra devices domain2 = virt_domain.append_device(devices.keys()) # delete vm manager instance del virt_domain # release libvirt connection self.clsk_instance.release_hypervisor_conn( 'qemu', hostname, qemu_conn) except (ApiManagerError, VirtDomainError) as ex: self.logger.error('Error appending devices to libvirt domain') raise ClskObjectError(ex) # save virtual machine devices configuration on db try: # add new virtual machine reference into db and append device # if it doesn't exists if not self.db_manager.get_vm(vm_id): self.db_manager.add_vm(vm_id, devices) except (QueryError, TransactionError) as ex: self.logger.error( 'Error saving libvirt domain extended configuration to db') raise ClskObjectError(ex) # other hypervisor else: self.logger.debug('Hypervisor %s doesn\'t support append devices' % (hypervisor))