Beispiel #1
0
 def vpsa_send_cmd(self, cmd, **kwargs):
     try:
         response = self.vpsa.send_cmd(cmd, **kwargs)
     except common.exception.UnknownCmd as e:
         raise cinder_exception.UnknownCmd(cmd=e.cmd)
     except common.exception.SessionRequestException as e:
         raise zadara_exception.ZadaraSessionRequestException(msg=e.msg)
     except common.exception.BadHTTPResponseStatus as e:
         raise cinder_exception.BadHTTPResponseStatus(status=e.status)
     except common.exception.FailedCmdWithDump as e:
         raise cinder_exception.FailedCmdWithDump(status=e.status,
                                                  data=e.data)
     except common.exception.ZadaraInvalidAccessKey:
         raise zadara_exception.ZadaraCinderInvalidAccessKey()
     return response
Beispiel #2
0
    def _generate_vpsa_cmd(self, cmd, **kwargs):
        """Generate command to be sent to VPSA."""
        def _joined_params(params):
            param_str = []
            for k, v in params.items():
                param_str.append("%s=%s" % (k, v))
            return '&'.join(param_str)

        # Dictionary of applicable VPSA commands in the following format:
        # 'command': (method, API_URL, {optional parameters})
        vpsa_commands = {
            'login': ('POST', '/api/users/login.xml', {
                'user': self.conf.zadara_user,
                'password': self.conf.zadara_password
            }),

            # Volume operations
            'create_volume': ('POST', '/api/volumes.xml', {
                'name':
                kwargs.get('name'),
                'capacity':
                kwargs.get('size'),
                'pool':
                self.conf.zadara_vpsa_poolname,
                'thin':
                'YES',
                'crypt':
                'YES' if self.conf.zadara_vol_encrypt else 'NO',
                'attachpolicies':
                'NO' if not self.conf.zadara_default_snap_policy else 'YES'
            }),
            'delete_volume':
            ('DELETE', '/api/volumes/%s.xml' % kwargs.get('vpsa_vol'), {
                'force': 'YES'
            }),
            'expand_volume':
            ('POST', '/api/volumes/%s/expand.xml' % kwargs.get('vpsa_vol'), {
                'capacity': kwargs.get('size')
            }),

            # Snapshot operations
            # Snapshot request is triggered for a single volume though the
            # API call implies that snapshot is triggered for CG (legacy API).
            'create_snapshot':
            ('POST', '/api/consistency_groups/%s/snapshots.xml' %
             kwargs.get('cg_name'), {
                 'display_name': kwargs.get('snap_name')
             }),
            'delete_snapshot':
            ('DELETE', '/api/snapshots/%s.xml' % kwargs.get('snap_id'), {}),
            'create_clone_from_snap':
            ('POST',
             '/api/consistency_groups/%s/clone.xml' % kwargs.get('cg_name'), {
                 'name': kwargs.get('name'),
                 'snapshot': kwargs.get('snap_id')
             }),
            'create_clone':
            ('POST',
             '/api/consistency_groups/%s/clone.xml' % kwargs.get('cg_name'), {
                 'name': kwargs.get('name')
             }),

            # Server operations
            'create_server': ('POST', '/api/servers.xml', {
                'display_name': kwargs.get('initiator'),
                'iqn': kwargs.get('initiator')
            }),

            # Attach/Detach operations
            'attach_volume':
            ('POST', '/api/servers/%s/volumes.xml' % kwargs.get('vpsa_srv'), {
                'volume_name[]': kwargs.get('vpsa_vol'),
                'force': 'NO'
            }),
            'detach_volume':
            ('POST', '/api/volumes/%s/detach.xml' % kwargs.get('vpsa_vol'), {
                'server_name[]': kwargs.get('vpsa_srv'),
                'force': 'NO'
            }),

            # Get operations
            'list_volumes': ('GET', '/api/volumes.xml', {}),
            'list_pools': ('GET', '/api/pools.xml', {}),
            'list_controllers': ('GET', '/api/vcontrollers.xml', {}),
            'list_servers': ('GET', '/api/servers.xml', {}),
            'list_vol_attachments': ('GET', '/api/volumes/%s/servers.xml' %
                                     kwargs.get('vpsa_vol'), {}),
            'list_vol_snapshots': ('GET',
                                   '/api/consistency_groups/%s/snapshots.xml' %
                                   kwargs.get('cg_name'), {})
        }

        if cmd not in vpsa_commands:
            raise exception.UnknownCmd(cmd=cmd)
        else:
            (method, url, params) = vpsa_commands[cmd]

        if method == 'GET':
            # For GET commands add parameters to the URL
            params.update(
                dict(access_key=self.access_key, page=1, start=0, limit=0))
            url += '?' + _joined_params(params)
            body = ''

        elif method == 'DELETE':
            # For DELETE commands add parameters to the URL
            params.update(dict(access_key=self.access_key))
            url += '?' + _joined_params(params)
            body = ''

        elif method == 'POST':
            if self.access_key:
                params.update(dict(access_key=self.access_key))
            body = _joined_params(params)

        else:
            msg = (_('Method %(method)s is not defined') % {'method': method})
            LOG.error(msg)
            raise AssertionError(msg)

        return (method, url, body)
Beispiel #3
0
    def submit(self,
               rel_url,
               method='GET',
               params=None,
               user_id=None,
               project_id=None,
               req_id=None,
               action=None,
               **kwargs):
        """Submit a request to the configured API endpoint."""

        cfg = self._get_api_cfg()
        if cfg is None:
            msg = _("Failed to determine blockbridge API configuration")
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)

        # alter the url appropriately if an action is requested
        if action:
            rel_url += "/actions/%s" % action

        headers = cfg['default_headers'].copy()
        url = cfg['base_url'] + rel_url
        body = None

        # include user, project and req-id, if supplied
        tsk_ctx = []
        if user_id and project_id:
            tsk_ctx.append("ext_auth=keystone/%s/%s" % (project_id, user_id))
        if req_id:
            tsk_ctx.append("id=%s", req_id)

        if tsk_ctx:
            headers['X-Blockbridge-Task'] = ','.join(tsk_ctx)

        # encode params based on request method
        if method in ['GET', 'DELETE']:
            # For GET method add parameters to the URL
            if params:
                url += '?' + urllib.parse.urlencode(params)
        elif method in ['POST', 'PUT', 'PATCH']:
            body = jsonutils.dumps(params)
            headers['Content-Type'] = 'application/json'
        else:
            raise exception.UnknownCmd(cmd=method)

        # connect and execute the request
        connection = http_client.HTTPSConnection(cfg['host'], cfg['port'])
        connection.request(method, url, body, headers)
        response = connection.getresponse()

        # read response data
        rsp_body = response.read()
        rsp_data = jsonutils.loads(rsp_body)

        connection.close()

        code = response.status
        if code in [200, 201, 202, 204]:
            pass
        elif code == 401:
            raise exception.NotAuthorized(_("Invalid credentials"))
        elif code == 403:
            raise exception.NotAuthorized(_("Insufficient privileges"))
        else:
            raise exception.VolumeBackendAPIException(data=rsp_data['message'])

        return rsp_data
Beispiel #4
0
    def _generate_vpsa_cmd(self, cmd, **kwargs):
        """Generate command to be sent to VPSA."""

        def _joined_params(params):
            param_str = []
            for k, v in params.items():
                param_str.append("%s=%s" % (k, v))
            return '&'.join(param_str)

        # Dictionary of applicable VPSA commands in the following format:
        # 'command': (method, API_URL, {optional parameters})
        vpsa_commands = {
            'login': ('POST',
                      '/api/users/login.xml',
                      {'user': self.user,
                       'password': self.password}),

            # Volume operations
            'create_volume': ('POST',
                              '/api/volumes.xml',
                              {'display_name': kwargs.get('name'),
                               'virtual_capacity': kwargs.get('size'),
                               'raid_group_name[]': FLAGS.zadara_vpsa_poolname,
                               'quantity': 1,
                               'cache': FLAGS.zadara_default_cache_policy,
                               'crypt': FLAGS.zadara_default_encryption,
                               'mode': FLAGS.zadara_default_striping_mode,
                               'stripesize': FLAGS.zadara_default_stripesize,
                               'force': 'NO'}),
            'delete_volume': ('DELETE',
                              '/api/volumes/%s.xml' % kwargs.get('vpsa_vol'),
                              {}),

            # Server operations
            'create_server': ('POST',
                              '/api/servers.xml',
                              {'display_name': kwargs.get('initiator'),
                               'iqn': kwargs.get('initiator')}),

            # Attach/Detach operations
            'attach_volume': ('POST',
                              '/api/servers/%s/volumes.xml'
                              % kwargs.get('vpsa_srv'),
                              {'volume_name[]': kwargs.get('vpsa_vol'),
                               'force': 'NO'}),
            'detach_volume': ('POST',
                              '/api/volumes/%s/detach.xml'
                              % kwargs.get('vpsa_vol'),
                              {'server_name[]': kwargs.get('vpsa_srv'),
                               'force': 'NO'}),

            # Get operations
            'list_volumes': ('GET',
                             '/api/volumes.xml',
                             {}),
            'list_controllers': ('GET',
                                 '/api/vcontrollers.xml',
                                 {}),
            'list_servers': ('GET',
                             '/api/servers.xml',
                             {}),
            'list_vol_attachments': ('GET',
                                     '/api/volumes/%s/servers.xml'
                                     % kwargs.get('vpsa_vol'),
                                     {}), }

        if cmd not in vpsa_commands.keys():
            raise exception.UnknownCmd(cmd=cmd)
        else:
            (method, url, params) = vpsa_commands[cmd]

        if method == 'GET':
            # For GET commands add parameters to the URL
            params.update(dict(access_key=self.access_key,
                               page=1, start=0, limit=0))
            url += '?' + _joined_params(params)
            body = ''

        elif method == 'DELETE':
            # For DELETE commands add parameters to the URL
            params.update(dict(access_key=self.access_key))
            url += '?' + _joined_params(params)
            body = ''

        elif method == 'POST':
            if self.access_key:
                params.update(dict(access_key=self.access_key))
            body = _joined_params(params)

        else:
            raise exception.UnknownCmd(cmd=method)

        return (method, url, body)
Beispiel #5
0
    def generate_vrm_cmd(self, cmd, **kwargs):
        cpu = {'quantity': 1}
        memory = {'quantityMB': 1024}
        disks = {
            'datastoreUrn': 'urn:sites:4749082E:datastores:2',
            'quantityGB': 10,
            'volType': 1,
            'isThin': True,
            'sequenceNum': 1,
        }
        properties = {
            'isEnableHa': True,
            'reoverByHost': False,
            'isEnableFt': False
        }
        COMMANDS = {
            'v5.1': {
                'list_tasks': ('GET', ('/tasks', kwargs.get(self.RESOURCE_URI),
                                       None, None), {}, {}, False),
                'list_hosts': ('GET', ('/hosts', kwargs.get(self.RESOURCE_URI),
                                       None, None), {
                                           'limit': kwargs.get('limit'),
                                           'offset': kwargs.get('offset'),
                                           'scope': kwargs.get('scope')
                                       }, {}, False),
                'list_datastores':
                ('GET', ('/datastores', kwargs.get(self.RESOURCE_URI), None,
                         None), {
                             'limit': kwargs.get('limit'),
                             'offset': kwargs.get('offset'),
                             'scope': kwargs.get('scope')
                         }, {}, False),
                'list_volumes':
                ('GET', ('/volumes', kwargs.get(self.RESOURCE_URI), None,
                         kwargs.get('id')), {
                             'limit': kwargs.get('limit'),
                             'offset': kwargs.get('offset'),
                             'scope': kwargs.get('scope')
                         }, {}, False),
                'create_volume': ('POST', ('/volumes', None, None, None), {}, {
                    'name':
                    kwargs.get('name'),
                    'quantityGB':
                    kwargs.get('quantityGB'),
                    'datastoreUrn':
                    kwargs.get('datastoreUrn'),
                    'uuid':
                    kwargs.get('uuid'),
                    'isThin':
                    kwargs.get('isThin'),
                    'type':
                    kwargs.get('type'),
                    'indepDisk':
                    kwargs.get('indepDisk'),
                    'persistentDisk':
                    kwargs.get('persistentDisk'),
                    'volumeId':
                    kwargs.get('volumeId'),
                }, True),
                'delete_volume':
                ('DELETE', ('/volumes', kwargs.get(self.RESOURCE_URI), None,
                            None), {}, {}, True),
                'list_volumesnapshot':
                ('GET', ('/volumesnapshots', None, kwargs.get('uuid'), None), {
                    'limit': kwargs.get('limit'),
                    'offset': kwargs.get('offset'),
                    'scope': kwargs.get('scope')
                }, {}, False),
                'create_volumesnapshot':
                ('POST', ('/volumesnapshots', None, None, None), {}, {
                    'volumeUrn': kwargs.get('vol_urn'),
                    'snapshotUuid': kwargs.get('uuid'),
                }, False),
                'delete_volumesnapshot': ('DELETE',
                                          ('/volumesnapshots', None, None,
                                           kwargs.get('id')), {}, {
                                               'snapshotUuid':
                                               kwargs.get('snapshotUuid'),
                                           }, True),
                'createvolumefromsnapshot':
                ('POST', ('/volumesnapshots', None, "createvol", None), {}, {
                    'snapshotUuid': kwargs.get('uuid'),
                    'volumeName': kwargs.get('name'),
                }, True),
                'clone_volume': ('POST', ('/volumes', None,
                                          kwargs.get('src_name'),
                                          'action/copyVol'), {}, {
                                              'destinationVolumeID':
                                              kwargs.get('dest_name')
                                          }, True),
                'copy_image_to_volume':
                ('POST', ('/volumes/imagetovolume', None, None, None), {}, {
                    'volumePara': {
                        'quantityGB': kwargs.get('volume_size'),
                        'urn': kwargs.get('volume_urn')
                    },
                    'imagePara': {
                        'id': kwargs.get('image_id'),
                        'url': kwargs.get('image_location')
                    },
                    'location': kwargs.get('host_urn'),
                    'needCreateVolume': False
                }, True),
                'copy_volume_to_image':
                ('POST', ('/volumes/volumetoimage', None, None, None), {}, {
                    'volumePara': {
                        'urn': kwargs.get('volume_urn'),
                        'quantityGB': kwargs.get('volume_size')
                    },
                    'imagePara': {
                        'id': kwargs.get('image_id'),
                        'url': kwargs.get('image_url')
                    }
                }, True),
                'import_vm_from_image':
                ('POST', ('/vms/action/import', None, None, None), {},
                 dict({
                     'name': 'name',
                     'location': kwargs.get('host_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),
                'detach_vol_from_vm': ('POST', ('/vms', None,
                                                kwargs.get('vm_id'),
                                                'action/detachvol'), {}, {
                                                    'volUrn':
                                                    kwargs.get('volUrn')
                                                }, True),
                'stop_vm': ('POST', ('/vms', None, kwargs.get('vm_id'),
                                     'action/stop'), {}, {
                                         'mode': kwargs.get('mode')
                                     }, True),
                'delete_vm': ('DELETE', ('/vms', None, kwargs.get('vm_id'),
                                         None), {}, {}, True),
                'query_vm': ('GET', ('/vms', None, kwargs.get('vm_id'), None),
                             {}, {}, False),
                'list_templates': ('GET', ('/vms', None, None, None), {
                    'limit': kwargs.get('limit'),
                    'offset': kwargs.get('offset'),
                    'scope': kwargs.get('scope'),
                    'isTemplate': 'true'
                }, {}, False),
                'clone_vm': ('POST', ('/vms', None, kwargs.get('template_id'),
                                      'action/clone'), {},
                             dict({
                                 "name": "cinder-plugin-temp-vm",
                                 "description": "cinder-plugin-temp-vm",
                                 "isLinkClone": kwargs.get('linked_clone'),
                                 'location': kwargs.get('host_urn'),
                                 'autoBoot': 'false',
                                 'vmConfig': {
                                     'cpu': {
                                         'quantity': 2
                                     },
                                     'memory': {
                                         'quantityMB': 1024
                                     },
                                     'disks': [
                                         {
                                             'pciType':
                                             'IDE',
                                             'datastoreUrn':
                                             kwargs.get('ds_urn'),
                                             'quantityGB':
                                             kwargs.get('volume_size'),
                                             'volType':
                                             0,
                                             'sequenceNum':
                                             1,
                                             'isThin':
                                             kwargs.get('is_thin')
                                         },
                                     ],
                                 },
                             }), True),
            },
            'v2.0': {}
        }

        path = query = body = None

        LOG.info("[BRM-DRIVER] version is [%s]", self.version)
        if self.version not in COMMANDS.keys():
            raise driver_exception.UnsupportedVersion()
        else:
            commands = COMMANDS[self.version]

        if cmd not in commands.keys():
            raise driver_exception.UnsupportedCommand()
        else:
            (method, pathparams, queryparams, bodyparams,
             hastask) = commands[cmd]

        resource, resource_uri, tag1, tag2 = pathparams
        if resource_uri:
            path = resource_uri
            LOG.debug(_("[VRM-CINDER] [%s]"), path)
        else:
            path = self.site_uri + resource
            LOG.debug(_("[VRM-CINDER] [%s]"), path)
        if tag1:
            path += ('/' + str(tag1))
            LOG.debug(_("[VRM-CINDER] [%s]"), path)
        if tag2:
            path += ('/' + str(tag2))
            LOG.debug(_("[VRM-CINDER] [%s]"), path)

        if method == 'GET':
            query = self._joined_params(queryparams)
        elif method == 'DELETE':
            query = self._joined_params(queryparams)
        elif method == 'POST':
            query = self._joined_params(queryparams)
            LOG.info("[BRM-DRIVER] _generate_vrm_cmd bodyparams is [%s]",
                     bodyparams)
            body = json.dumps(bodyparams)
            LOG.info("[BRM-DRIVER] _generate_vrm_cmd body is [%s]", body)
        else:
            raise cinder_exception.UnknownCmd(cmd=method)

        url = self._generate_url(path, query)
        LOG.info("[BRM-DRIVER] _generate_vrm_cmd url is [%s]", url)

        return (method, url, body, hastask)
Beispiel #6
0
    def _generate_vpsa_cmd(self, cmd, **kwargs):
        """Generate command to be sent to VPSA."""

        # Dictionary of applicable VPSA commands in the following format:
        # 'command': (method, API_URL, {optional parameters})
        vpsa_commands = {
            'login': ('POST',
                      '/api/users/login.xml',
                      {'user': self.conf.zadara_user,
                       'password': self.conf.zadara_password}),
            # Volume operations
            'create_volume': ('POST',
                              '/api/volumes.xml',
                              {'name': kwargs.get('name'),
                               'capacity': kwargs.get('size'),
                               'pool': self.conf.zadara_vpsa_poolname,
                               'thin': 'YES',
                               'crypt': 'YES'
                               if self.conf.zadara_vol_encrypt else 'NO',
                               'attachpolicies': 'NO'
                               if not self.conf.zadara_default_snap_policy
                               else 'YES'}),
            'delete_volume': ('DELETE',
                              '/api/volumes/%s.xml' % kwargs.get('vpsa_vol'),
                              {'force': 'YES'}),
            'expand_volume': ('POST',
                              '/api/volumes/%s/expand.xml'
                              % kwargs.get('vpsa_vol'),
                              {'capacity': kwargs.get('size')}),
            # Snapshot operations
            # Snapshot request is triggered for a single volume though the
            # API call implies that snapshot is triggered for CG (legacy API).
            'create_snapshot': ('POST',
                                '/api/consistency_groups/%s/snapshots.xml'
                                % kwargs.get('cg_name'),
                                {'display_name': kwargs.get('snap_name')}),
            'delete_snapshot': ('DELETE',
                                '/api/snapshots/%s.xml'
                                % kwargs.get('snap_id'),
                                {}),
            'create_clone_from_snap': ('POST',
                                       '/api/consistency_groups/%s/clone.xml'
                                       % kwargs.get('cg_name'),
                                       {'name': kwargs.get('name'),
                                        'snapshot': kwargs.get('snap_id')}),
            'create_clone': ('POST',
                             '/api/consistency_groups/%s/clone.xml'
                             % kwargs.get('cg_name'),
                             {'name': kwargs.get('name')}),
            # Server operations
            'create_server': ('POST',
                              '/api/servers.xml',
                              {'display_name': kwargs.get('initiator'),
                               'iqn': kwargs.get('initiator')}),
            # Attach/Detach operations
            'attach_volume': ('POST',
                              '/api/servers/%s/volumes.xml'
                              % kwargs.get('vpsa_srv'),
                              {'volume_name[]': kwargs.get('vpsa_vol'),
                               'force': 'NO'}),
            'detach_volume': ('POST',
                              '/api/volumes/%s/detach.xml'
                              % kwargs.get('vpsa_vol'),
                              {'server_name[]': kwargs.get('vpsa_srv'),
                               'force': 'YES'}),
            # Get operations
            'list_volumes': ('GET',
                             '/api/volumes.xml',
                             {}),
            'list_pools': ('GET',
                           '/api/pools.xml',
                           {}),
            'list_controllers': ('GET',
                                 '/api/vcontrollers.xml',
                                 {}),
            'list_servers': ('GET',
                             '/api/servers.xml',
                             {}),
            'list_vol_attachments': ('GET',
                                     '/api/volumes/%s/servers.xml'
                                     % kwargs.get('vpsa_vol'),
                                     {}),
            'list_vol_snapshots': ('GET',
                                   '/api/consistency_groups/%s/snapshots.xml'
                                   % kwargs.get('cg_name'),
                                   {})}

        try:
            method, url, params = vpsa_commands[cmd]
        except KeyError:
            raise exception.UnknownCmd(cmd=cmd)

        if method == 'GET':
            params = dict(page=1, start=0, limit=0)
            body = None

        elif method in ['DELETE', 'POST']:
            body = params
            params = None

        else:
            msg = (_('Method %(method)s is not defined') %
                   {'method': method})
            LOG.error(msg)
            raise AssertionError(msg)

        # 'access_key' was generated using username and password
        # or it was taken from the input file
        headers = {'X-Access-Key': self.access_key}

        return method, url, params, body, headers