<filename>volume/drivers/huawei/vrm/vm_proxy.py
# vim: tabstop=4 shiftwidth=4 softtabstop=4

"""
[VRM DRIVER] VRM CLIENT.

"""
import json

from oslo.config import cfg
from cinder import exception
from cinder.openstack.common import log as logging
from cinder.openstack.common.gettextutils import _
from cinder.volume.drivers.huawei.vrm.base_proxy import BaseProxy
from cinder.volume.drivers.huawei.vrm.task_proxy import TaskProxy
from cinder.volume.drivers.huawei.vrm.conf import FC_DRIVER_CONF
from FSComponentUtil import crypt


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


class VmProxy(BaseProxy):
    '''
    VmProxy
    '''
    def __init__(self, *args, **kwargs):
        super(VmProxy, self).__init__()
        self.task_proxy = TaskProxy()


    def query_vm(self, **kwargs):
        '''
        'query_vm': ('GET',
                     ('/vms', None, kwargs.get('vm_id'), None),
                     {},
                     {},
                     False)
        '''
        LOG.debug(_("[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.debug(_("[VRM-CINDER] end ()"))
        return body

    def query_vm_by_uri(self, **kwargs):
        '''
        'query_vm': ('GET',
                     ('/vms', None, kwargs.get('vm_id'), None),
                     {},
                     {},
                     False)
        '''
        LOG.debug(_("[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.debug(_("[VRM-CINDER] end ()"))
        return body

    def delete_vm(self, **kwargs):
        '''
                'delete_vm': ('DELETE',
                              ('/vms', None, kwargs.get('vm_id'), None),
                              {},
                              {},
                              True),
        '''
        LOG.debug(_("[VRM-CINDER] start delete_vm()"))
        uri = '/vms'
        method = 'DELETE'
        path = self.site_uri + uri + '/' + kwargs.get('vm_id')
        new_url = self._generate_url(path)
        resp, body = self.vrmhttpclient.request(new_url, method)
        task_urn_ = body.get('taskUrn')
        task_uri = body.get('taskUri')
        self.task_proxy.wait_task(task_uri=task_uri)
        LOG.debug(_("[VRM-CINDER] end ()"))

    def detach_vol_from_vm(self, **kwargs):
        '''
                'detach_vol_from_vm': ('POST',
                                       ('/vms', None, kwargs.get('vm_id'), 'action/detachvol'),
                                       {},
                                       {'volUrn': kwargs.get('volUrn')},
                                       True),
        '''
        LOG.debug(_("[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_urn_ = body.get('taskUrn')
        task_uri = body.get('taskUri')
        self.task_proxy.wait_task(task_uri=task_uri)
        LOG.debug(_("[VRM-CINDER] end ()"))

    def attach_vol_to_vm(self, **kwargs):
        '''
                'attach_vol_to_vm': ('POST',
                                       ('/vms', None, kwargs.get('vm_id'), 'action/attachvol'),
                                       {},
                                       {'volUrn': kwargs.get('volUrn')},
                                       True),
        '''
        LOG.debug(_("[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_urn_ = body.get('taskUrn')
        task_uri = body.get('taskUri')
        self.task_proxy.wait_task(task_uri=task_uri)
        LOG.debug(_("[VRM-CINDER] end attach_vol_to_vm()"))


    def stop_vm(self, **kwargs):
        '''
                'stop_vm': ('POST',
                            ('/vms', None, kwargs.get('vm_id'), 'action/stop'),
                            {},
                            {'mode': kwargs.get('mode')},
                            True),
        '''
        LOG.debug(_("[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_urn_ = body.get('taskUrn')
        task_uri = body.get('taskUri')
        self.task_proxy.wait_task(task_uri=task_uri)
        LOG.debug(_("[VRM-CINDER] end ()"))

    def _combine_empty_vmConfig(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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.debug(_("[VRM-CINDER] _combine_empty_vmConfig end ()"))
        return vmConfigBody

    def _combine_vmConfig_4_import(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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')
        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.debug(_("[VRM-CINDER] end ()"))
        return vmConfigBody

    def _combine_vmConfig_4_clone(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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')
        volumeUrn = kwargs.get('volume_urn')
        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.debug(_("[VRM-CINDER] end ()"))
        return vmConfigBody

    def _combine_vmConfig_4_export(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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')
        volumeUrn = kwargs.get('volume_urn')
        cpu = {'quantity': cpu_quantity}
        memory = {'quantityMB': mem_quantityMB}
        disks = [
            {
                'sequenceNum': kwargs.get('volume_sequence_num'),
            }
        ]
        vmConfigBody = {
            'cpu': cpu,
            'memory': memory,
            'disks': disks,
        }
        LOG.debug(_("[VRM-CINDER] end ()"))
        return vmConfigBody

    def _combine_os_options(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        osOptions = {
            'osType': 'Windows',
            'osVersion': 26
        }
        LOG.debug(_("[VRM-CINDER] end ()"))
        return osOptions

    def clone_vm(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''

        LOG.debug(_("[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.debug(_("[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)
        LOG.debug(_("[VRM-CINDER] end clone_vm()"))
        return body.get('urn')

    def import_vm_from_glance(self, **kwargs):
        '''
        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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:
            template = 'false'
        else:
            template = 'true'

        if CONF.glance_host is None or str(CONF.glance_port) is None \
                or FC_DRIVER_CONF.glance_server_ip is None:
            LOG.error(_("[VRM-CINDER] params is None,"
                        "glance_host: %s; glance_port: %s; glance_ip: %s"),
                      CONF.glance_host, str(CONF.glance_port),
                      FC_DRIVER_CONF.glance_server_ip)
            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
        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.debug(_("[VRM-CINDER] end import_vm_from_glance()"))
        return body.get('urn')


    def import_vm_from_uds(self, **kwargs):
        '''
        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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:
            template = 'false'
        else:
            template = 'true'

        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.debug(_("[VRM-CINDER] end import_vm_from_uds()"))
        return body.get('urn')

    def import_vm_from_nfs(self, **kwargs):
        '''
            '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.debug(_("[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:
            template = 'false'
        else:
            template = 'true'

        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.debug(_("[VRM-CINDER] end import_vm_from_nfs()"))
        return body.get('urn')



    def create_volume_from_extend(self, **kwargs):
        '''
        create_linkclone_volume

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[VRM-CINDER] start create_volume_from_extend()"))
        image_type = kwargs.get('image_type')

        if image_type == "nfs":
            LOG.debug(_("[VRM-CINDER] start create_volume_from_nfs"))
            vm_urn = self.import_vm_from_nfs(**kwargs)
        elif image_type == 'uds':
            LOG.debug(_("[VRM-CINDER] start create_volume_from_uds"))
            vm_urn = self.import_vm_from_uds(**kwargs)
        else:
            LOG.debug(_("[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.debug(_("[VRM-CINDER] end ()"))
        return volume_urn

    def check_template_status(self,vm_id):
        LOG.debug(_("[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.debug(_("[VRM-CINDER] template info %s")%body)
        body.get('status')


    def check_template(self, **kwargs):
        '''

        :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.debug(_("[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.debug(_("[VRM-CINDER] vm is exists [%s]"), vm_name)
                    return id
        return id



    def create_volume_from_template(self, **kwargs):
        '''
        create_linkclone_volume

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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'))
            LOG.error(msg)
            raise exception.ImageUnacceptable(image_id=kwargs['image_id'], reason=msg)

        while True:
            template_vm = self.query_vm(vm_id=kwargs['template_id'])
            LOG.debug(_("[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.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.debug(_("[VRM-CINDER] end ()"))
        return volume_urn

    def create_linkclone_from_template(self, **kwargs):
        '''
        create_linkclone_volume

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[VRM-CINDER] start create_linkClone_volume()"))
        kwargs['linkClone'] = True
        vm_name = 'cinder-vm-' + kwargs.get('image_id')
        LOG.debug(_("[VRM-CINDER] vm_name is %s"), vm_name)
        kwargs['vm_name'] = vm_name
        vm_id = self.check_template(**kwargs)
        kwargs.pop('vm_name')
        LOG.debug(_("[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.debug(_("[VRM-CINDER] import_vm_from_nfs vm_urn is %s"), vm_urn)
                vm_id = vm_urn[-10:]
                kwargs['image_location'] = vm_id
                return self.create_linkclone_from_template(**kwargs)
            elif image_type == 'uds':
                vm_urn = self.import_vm_from_uds(**kwargs)
                kwargs.pop('linkClone')
                LOG.debug(_("[VRM-CINDER] import_vm_from_uds vm_urn is %s"), vm_urn)
                vm_id = vm_urn[-10:]
                kwargs['image_location'] = vm_id
                return self.create_linkclone_from_template(**kwargs)
            else:
                vm_urn = self.import_vm_from_glance(**kwargs)
                kwargs.pop('linkClone')
                LOG.debug(_("[VRM-CINDER] import_vm_from_glance vm_urn is %s"), vm_urn)
                vm_id = vm_urn[-10:]
                kwargs['image_location'] = vm_id
                return self.create_linkclone_from_template(**kwargs)
        else:
            kwargs.pop('linkClone')
            kwargs['image_location'] = vm_id
            return self.create_linkclone_from_template(**kwargs)


    def _get_templates(self, **kwargs):
        '''
        'list_templates': ('GET',
                   ('/vms', None, None, None),
                   {'limit': kwargs.get('limit'),
                    'offset': kwargs.get('offset'),
                    'scope': kwargs.get('scope'),
                    'isTemplate': 'true'
                   },
                   {},
                   False),
        '''

        LOG.debug(_("[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.debug(_("[VRM-CINDER] end ()"))
        return templates

    def create_vm(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''

        LOG.debug(_("[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.debug(_("[VRM-CINDER] end create_vm()"))
        return body

    def export_vm_to_glance(self, **kwargs):
        '''
        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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:
            LOG.error(_("[VRM-CINDER] params is None,"
                        "glance_host: %s; glance_port: %s; glance_ip: %s"),
                      CONF.glance_host, str(CONF.glance_port),
                      FC_DRIVER_CONF.glance_server_ip)
            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.debug(_("[VRM-CINDER] end export_vm_to_glance"))
        return body.get('urn')

    def export_vm_to_uds(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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')

        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.debug(_("[VRM-CINDER] end export_vm_to_uds"))
        return body.get('urn')



    def export_vm_to_nfs(self, **kwargs):
        '''
            Post <vm_uri>/<id>/action/export HTTP/1.1
            Host: https://<ip>:<port>
            Content-Type: application/json; charset=UTF-8
            Accept: application/json;version=<version>; charset=UTF-8
            X-Auth-Token: <<PASSWORD>_TOKEN>
            {
            "name":string,
            "url:string,
            "username":administrator
            "password":<PASSWORD>
            }
        '''

        LOG.debug(_("[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.debug(_("[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.debug(_("[VRM-CINDER] vm_body is null)"))
        return volume_sequence_num

    def export_volume_to_image(self, **kwargs):
        '''

        :param kwargs:
        :return:
        '''
        LOG.debug(_("[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.debug(_("[VRM-CINDER] volume is already attached"))
            self.export_attached_volume_to_image(**kwargs)
            LOG.debug(_("[VRM-CINDER] volume_sequence_num %s"), kwargs['volume_sequence_num'])
            return kwargs['volume_sequence_num']

        vm_body = self.create_vm(**kwargs)
        vm_urn = vm_body.get('urn')
        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.debug(_("[VRM-CINDER] end export_volume_to_nfs()"))
        LOG.debug(_("[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.debug(_('[VRM-CINDER]  export_vm_to_nfs'))
            self.export_vm_to_nfs(**kwargs)
        elif image_type == 'uds':
            LOG.debug(_('VRM-CINDER]  export_vm_to_uds'))
            self.export_vm_to_uds(**kwargs)
        else:
            LOG.debug(_('VRM-CINDER]  export_vm_to_glance'))
            self.export_vm_to_glance(**kwargs)

        LOG.debug(_("[VRM-CINDER] end export_attached_volume_to_image()"))

    def query_vm_volume(self, **kwargs):
        '''
            URL:https://192.168.106.111:8443/OmsPortal/service/sites/4286080F/vms
            ?scope=urn%3Asites%3A4286080F%3Avolumes%3A137
            &detail=2
        '''

        LOG.debug(_("[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.debug(_("[VRM-CINDER] find no vms()"))
        LOG.debug(_("[VRM-CINDER] end query_vm_volume()"))
        return vm


    def migrate_vm_volume(self, **kwargs):
        '''
            Post /<vm_uri>/<vm_id>/action/migratevol HTTP/1.1
            Host: https://<ip>:<port>
            Content-Type: application/json; charset=UTF-8
            Accept: application/json;version=<version>; charset=UTF-8
            X-Auth-Token: <<PASSWORD>en_TOKEN>
            {
            "disks":[
            {
            "volumeUrn":string
            "datastoreUrn":string //urn:sites:1:datastores:1
            }
            ],
            "speed": integer
            }
        '''

        LOG.debug(_("[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.debug(_("[VRM-CINDER] end migrate_vm_volume()"))
        return body.get('urn')
