# Copyright 2016 Huawei Technologies Co.,LTD. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ [VRM DRIVER] VRM CLIENT. """ import json import threading from oslo_config import cfg from oslo_log import log as logging from cinder import exception from cinder.i18n import _ from cinder.volume.drivers.huawei.fusioncompute.base_proxy import BaseProxy from cinder.volume.drivers.huawei.fusioncompute.conf import FC_DRIVER_CONF from cinder.volume.drivers.huawei.fusioncompute.task_proxy import TaskProxy try: from eventlet import sleep except ImportError: from time import sleep TASK_WAITING = 'waiting' TASK_RUNNING = 'running' TASK_SUCCESS = 'success' TASK_FAILED = 'failed' TASK_CANCELLING = 'cancelling' TASK_UNKNOWN = 'unknown' LOG = logging.getLogger(__name__) CONF = cfg.CONF vrm_template_lock = threading.Lock() class VmProxy(BaseProxy): '''VmProxy VmProxy ''' def __init__(self, *args, **kwargs): super(VmProxy, self).__init__() self.task_proxy = TaskProxy() def query_vm(self, **kwargs): '''Query VM 'query_vm': ('GET', ('/vms', None, kwargs.get('vm_id'), None), {}, {}, False) ''' LOG.info(_("[VRM-CINDER] start query_vm()")) uri = '/vms' method = 'GET' path = self.site_uri + uri + '/' + kwargs.get('vm_id') new_url = self._generate_url(path) resp, body = self.vrmhttpclient.request(new_url, method) LOG.info(_("[VRM-CINDER] end ()")) return body def query_vm_by_uri(self, **kwargs): '''Query VM by Uri 'query_vm': ('GET', ('/vms', None, kwargs.get('vm_id'), None), {}, {}, False) ''' LOG.info(_("[VRM-CINDER] start query_vm()")) method = 'GET' path = kwargs.get('vm_uri') new_url = self._generate_url(path) resp, body = self.vrmhttpclient.request(new_url, method) LOG.info(_("[VRM-CINDER] end ()")) return body def delete_vm(self, **kwargs): '''Delete VM 'delete_vm': ('DELETE', ('/vms', None, kwargs.get('vm_id'), None), {}, {}, True), ''' LOG.info(_("[VRM-CINDER] start delete_vm()")) uri = '/vms' method = 'DELETE' path = self.site_uri + uri + '/' + kwargs.get('vm_id') if kwargs.get('isReserveDisks') is not None and kwargs.get( 'isReserveDisks') == 1: path = path + '?isReserveDisks=1' new_url = self._generate_url(path) resp, body = self.vrmhttpclient.request(new_url, method) task_uri = body.get('taskUri') if kwargs.get('isReserveDisks') is not None and kwargs.get( 'isReserveDisks') == 1: self.task_proxy.wait_task(task_uri=task_uri, isShortQuery=1) else: self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end ()")) def detach_vol_from_vm(self, **kwargs): '''detach_vol_from_vm 'detach_vol_from_vm': ('POST', ('/vms', None, kwargs.get('vm_id'), 'action/detachvol'), {}, {'volUrn': kwargs.get('volUrn')}, True), ''' LOG.info(_("[VRM-CINDER] start detach_vol_from_vm()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/detachvol' new_url = self._generate_url(path) body = {'volUrn': kwargs.get('volume_urn')} resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end ()")) def attach_vol_to_vm(self, **kwargs): '''attach_vol_to_vm 'attach_vol_to_vm': ('POST', ('/vms', None, kwargs.get('vm_id'), 'action/attachvol'), {}, {'volUrn': kwargs.get('volUrn')}, True), ''' LOG.info(_("[VRM-CINDER] start attach_vol_to_vm()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/attachvol' new_url = self._generate_url(path) body = {'volUrn': kwargs.get('volume_urn')} resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end attach_vol_to_vm()")) def stop_vm(self, **kwargs): '''stop_vm 'stop_vm': ('POST', ('/vms', None, kwargs.get('vm_id'), 'action/stop'), {}, {'mode': kwargs.get('mode')}, True), ''' LOG.info(_("[VRM-CINDER] start stop_vm()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get('vm_id') + '/action/stop' new_url = self._generate_url(path) body = {'mode': kwargs.get('mode')} resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end ()")) def _combine_empty_vmConfig(self, **kwargs): '''_combine_empty_vmConfig :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start _combine_empty_vmConfig ()")) cpu_quantity = 2 mem_quantityMB = 1024 cpu = {'quantity': cpu_quantity} memory = {'quantityMB': mem_quantityMB} disks = [] vmConfigBody = { 'cpu': cpu, 'memory': memory, 'disks': disks, } LOG.info(_("[VRM-CINDER] _combine_empty_vmConfig end ()")) return vmConfigBody def _combine_vmConfig_4_import(self, **kwargs): '''_combine_vmConfig_4_import :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start _combine_vmConfig ()")) cpu_quantity = 2 mem_quantityMB = 1024 datastoreUrn = kwargs.get('ds_urn') if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 link = kwargs.get('linkClone') disk_quantityGB = kwargs.get('volume_size') if link: uuid = "" if kwargs.get('quick_start') is True: disk_quantityGB = kwargs.get('image_size') else: uuid = kwargs.get("volume_id") thin = kwargs.get('is_thin') volumeUrn = kwargs.get('volume_urn') cpu = {'quantity': cpu_quantity} memory = {'quantityMB': mem_quantityMB} disks = [ { 'volumeUrn': volumeUrn, 'datastoreUrn': datastoreUrn, 'quantityGB': disk_quantityGB, 'volType': 0, 'sequenceNum': kwargs.get('volume_sequence_num'), 'pciType': 'IDE', 'volumeUuid': uuid, 'isThin': thin, 'isCoverData': True } ] vmConfigBody = { 'cpu': cpu, 'memory': memory, 'disks': disks, } LOG.info(_("[VRM-CINDER] end ()")) return vmConfigBody def _combine_vmConfig_4_clone(self, **kwargs): '''_combine_vmConfig_4_clone :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start _combine_vmConfig ()")) cpu_quantity = 2 mem_quantityMB = 1024 datastoreUrn = kwargs.get('ds_urn') if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 disk_quantityGB = kwargs.get('volume_size') link = kwargs.get('linkClone') if link: uuid = "" else: uuid = kwargs.get("volume_id") thin = kwargs.get('is_thin') cpu = {'quantity': cpu_quantity} memory = {'quantityMB': mem_quantityMB} disks = [ { 'datastoreUrn': datastoreUrn, 'quantityGB': disk_quantityGB, 'volType': 0, 'sequenceNum': 1, 'pciType': 'IDE', 'volumeUuid': uuid, 'isThin': thin } ] vmConfigBody = { 'cpu': cpu, 'memory': memory, 'disks': disks, } LOG.info(_("[VRM-CINDER] end ()")) return vmConfigBody def _combine_vmConfig_4_export(self, **kwargs): '''_combine_vmConfig_4_export :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start _combine_vmConfig ()")) cpu_quantity = 2 mem_quantityMB = 1024 if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 cpu = {'quantity': cpu_quantity} memory = {'quantityMB': mem_quantityMB} disks = [ { 'sequenceNum': kwargs.get('volume_sequence_num'), } ] vmConfigBody = { 'cpu': cpu, 'memory': memory, 'disks': disks, } LOG.info(_("[VRM-CINDER] end ()")) return vmConfigBody def _combine_os_options(self, **kwargs): '''_combine_os_options :param kwargs: :return: ''' osOptions = { 'osType': 'Windows', 'osVersion': 26 } LOG.info(_("[VRM-CINDER] end ()")) return osOptions def clone_vm(self, **kwargs): '''clone_vm :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start clone_vm()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'template_id') + '/action/clone' new_url = self._generate_url(path) linked_clone = kwargs.get('linked_clone') if linked_clone is None: linked_clone = False LOG.info(_("[VRM-CINDER] start clone_vm()")) body = { 'name': 'cinder-vm-' + kwargs.get('volume_id'), 'group': 'FSP', 'description': 'cinder-driver-temp-vm', 'autoBoot': 'false', 'isLinkClone': linked_clone, 'vmConfig': self._combine_vmConfig_4_clone(**kwargs), } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri, isShortQuery=1) LOG.info(_("[VRM-CINDER] end clone_vm()")) return body.get('urn') def import_vm_from_glance(self, **kwargs): '''import_vm_from_glance :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start import_vm_from_glance()")) uri = self.site_uri + '/vms/action/import' method = 'POST' new_url = self._generate_url(uri) link_nfs = kwargs.get('linkClone') if link_nfs: name = kwargs.get('image_id') else: name = kwargs.get('volume_id') is_template = kwargs.get("is_template") if is_template is None or is_template: template = 'true' else: template = 'false' token = kwargs.get('auth_token') endpoint = str(FC_DRIVER_CONF.glance_host) + ":" + str(FC_DRIVER_CONF.glance_port) serviceIp = FC_DRIVER_CONF.glance_host_ip body = { 'name': 'cinder-vm-' + name, 'group': 'FSP', 'description': 'cinder-glance-vm', 'autoBoot': 'false', 'location': kwargs.get("cluster_urn"), 'osOptions': self._combine_os_options(**kwargs), 'protocol': "glance", 'vmConfig': self._combine_vmConfig_4_import(**kwargs), 'isTemplate': template, 'glanceConfig': { 'imageID': kwargs.get('image_id'), 'endPoint': endpoint, 'serverIp': serviceIp, 'token': token} } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end import_vm_from_glance()")) return body.get('urn') def import_vm_from_uds(self, **kwargs): '''import_vm_from_uds :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start import_vm_from_uds()")) uri = self.site_uri + '/vms/action/import' method = 'POST' new_url = self._generate_url(uri) link_nfs = kwargs.get('linkClone') if link_nfs: name = kwargs.get('image_id') else: name = kwargs.get('volume_id') is_template = kwargs.get("is_template") if is_template is None or is_template: template = 'true' else: template = 'false' if FC_DRIVER_CONF.s3_store_access_key_for_cinder is None or \ FC_DRIVER_CONF.s3_store_secret_key_for_cinder is None: LOG.error(_("[VRM-CINDER] some params is None, please check: " "s3_store_access_key_for_cinder, " "s3_store_secret_key_for_cinder")) raise exception.ParameterNotFound( param='s3_store_access_key_for_cinder or ' 's3_store_secret_key_for_cinder') uds_name = FC_DRIVER_CONF.s3_store_access_key_for_cinder uds_password = FC_DRIVER_CONF.s3_store_secret_key_for_cinder location = kwargs.get('image_location') location = location.split(":") if len(location) != 4: msg = _('image_location is invalid') LOG.error(msg) raise exception.ImageUnacceptable(image_id=kwargs.get('image_id'), reason=msg) serverIp = location[0].strip() port = location[1].strip() bucketName = location[2].strip() key = location[3].strip() body = { 'name': 'cinder-vm-' + name, 'group': 'FSP', 'description': 'cinder-uds-vm', 'autoBoot': 'false', 'location': kwargs.get("cluster_urn"), 'osOptions': self._combine_os_options(**kwargs), 'protocol': "uds", 'vmConfig': self._combine_vmConfig_4_import(**kwargs), 'isTemplate': template, 's3Config': { 'serverIp': serverIp, 'port': port, 'accessKey': uds_name, 'secretKey': uds_password, 'bucketName': bucketName, 'key': key } } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end import_vm_from_uds()")) return body.get('urn') def import_vm_from_nfs(self, **kwargs): '''import_vm_from_nfs 'import_vm_from_image': ('POST', ('/vms/action/import', None, None, None), {}, dict({ 'name': 'name', 'location': kwargs.get('cluster_urn'), 'autoBoot': 'false', 'url': kwargs.get('url'), 'protocol': 'nfs', 'vmConfig': { 'cpu': { 'quantity': 1 }, 'memory': { 'quantityMB': 1024 }, 'disks': [ { 'pciType': 'IDE', 'datastoreUrn': kwargs.get('ds_urn'), 'quantityGB': kwargs.get('vol_size'), 'volType': 0, 'sequenceNum': 1, }, ], }, 'osOptions': { 'osType': 'Windows', 'osVersion': 32 } }), True), ''' LOG.info(_("[VRM-CINDER] start import_vm_from_nfs()")) uri = self.site_uri + '/vms/action/import' method = 'POST' new_url = self._generate_url(uri) link_nfs = kwargs.get('linkClone') if link_nfs: name = kwargs.get('image_id') else: name = kwargs.get('volume_id') is_template = kwargs.get("is_template") if is_template is None or is_template: template = 'true' else: template = 'false' body = \ { 'name': 'cinder-vm-' + name, 'group': 'FSP', 'description': 'cinder-nfs-vm', 'autoBoot': 'false', 'location': kwargs.get("cluster_urn"), 'osOptions': self._combine_os_options(**kwargs), 'protocol': "nfs", 'vmConfig': self._combine_vmConfig_4_import(**kwargs), 'url': kwargs.get('image_location'), 'isTemplate': template } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end import_vm_from_nfs()")) return body.get('urn') def create_volume_from_extend(self, **kwargs): '''create_volume_from_extend create_linkclone_volume :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start create_volume_from_extend()")) image_type = kwargs.get('image_type') if image_type == "nfs": LOG.info(_("[VRM-CINDER] start create_volume_from_nfs")) vm_urn = self.import_vm_from_nfs(**kwargs) elif image_type == 'uds': LOG.info(_("[VRM-CINDER] start create_volume_from_uds")) vm_urn = self.import_vm_from_uds(**kwargs) else: LOG.info(_("[VRM-CINDER] start create_volume_from_glance")) vm_urn = self.import_vm_from_glance(**kwargs) vm_id = vm_urn[-10:] vm = self.query_vm(vm_id=vm_id) vm_config = vm['vmConfig'] disks = vm_config['disks'] volume_urn = None if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 for disk in disks: if int(disk['sequenceNum']) == int(kwargs['volume_sequence_num']): volume_urn = disk['volumeUrn'] break if volume_urn is None: msg = (_("[VRM-CINDER] no available disk")) LOG.error(msg) self.delete_vm(vm_id=vm_id) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) try: self.detach_vol_from_vm(vm_id=vm_id, volume_urn=volume_urn) except Exception as ex: LOG.error(_('detach volume is failed')) self.delete_vm(vm_id=vm_id) raise ex self.delete_vm(vm_id=vm_id) LOG.info(_("[VRM-CINDER] end ()")) return volume_urn def check_template_status(self, vm_id): LOG.info(_("[VRM-CINDER] start check template status()")) uri = self.site_uri + '/vms/' + vm_id + '/competition' method = 'GET' new_url = self._generate_url(uri) resp, body = self.vrmhttpclient.request(new_url, method) LOG.info(_("[VRM-CINDER] template info %s") % body) body.get('status') def check_template(self, **kwargs): '''check_template :param kwargs: :return: ''' template_id = kwargs.get('template_id') vm_name = kwargs.get('vm_name') templates = self.get_templates() id = None for template in templates: if template_id is not None: urn = template.get('urn') id = urn[-10:] if id == template_id: LOG.info(_("[VRM-CINDER] template exists [%s]"), template_id) return id if vm_name is not None: name = template.get('name') if name == vm_name: urn = template.get('urn') id = urn[-10:] LOG.info(_("[VRM-CINDER] vm is exists [%s]"), vm_name) return id return id def create_volume_from_template(self, **kwargs): '''create_volume_from_template create_linkclone_volume :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start create_volume_from_template()")) template = kwargs['image_location'] kwargs['template_id'] = template[-10:] is_exist = self.check_template(**kwargs) if is_exist is None: msg = (_("[VRM-CINDER] no such template %s "), kwargs.get('template_id')) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) while True: template_vm = self.query_vm(vm_id=kwargs['template_id']) LOG.info(_("[VRM-CINDER] template_vm status is %s"), template_vm.get('status')) if 'creating' == template_vm.get('status'): sleep(10) elif 'stopped' == template_vm.get('status'): break else: msg = (_("[VRM-CINDER] template isn't available %s "), kwargs.get('template_id')) LOG.error(msg) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) vm_config = template_vm['vmConfig'] template_disks = vm_config['disks'] if len(template_disks) != 1: msg = _("template must have one disk") LOG.error(msg) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) vm_urn = self.clone_vm(**kwargs) vm_id = vm_urn[-10:] vm = self.query_vm(vm_id=vm_id) vm_config = vm['vmConfig'] disks = vm_config['disks'] volume_urn = None if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 for disk in disks: if int(disk['sequenceNum']) == int(kwargs['volume_sequence_num']): volume_urn = disk['volumeUrn'] break if volume_urn is None: msg = (_("[VRM-CINDER] no available disk")) LOG.error(msg) self.delete_vm(vm_id=vm_id) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) try: self.delete_vm(vm_id=vm_id, isReserveDisks=1) except Exception as ex: LOG.error(_("delete vm(reserveDisk) is failed ")) self.delete_vm(vm_id=vm_id) raise ex LOG.info(_("[VRM-CINDER] end ()")) return volume_urn def create_linkclone_from_template(self, **kwargs): '''create_linkclone_from_template create_linkclone_volume :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start create_linkclone_from_template()")) kwargs['linked_clone'] = True return self.create_volume_from_template(**kwargs) def create_linkClone_from_extend(self, **kwargs): '''create_linkClone_from_extend :param kwargs: :return: ''' LOG.debug(_("[VRM-CINDER] start create_linkClone_volume()")) vrm_template_lock.acquire() try: kwargs['linkClone'] = True vm_name = 'cinder-vm-' + kwargs.get('image_id') LOG.info(_("[VRM-CINDER] vm_name is %s"), vm_name) kwargs['vm_name'] = vm_name vm_id = self.check_template(**kwargs) kwargs.pop('vm_name') LOG.info(_("[VRM-CINDER] vm_id is %s"), vm_id) image_type = kwargs.get('image_type') if kwargs.get('volume_sequence_num') is None: kwargs['volume_sequence_num'] = 1 if 1 < int(kwargs['volume_sequence_num']): msg = (_("[VRM-CINDER] volume_sequence_num is %s "), kwargs['volume_sequence_num']) LOG.error(msg) raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg) if vm_id is None: kwargs["is_template"] = True if image_type == 'nfs': vm_urn = self.import_vm_from_nfs(**kwargs) kwargs.pop('linkClone') LOG.info(_("[VRM-CINDER] import_vm_from_nfs vm_urn is %s"), vm_urn) vm_id = vm_urn[-10:] kwargs['image_location'] = vm_id elif image_type == 'uds': vm_urn = self.import_vm_from_uds(**kwargs) kwargs.pop('linkClone') LOG.info(_("[VRM-CINDER] import_vm_from_uds vm_urn is %s"), vm_urn) vm_id = vm_urn[-10:] kwargs['image_location'] = vm_id else: vm_urn = self.import_vm_from_glance(**kwargs) kwargs.pop('linkClone') LOG.info( _("[VRM-CINDER] import_vm_from_glance vm_urn is %s"), vm_urn) vm_id = vm_urn[-10:] kwargs['image_location'] = vm_id else: kwargs.pop('linkClone') kwargs['image_location'] = vm_id except Exception as ex: vrm_template_lock.release() raise ex vrm_template_lock.release() return self.create_linkclone_from_template(**kwargs) def get_templates(self, **kwargs): '''get_templates 'list_templates': ('GET', ('/vms', None, None, None), {'limit': kwargs.get('limit'), 'offset': kwargs.get('offset'), 'scope': kwargs.get('scope'), 'isTemplate': 'true' }, {}, False), ''' LOG.info(_("[VRM-CINDER] start _get_templates()")) uri = '/vms' method = 'GET' path = self.site_uri + uri offset = 0 templates = [] while True: parames = { 'limit': self.limit, 'offset': offset, 'scope': kwargs.get('scope'), 'isTemplate': 'true' } appendix = self._joined_params(parames) new_url = self._generate_url(path, appendix) resp, body = self.vrmhttpclient.request(new_url, method) total = int(body.get('total') or 0) if total > 0: res = body.get('vms') templates += res offset += len(res) if offset >= total or len(templates) >= total or len( res) < self.limit: break else: break LOG.info(_("[VRM-CINDER] end ()")) return templates def create_vm(self, **kwargs): '''Create Vm :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start create_vm()")) uri = '/vms' method = 'POST' path = self.site_uri + uri new_url = self._generate_url(path) body = { 'name': 'cinder-driver-temp-' + kwargs.get('volume_id'), 'group': 'FSP', 'description': 'cinder-driver-temp-vm', 'autoBoot': 'false', 'location': kwargs.get("cluster_urn"), 'vmConfig': self._combine_empty_vmConfig(**kwargs), 'osOptions': self._combine_os_options(**kwargs) } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end create_vm()")) return body def export_vm_to_glance(self, **kwargs): '''export_vm_to_glance :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start export_vm_to_glance")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/export' new_url = self._generate_url(path) if CONF.glance_host is None or str(CONF.glance_port) is None \ or FC_DRIVER_CONF.glance_server_ip is None: raise exception.ParameterNotFound(param='glance_host or ' 'glance_port or glance_ip') endpoint = CONF.glance_host + ":" + str(CONF.glance_port) token = kwargs.get('auth_token') serviceIp = FC_DRIVER_CONF.glance_server_ip format = 'xml' if FC_DRIVER_CONF.export_version == 'v1.2' else 'ovf' body = { 'name': kwargs.get('image_id'), 'format': format, 'protocol': 'glance', 'isOverwrite': 'false', 'vmConfig': self._combine_vmConfig_4_export(**kwargs), 'glanceConfig': { 'imageID': kwargs.get('image_id'), 'endPoint': endpoint, 'serverIp': serviceIp, 'token': token} } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end export_vm_to_glance")) return body.get('urn') def export_vm_to_uds(self, **kwargs): '''export_vm_to_uds :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start export_vm_to_uds")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/export' new_url = self._generate_url(path) if FC_DRIVER_CONF.s3_store_access_key_for_cinder is None \ or FC_DRIVER_CONF.s3_store_secret_key_for_cinder is None \ or FC_DRIVER_CONF.uds_port is None or FC_DRIVER_CONF.uds_ip \ is None \ or FC_DRIVER_CONF.uds_bucket_name is None: LOG.error(_("[VRM-CINDER] some params is None, please check: " "s3_store_access_key_for_cinder, " "s3_store_secret_key_for_cinder, uds_port, uds_ip, " "uds_bucket_name")) raise exception.ParameterNotFound( param='s3_store_access_key_for_cinder ' 'or s3_store_secret_key_for_cinder or' 'uds_port or uds_serverIp or uds_bucket_name') uds_name = FC_DRIVER_CONF.s3_store_access_key_for_cinder uds_password = FC_DRIVER_CONF.s3_store_secret_key_for_cinder port = FC_DRIVER_CONF.uds_port serverIp = FC_DRIVER_CONF.uds_ip bucketName = FC_DRIVER_CONF.uds_bucket_name key = kwargs.get('image_id') bucket_type = FC_DRIVER_CONF.uds_bucket_type if bucket_type is not None: if str(bucket_type) == 'wildcard': if kwargs.get('project_id') is None: LOG.error(_("project_id is none ")) raise exception.ParameterNotFound( param='project_id is none') else: bucketName += kwargs.get('project_id') LOG.info(_("[VRM-CINDER] bucketName is %s"), bucketName) format = 'xml' if FC_DRIVER_CONF.export_version == 'v1.2' else 'ovf' body = { 'name': kwargs.get('image_id'), 'format': format, 'protocol': 'uds', 'isOverwrite': 'false', 'vmConfig': self._combine_vmConfig_4_export(**kwargs), 's3Config': { 'serverIp': serverIp, 'port': port, 'accessKey': uds_name, 'secretKey': uds_password, 'bucketName': bucketName, 'key': key} } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end export_vm_to_uds")) return body.get('urn') def export_vm_to_nfs(self, **kwargs): '''export_vm_to_nfs Post //action/export HTTP/1.1 Host: https://: Content-Type: application/json; charset=UTF-8 Accept: application/json;version=; charset=UTF-8 X-Auth-Token: { "name":string, "url:string, "username":administrator "password":string } ''' LOG.info(_("[VRM-CINDER] start export_vm_to_nfs()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/export' new_url = self._generate_url(path) format = 'xml' if FC_DRIVER_CONF.export_version == 'v1.2' else 'ovf' body = { 'name': kwargs.get('image_id'), 'url': kwargs.get('image_url') + '/' + kwargs.get('image_id'), 'vmConfig': self._combine_vmConfig_4_export(**kwargs), 'format': format, 'protocol': 'nfs', 'isOverwrite': 'false' } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end export_vm_to_nfs()")) return body.get('urn') def get_volume_sequence_num(self, vm_body, volume_urn): volume_sequence_num = 1 if vm_body is not None: vm_uri = vm_body.get('uri') volume_body = self.query_vm(vm_id=vm_uri[-10:]) if volume_body is not None: for item in volume_body.get('vmConfig').get('disks'): if item.get('volumeUrn') == volume_urn: volume_sequence_num = item.get("sequenceNum") else: LOG.info(_("[VRM-CINDER] vm_body is null)")) return volume_sequence_num def export_volume_to_image(self, **kwargs): '''export_volume_to_image :param kwargs: :return: ''' LOG.info(_("[VRM-CINDER] start export_volume_to_image()")) vm_body = self.query_vm_volume(**kwargs) if vm_body is not None: kwargs['volume_sequence_num'] = self.get_volume_sequence_num( vm_body, kwargs.get('volume_urn')) vm_uri = vm_body.get('uri') kwargs['vm_id'] = vm_uri[-10:] LOG.info(_("[VRM-CINDER] volume is already attached")) self.export_attached_volume_to_image(**kwargs) LOG.info(_("[VRM-CINDER] volume_sequence_num %s"), kwargs['volume_sequence_num']) return kwargs['volume_sequence_num'] vm_body = self.create_vm(**kwargs) vm_uri = vm_body.get('uri') kwargs['vm_id'] = vm_uri[-10:] if kwargs.get('shareable') == 'share': kwargs['volume_sequence_num'] = 2 else: kwargs['volume_sequence_num'] = 1 try: self.attach_vol_to_vm(**kwargs) except Exception as ex: LOG.error(_("[VRM-CINDER] attach volume is error ")) self.delete_vm(**kwargs) raise ex try: self.export_attached_volume_to_image(**kwargs) except Exception as ex: LOG.error(_("[VRM-CINDER] export vm is error ")) self.detach_vol_from_vm(**kwargs) self.delete_vm(**kwargs) raise ex self.detach_vol_from_vm(**kwargs) self.delete_vm(**kwargs) LOG.info(_("[VRM-CINDER] end export_volume_to_nfs()")) LOG.info(_("[VRM-CINDER] volume_sequence_num %s"), kwargs['volume_sequence_num']) return kwargs['volume_sequence_num'] def export_attached_volume_to_image(self, **kwargs): image_type = kwargs.get('image_type') if image_type == 'nfs': LOG.info(_('[VRM-CINDER] export_vm_to_nfs')) self.export_vm_to_nfs(**kwargs) elif image_type == 'uds': LOG.info(_('VRM-CINDER] export_vm_to_uds')) self.export_vm_to_uds(**kwargs) else: LOG.info(_('VRM-CINDER] export_vm_to_glance')) self.export_vm_to_glance(**kwargs) LOG.info(_("[VRM-CINDER] end export_attached_volume_to_image()")) def query_vm_volume(self, **kwargs): '''query_vm_volume URL:https://192.168.106.111:8443/OmsPortal/service/sites/4286080F/vms ?scope=urn%3Asites%3A4286080F%3Avolumes%3A137 &detail=2 ''' LOG.info(_("[VRM-CINDER] start query_vm_volume()")) uri = '/vms' method = 'GET' path = self.site_uri + uri parames = { 'scope': kwargs.get('volume_urn'), 'detail': 0 } appendix = self._joined_params(parames) new_url = self._generate_url(path, appendix) resp, body = self.vrmhttpclient.request(new_url, method) total = int(body.get('total') or 0) vm = None if total >= 1: vms = body.get('vms') vm = vms[0] else: LOG.info(_("[VRM-CINDER] find no vms()")) LOG.info(_("[VRM-CINDER] end query_vm_volume()")) return vm def migrate_vm_volume(self, **kwargs): '''migrate_vm_volume Post ///action/migratevol HTTP/1.1 Host: https://: Content-Type: application/json; charset=UTF-8 Accept: application/json;version=; charset=UTF-8 X-Auth-Token: { "disks":[ { "volumeUrn":string "datastoreUrn":string //urn:sites:1:datastores:1 } ], "speed": integer } ''' LOG.info(_("[VRM-CINDER] start migrate_vm_volume()")) uri = '/vms' method = 'POST' path = self.site_uri + uri + '/' + kwargs.get( 'vm_id') + '/action/migratevol' new_url = self._generate_url(path) body = { "disks": [ { "volumeUrn": kwargs.get('volume_urn'), "datastoreUrn": kwargs.get('dest_ds_urn'), 'migrateType': kwargs.get('migrate_type') } ], "speed": kwargs.get('speed') } resp, body = self.vrmhttpclient.request(new_url, method, body=json.dumps(body)) task_uri = body.get('taskUri') self.task_proxy.wait_task(task_uri=task_uri) LOG.info(_("[VRM-CINDER] end migrate_vm_volume()")) return body.get('urn')