Exemple #1
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if not t_context.is_admin_context(context):
            pecan.abort(400, _('Admin role required to create bindings'))
            return

        if 'pod_binding' not in kw:
            pecan.abort(400, _('Request body not found'))
            return

        pod_b = kw['pod_binding']
        tenant_id = pod_b.get('tenant_id', '').strip()
        pod_id = pod_b.get('pod_id', '').strip()
        _uuid = uuidutils.generate_uuid()

        if tenant_id == '' or pod_id == '':
            return Response(_('Tenant_id and pod_id can not be empty'), 422)

        # the az_pod_map_id should be exist for in the pod map table
        try:
            with context.session.begin():
                pod = core.get_resource(context, models.Pod, pod_id)
                if pod.get('az_name') == '':
                    return Response(_('Top region can not be bound'), 422)
        except t_exc.ResourceNotFound:
            return Response(_('pod_id not found in pod'), 422)
        except Exception as e:
            LOG.exception(
                _LE('Failed to get_resource for pod_id: '
                    '%(pod_id)s ,'
                    '%(exception)s '), {
                        'pod_id': pod_id,
                        'exception': e
                    })
            pecan.abort(500, _('Failed to create pod binding'))
            return

        try:
            with context.session.begin():
                pod_binding = core.create_resource(context, models.PodBinding,
                                                   {
                                                       'id': _uuid,
                                                       'tenant_id': tenant_id,
                                                       'pod_id': pod_id
                                                   })
        except db_exc.DBDuplicateEntry:
            return Response(_('Pod binding already exists'), 409)
        except db_exc.DBConstraintError:
            return Response(_('pod_id not exists in pod'), 422)
        except db_exc.DBReferenceError:
            return Response(_('DB reference not exists in pod'), 422)
        except Exception as e:
            LOG.exception(_LE('Failed to create pod binding: %(exception)s '),
                          {'exception': e})
            pecan.abort(500, _('Failed to create pod binding'))
            return

        return {'pod_binding': pod_binding}
Exemple #2
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if not policy.enforce(context, policy.ADMIN_API_BINDINGS_CREATE):
            pecan.abort(401, _('Unauthorized to create bindings'))
            return

        if 'pod_binding' not in kw:
            pecan.abort(400, _('Request body not found'))
            return

        pod_b = kw['pod_binding']
        tenant_id = pod_b.get('tenant_id', '').strip()
        pod_id = pod_b.get('pod_id', '').strip()

        if tenant_id == '' or pod_id == '':
            return Response(_('Tenant_id and pod_id can not be empty'), 422)

        # the az_pod_map_id should be exist for in the pod map table
        try:
            with context.session.begin():
                pod = core.get_resource(context, models.Pod, pod_id)
                if pod.get('az_name') == '':
                    return Response(_('Top region can not be bound'), 422)
        except t_exc.ResourceNotFound:
            return Response(_('pod_id not found in pod'), 422)
        except Exception as e:
            LOG.exception(
                _LE('Failed to get_resource for pod_id: '
                    '%(pod_id)s ,'
                    '%(exception)s '), {
                        'pod_id': pod_id,
                        'exception': e
                    })
            pecan.abort(500, _('Failed to create pod binding'))
            return

        try:
            pod_binding = db_api.create_pod_binding(context, tenant_id, pod_id)
        except db_exc.DBDuplicateEntry:
            return Response(_('Pod binding already exists'), 409)
        except db_exc.DBConstraintError:
            return Response(_('pod_id not exists in pod'), 422)
        except db_exc.DBReferenceError:
            return Response(_('DB reference not exists in pod'), 422)
        except Exception as e:
            LOG.exception(_LE('Failed to create pod binding: %(exception)s '),
                          {'exception': e})
            pecan.abort(500, _('Failed to create pod binding'))
            return

        return {'pod_binding': pod_binding}
Exemple #3
0
    def delete(self, _id):
        context = t_context.extract_context_from_environ()

        if not t_context.is_admin_context(context):
            pecan.abort(400, _('Admin role required to delete pods'))
            return

        try:
            with context.session.begin():
                pod = core.get_resource(context, models.Pod, _id)
                if pod is not None:
                    ag_name = utils.get_ag_name(pod['pod_name'])
                    ag = az_ag.get_ag_by_name(context, ag_name)
                    if ag is not None:
                        az_ag.delete_ag(context, ag['id'])
                core.delete_resource(context, models.Pod, _id)
                pecan.response.status = 200
                return {}
        except t_exc.ResourceNotFound:
            return Response(_('Pod not found'), 404)
        except Exception as e:
            LOG.exception(
                _LE('Failed to delete pod: %(pod_id)s,'
                    '%(exception)s'), {
                        'pod_id': _id,
                        'exception': e
                    })

            return Response(_('Failed to delete pod'), 500)
Exemple #4
0
def enforce(context, rule=None, target=None, *args, **kwargs):
    """Check authorization of a rule against the target and credentials.

        :param dict context: As much information about the user performing the
                             action as possible.
        :param rule: The rule to evaluate.
        :param dict target: As much information about the object being operated
                            on as possible.
        :return: ``True`` if the policy allows the action.
                 ``False`` if the policy does not allow the action.
    """
    enforcer = init()
    credentials = context.to_dict()
    if target is None:
        target = {'project_id': context.project_id, 'user_id': context.user_id}

    exc = t_exec.PolicyNotAuthorized

    try:
        result = enforcer.enforce(rule,
                                  target,
                                  credentials,
                                  do_raise=True,
                                  exc=exc,
                                  *args,
                                  **kwargs)

    except t_exec.PolicyNotAuthorized as e:
        result = False
        LOG.exception(_LE("%(msg)s, %(rule)s, %(target)s"), {
            'msg': str(e),
            'rule': rule,
            'target': target
        })
    return result
Exemple #5
0
    def delete(self, _id):
        """Marks volume types as deleted.

        :param _id: id of volume type to be deleted
        """
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        session = core.get_session()
        with session.begin():
            try:
                db_api.volume_type_get(context, _id, session)
            except exceptions.VolumeTypeNotFound as e:
                return utils.format_cinder_error(404, e.message)
            try:
                db_api.volume_type_delete(context, _id, session)
            except Exception as e:
                LOG.exception(
                    _LE('Fail to update volume type: %(id)s,'
                        '%(exception)s'), {
                            'id': _id,
                            'exception': e
                        })
                return utils.format_cinder_error(
                    500, _('Fail to delete volume type.'))

        pecan.response.status = 202
        return pecan.response
Exemple #6
0
    def delete(self, _id):
        context = t_context.extract_context_from_environ()

        if not policy.enforce(context, policy.ADMIN_API_PODS_DELETE):
            pecan.abort(401, _('Unauthorized to delete pods'))
            return

        try:
            with context.session.begin():
                pod = core.get_resource(context, models.Pod, _id)
                if pod is not None:
                    ag_name = utils.get_ag_name(pod['pod_name'])
                    ag = az_ag.get_ag_by_name(context, ag_name)
                    if ag is not None:
                        az_ag.delete_ag(context, ag['id'])
                core.delete_resource(context, models.Pod, _id)
                pecan.response.status = 200
        except t_exc.ResourceNotFound:
            return Response(_('Pod not found'), 404)
        except Exception as e:
            LOG.exception(
                _LE('Failed to delete pod: %(pod_id)s,'
                    '%(exception)s'), {
                        'pod_id': _id,
                        'exception': e
                    })

            return Response(_('Failed to delete pod'), 500)
Exemple #7
0
    def _get_all(self, context):

        # TODO(joehuang): query optimization for pagination, sort, etc
        ret = {}
        ret['volumes'] = []

        pods = az_ag.list_pods_by_tenant(context, self.tenant_id)
        for pod in pods:
            if pod['pod_name'] == '':
                continue

            query = urlparse.urlsplit(request.url).query
            query_filters = urlparse.parse_qsl(query)
            skip_pod = False
            for k, v in query_filters:
                if k == 'availability_zone' and v != pod['az_name']:
                    skip_pod = True
                    break
            if skip_pod:
                continue

            s_ctx = hclient.get_pod_service_ctx(context,
                                                request.url,
                                                pod['pod_name'],
                                                s_type=cons.ST_CINDER)
            if s_ctx['b_url'] == '':
                LOG.error(
                    _LE("bottom pod endpoint incorrect %s") % pod['pod_name'])
                continue

            # TODO(joehuang): get the release of top and bottom
            t_release = cons.R_MITAKA
            b_release = cons.R_MITAKA
            b_headers = hclient.convert_header(t_release, b_release,
                                               request.headers)

            resp = hclient.forward_req(context, 'GET', b_headers,
                                       s_ctx['b_url'], request.body)

            if resp.status_code == 200:

                routings = db_api.get_bottom_mappings_by_tenant_pod(
                    context, self.tenant_id, pod['pod_id'], cons.RT_VOLUME)

                b_ret_body = jsonutils.loads(resp.content)
                if b_ret_body.get('volumes'):
                    for vol in b_ret_body['volumes']:

                        if not routings.get(vol['id']):
                            b_ret_body['volumes'].remove(vol)
                            continue

                        vol['availability_zone'] = pod['az_name']

                    ret['volumes'].extend(b_ret_body['volumes'])

                if b_ret_body.get('volumes_links'):
                    ret['volumes_links'] = b_ret_body['volumes_links']
        return ret
Exemple #8
0
    def _should_format(self):

        if self.kwargs['message'] is None and '%(message)' in self.message:
            LOG.error(
                _LE('\%(message)s in message '
                    'but init parameter is None'))

        return self.kwargs['message'] is None or '%(message)' in self.message
Exemple #9
0
 def create_binding(context, tenant_id, pod_id):
     try:
         db_api.create_pod_binding(context, tenant_id, pod_id)
     except Exception as e:
         LOG.error(_LE('Fail to create pod binding: %(exception)s'),
                   {'exception': e})
         return False
     return True
Exemple #10
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if 'volumeAttachment' not in kw:
            return utils.format_nova_error(400,
                                           _('volumeAttachment is not set'))
        body = kw['volumeAttachment']
        if 'volumeId' not in body:
            return utils.format_nova_error(
                400, _('Invalid input for field/attribute volumeAttachment'))

        server_mappings = db_api.get_bottom_mappings_by_top_id(
            context, self.server_id, constants.RT_SERVER)
        if not server_mappings:
            return utils.format_nova_error(
                404,
                _('Instance %s could not be '
                  'found.') % self.server_id)
        volume_mappings = db_api.get_bottom_mappings_by_top_id(
            context, body['volumeId'], constants.RT_VOLUME)
        if not volume_mappings:
            return utils.format_nova_error(
                404,
                _('Volume %s could not be found') % body['volumeId'])

        server_pod_name = server_mappings[0][0]['pod_name']
        volume_pod_name = volume_mappings[0][0]['pod_name']
        if server_pod_name != volume_pod_name:
            LOG.error(
                _LE('Server %(server)s is in pod %(server_pod)s and '
                    'volume %(volume)s is in pod %(volume_pod)s, which '
                    'are not the same.'), {
                        'server': self.server_id,
                        'server_pod': server_pod_name,
                        'volume': body['volumeId'],
                        'volume_pod': volume_pod_name
                    })
            return utils.format_nova_error(
                400, _('Server and volume not in the same pod'))

        device = None
        if 'device' in body:
            device = body['device']
            # this regular expression is copied from nova/block_device.py
            match = re.match('(^/dev/x{0,1}[a-z]{0,1}d{0,1})([a-z]+)[0-9]*$',
                             device)
            if not match:
                return utils.format_nova_error(
                    400,
                    _('The supplied device path (%s) is '
                      'invalid.') % device)

        client = self._get_client(server_pod_name)
        volume = client.action_server_volumes(context, 'create_server_volume',
                                              server_mappings[0][1],
                                              volume_mappings[0][1], device)
        return {'volumeAttachment': volume.to_dict()}
Exemple #11
0
 def _process_metadata_quota(self, context, t_server_dict):
     try:
         ctx = context.elevated()
         metadata = t_server_dict.get('metadata', None)
         self._check_metadata_properties_quota(ctx, metadata)
     except t_exceptions.InvalidMetadata as e1:
         LOG.exception(_LE('Invalid metadata %(exception)s'),
                       {'exception': str(e1)})
         return utils.format_nova_error(400, _('Invalid metadata'))
     except t_exceptions.InvalidMetadataSize as e2:
         LOG.exception(_LE('Invalid metadata size %(exception)s'),
                       {'exception': str(e2)})
         return utils.format_nova_error(400, _('Invalid metadata size'))
     except t_exceptions.MetadataLimitExceeded as e3:
         LOG.exception(_LE('Quota exceeded %(exception)s'),
                       {'exception': str(e3)})
         return utils.format_nova_error(400,
                                        _('Quota exceeded in metadata'))
Exemple #12
0
 def update_binding(context, current_binding, pod_id):
     current_binding['is_binding'] = False
     try:
         db_api.change_pod_binding(context, current_binding, pod_id)
     except Exception as e:
         LOG.error(_LE('Fail to update pod binding: %(exception)s'),
                   {'exception': e})
         return False
     return True
Exemple #13
0
 def _process_injected_file_quota(self, context, t_server_dict):
     try:
         ctx = context.elevated()
         injected_files = t_server_dict.get('injected_files', None)
         self._check_injected_file_quota(ctx, injected_files)
     except (t_exceptions.OnsetFileLimitExceeded,
             t_exceptions.OnsetFilePathLimitExceeded,
             t_exceptions.OnsetFileContentLimitExceeded) as e:
         msg = str(e)
         LOG.exception(_LE('Quota exceeded %(msg)s'), {'msg': msg})
         return utils.format_nova_error(400, _('Quota exceeded %s') % msg)
Exemple #14
0
    def stop(self):
        try:
            self.rpc_server.stop()
        except Exception:
            pass

        try:
            self.manager.cleanup_host()
        except Exception:
            LOG.exception(_LE('Service error occurred during cleanup_host'))
            pass

        super(XService, self).stop()
Exemple #15
0
    def get_all(self):
        context = t_context.extract_context_from_environ()

        if not t_context.is_admin_context(context):
            pecan.abort(400, _('Admin role required to list pods'))
            return

        try:
            return {'pods': db_api.list_pods(context)}
        except Exception as e:
            LOG.exception(_LE('Failed to list all pods: %(exception)s '),
                          {'exception': e})

            pecan.abort(500, _('Failed to list pods'))
            return
Exemple #16
0
    def _get_top_region(self, ctx):
        top_region_name = ''
        try:
            with ctx.session.begin():
                pods = core.query_resource(ctx, models.Pod, [], [])
                for pod in pods:
                    if pod['az_name'] == '' and pod['pod_name'] != '':
                        return pod['pod_name']
        except Exception as e:
            LOG.exception(_LE('Failed to get top region: %(exception)s '),
                          {'exception': e})

            return top_region_name

        return top_region_name
Exemple #17
0
    def get_all(self):
        context = t_context.extract_context_from_environ()

        if not policy.enforce(context, policy.ADMIN_API_PODS_LIST):
            pecan.abort(401, _('Unauthorized to list pods'))
            return

        try:
            return {'pods': db_api.list_pods(context)}
        except Exception as e:
            LOG.exception(_LE('Failed to list all pods: %(exception)s '),
                          {'exception': e})

            pecan.abort(500, _('Failed to list pods'))
            return
Exemple #18
0
    def get_one(self):
        """Get all metadata associated with a volume."""
        context = t_context.extract_context_from_environ()

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        b_headers = hclient.convert_header(t_release,
                                           b_release,
                                           request.headers)

        try:
            s_ctx = hclient.get_res_routing_ref(context, self.volume_id,
                                                request.url, cons.ST_CINDER)
            if not s_ctx:
                return utils.format_cinder_error(
                    500, _('Fail to find resource'))
        except Exception as e:
            LOG.exception(_LE('Fail to get metadata for a volume:'
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(500, _('Fail to get metadata'))

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        resp = hclient.forward_req(context, 'GET',
                                   b_headers,
                                   s_ctx['b_url'],
                                   request.body)

        b_body_ret = jsonutils.loads(resp.content)

        b_status = resp.status_code
        response.status = b_status
        if b_status == 200:
            if b_body_ret.get('metadata') is not None:
                b_metadata_ret = b_body_ret['metadata']
                vol_ret = hclient.convert_object(b_release, t_release,
                                                 b_metadata_ret,
                                                 res_type=cons.
                                                 RT_VOl_METADATA)
                return {'metadata': vol_ret}

        return b_body_ret
Exemple #19
0
def get_pod_by_az_tenant(context, az_name, tenant_id):
    pod_bindings = core.query_resource(context, models.PodBinding,
                                       [{
                                           'key': 'tenant_id',
                                           'comparator': 'eq',
                                           'value': tenant_id
                                       }], [])
    for pod_b in pod_bindings:
        pod = core.get_resource(context, models.Pod, pod_b['pod_id'])
        if az_name and pod['az_name'] == az_name:
            return pod, pod['pod_az_name']
        elif az_name == '' and pod['az_name'] != '':
            # if the az_name is not specified, a defult bottom
            # pod will be selected
            return pod, pod['pod_az_name']
        else:
            pass

    # TODO(joehuang): schedule one dynamically in the future
    if az_name != '':
        filters = [{'key': 'az_name', 'comparator': 'eq', 'value': az_name}]
    else:
        filters = None

    # if az_name is valid, select a pod under this az_name
    # if az_name is '', select the first valid bottom pod.
    # change to dynamic schedluing in the future
    pods = db_api.list_pods(context, filters=filters)
    for pod in pods:
        if pod['pod_name'] != '' and pod['az_name'] != '':
            try:
                with context.session.begin():
                    core.create_resource(
                        context, models.PodBinding, {
                            'id': uuidutils.generate_uuid(),
                            'tenant_id': tenant_id,
                            'pod_id': pod['pod_id'],
                            'is_binding': True
                        })
                    return pod, pod['pod_az_name']
            except Exception as e:
                LOG.error(_LE('Fail to create pod binding: %(exception)s'),
                          {'exception': e})
                return None, None

    return None, None
Exemple #20
0
    def get_all(self):
        """Get all non-deleted volume_types."""
        filters = {}
        context = t_context.extract_context_from_environ()
        if not context.is_admin:
            # Only admin has query access to all volume types
            filters['is_public'] = True
        try:
            list_result = db_api.volume_type_get_all(context,
                                                     list_result=True,
                                                     filters=filters)
        except Exception as e:
            LOG.exception(_LE('Fail to retrieve volume types: %(exception)s'),
                          {'exception': e})
            return utils.format_cinder_error(500, e)

        return {'volume_types': list_result}
Exemple #21
0
    def delete(self, key):
        """Delete the given metadata item from a volume."""
        context = t_context.extract_context_from_environ()

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        try:
            s_ctx = hclient.get_res_routing_ref(context, self.volume_id,
                                                request.url, cons.ST_CINDER)
            if not s_ctx:
                return utils.format_cinder_error(
                    404, _('Fail to find resource'))
        except Exception as e:
            LOG.exception(_LE('Fail to delete metadata from a volume: '
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(
                500, _('Fail to delete metadata'))

        if s_ctx['b_url'] == '':
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release,
                                           b_release,
                                           request.headers)

        resp = hclient.forward_req(context, 'DELETE',
                                   b_headers,
                                   s_ctx['b_url'],
                                   request.body)

        response.status = resp.status_code

        # don't remove the resource routing for delete is async. operation
        # remove the routing when query is executed but not found
        # No content in the resp actually
        return response
Exemple #22
0
def get_res_routing_ref(context, _id, t_url, s_type):
    """Get the service context according to resource routing.

    :param _id: the top id of resource
    :param t_url: request url
    :param s_type: service type
    :returns: service context
    """
    pod = utils.get_pod_by_top_id(context, _id)

    if not pod:
        return None

    pod_name = pod['pod_name']

    s_ctx = get_pod_service_ctx(context, t_url, pod_name, s_type=s_type)

    if s_ctx['b_url'] == '':
        LOG.error(_LE("bottom pod endpoint incorrect %s") % pod_name)

    return s_ctx
Exemple #23
0
    def get_one(self, _id):
        """Retrieves single volume type by id.

        :param _id: id of volume type to be retrieved
        :returns: retrieved volume type
        """
        context = t_context.extract_context_from_environ()
        try:
            result = db_api.volume_type_get(context, _id)
        except exceptions.VolumeTypeNotFound as e:
            return utils.format_cinder_error(404, e.message)
        except Exception as e:
            LOG.exception(
                _LE('Volume type not found: %(id)s,'
                    '%(exception)s'), {
                        'id': _id,
                        'exception': e
                    })
            return utils.format_cinder_error(
                404,
                _("Volume type %(id)s could not be found.") % {'id': _id})
        return {'volume_type': result}
Exemple #24
0
    def post(self, **kw):
        """Create volume metadata associated with a volume.

        :param kw: dictionary of values to be created
        :returns: created volume metadata
        """
        context = t_context.extract_context_from_environ()

        if 'metadata' not in kw:
            return utils.format_cinder_error(
                400, _("Missing required element 'metadata' in "
                       "request body."))

        try:
            pod = utils.get_pod_by_top_id(context, self.volume_id)
            if pod is None:
                return utils.format_cinder_error(
                    404, _('Volume %(volume_id)s could not be found.') % {
                        'volume_id': self.volume_id
                    })

            t_pod = db_api.get_top_pod(context)
            if not t_pod:
                LOG.error(_LE("Top Pod not configured"))
                return utils.format_cinder_error(
                    500, _('Top Pod not configured'))
        except Exception as e:
            LOG.exception(_LE('Fail to create metadata for a volume:'
                              '%(volume_id)s'
                              '%(exception)s'),
                          {'volume_id': self.volume_id,
                           'exception': e})
            return utils.format_cinder_error(500, _('Fail to create metadata'))

        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_pod_service_ctx(
            context,
            request.url,
            pod['pod_name'],
            s_type=cons.ST_CINDER)

        if s_ctx['b_url'] == '':
            LOG.error(_LE("Bottom pod endpoint incorrect %s") %
                      pod['pod_name'])
            return utils.format_cinder_error(
                500, _('Bottom pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        t_metadata = kw['metadata']

        # add or remove key-value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release, b_release, t_metadata,
                                           res_type=cons.RT_VOl_METADATA)

        b_body = jsonutils.dumps({'metadata': b_vol_req})

        resp = hclient.forward_req(
            context,
            'POST',
            b_headers,
            s_ctx['b_url'],
            b_body)
        b_status = resp.status_code
        b_body_ret = jsonutils.loads(resp.content)

        # convert response from the bottom pod
        # for different version.
        response.status = b_status
        if b_status == 200:
            if b_body_ret.get('metadata') is not None:
                b_metadata_ret = b_body_ret['metadata']

                vol_ret = hclient.convert_object(b_release, t_release,
                                                 b_metadata_ret,
                                                 res_type=cons.
                                                 RT_VOl_METADATA)

                return {'metadata': vol_ret}

        return b_body_ret
Exemple #25
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if not policy.enforce(context, policy.ADMIN_API_PODS_CREATE):
            pecan.abort(401, _('Unauthorized to create pods'))
            return

        if 'pod' not in kw:
            pecan.abort(400, _('Request body pod not found'))
            return

        pod = kw['pod']

        # if az_name is null, and there is already one in db
        pod_name = pod.get('pod_name', '').strip()
        pod_az_name = pod.get('pod_az_name', '').strip()
        dc_name = pod.get('dc_name', '').strip()
        az_name = pod.get('az_name', '').strip()
        _uuid = uuidutils.generate_uuid()

        if az_name == '' and pod_name == '':
            return Response(_('Valid pod_name is required for top region'),
                            422)

        if az_name != '' and pod_name == '':
            return Response(_('Valid pod_name is required for pod'), 422)

        if pod.get('az_name') is None:
            if self._get_top_region(context) != '':
                return Response(_('Top region already exists'), 409)

        # if az_name is not null, then the pod region name should not
        # be same as that the top region
        if az_name != '':
            if self._get_top_region(context) == pod_name and pod_name != '':
                return Response(
                    _('Pod region name duplicated with the top region name'),
                    409)

        # to create the top region, make the pod_az_name to null value
        if az_name == '':
            pod_az_name = ''

        try:
            with context.session.begin():
                # if not top region,
                # then add corresponding ag and az for the pod
                if az_name != '':
                    ag_name = utils.get_ag_name(pod_name)
                    aggregate = az_ag.create_ag_az(context,
                                                   ag_name=ag_name,
                                                   az_name=az_name)
                    if aggregate is None:
                        return Response(_('Ag creation failure'), 400)

                new_pod = core.create_resource(
                    context, models.Pod, {
                        'pod_id': _uuid,
                        'pod_name': pod_name,
                        'pod_az_name': pod_az_name,
                        'dc_name': dc_name,
                        'az_name': az_name
                    })
        except db_exc.DBDuplicateEntry as e1:
            LOG.exception(
                _LE('Record already exists on %(pod_name)s: '
                    '%(exception)s'), {
                        'pod_name': pod_name,
                        'exception': e1
                    })
            return Response(_('Record already exists'), 409)
        except Exception as e2:
            LOG.exception(
                _LE('Failed to create pod: %(pod_name)s,'
                    'pod_az_name: %(pod_az_name)s,'
                    'dc_name: %(dc_name)s,'
                    'az_name: %(az_name)s'
                    '%(exception)s '), {
                        'pod_name': pod_name,
                        'pod_az_name': pod_az_name,
                        'dc_name': dc_name,
                        'az_name': az_name,
                        'exception': e2
                    })
            return Response(_('Failed to create pod'), 500)

        return {'pod': new_pod}
Exemple #26
0
    def put(self, _id, **kw):
        """Update volume type by id.

        :param _id: id of volume type to be updated
        :param kw: dictionary of values to be updated
        :returns: updated volume type
        """
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        if 'volume_type' not in kw:
            return utils.format_cinder_error(
                400,
                _("Missing required element 'volume_type' in "
                  "request body."))

        values = kw['volume_type']
        name = values.get('name')
        description = values.get('description')
        is_public = values.get('os-volume-type-access:is_public')

        # Name and description can not be both None.
        # If name specified, name can not be empty.
        if name and len(name.strip()) == 0:
            return utils.format_cinder_error(
                400, _("Volume type name can not be empty."))

        if name is None and description is None and is_public is None:
            msg = _("Specify volume type name, description, is_public or "
                    "a combination thereof.")
            return utils.format_cinder_error(400, msg)

        if is_public is not None and not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%(is_public)s' for is_public. Accepted "
                    "values: True or False.") % {
                        'is_public': is_public
                    }
            return utils.format_cinder_error(400, msg)

        if name:
            try:
                utils.check_string_length(name,
                                          'Type name',
                                          min_len=1,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        if description is not None:
            try:
                utils.check_string_length(description,
                                          'Type description',
                                          min_len=0,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        try:
            type_updated = \
                db_api.volume_type_update(context, _id,
                                          dict(name=name,
                                               description=description,
                                               is_public=is_public))
        except exceptions.VolumeTypeNotFound as e:
            return utils.format_cinder_error(404, e.message)
        except exceptions.VolumeTypeExists as e:
            return utils.format_cinder_error(409, e.message)
        except exceptions.VolumeTypeUpdateFailed as e:
            return utils.format_cinder_error(500, e.message)
        except Exception as e:
            LOG.exception(
                _LE('Fail to update volume type: %(name)s,'
                    '%(exception)s'), {
                        'name': values['name'],
                        'exception': e
                    })
            return utils.format_cinder_error(500,
                                             _("Fail to update volume type."))
        return {'volume_type': type_updated}
Exemple #27
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        if 'volume' not in kw:
            return utils.format_cinder_error(
                400, _("Missing required element 'volume' in request body."))

        az = kw['volume'].get('availability_zone', '')
        pod, pod_az = az_ag.get_pod_by_az_tenant(context,
                                                 az_name=az,
                                                 tenant_id=self.tenant_id)
        if not pod:
            LOG.error(_LE("Pod not configured or scheduling failure"))
            return utils.format_cinder_error(
                500, _('Pod not configured or scheduling failure'))

        t_pod = db_api.get_top_pod(context)
        if not t_pod:
            LOG.error(_LE("Top Pod not configured"))
            return utils.format_cinder_error(500, _('Top Pod not configured'))

        # TODO(joehuang): get release from pod configuration,
        # to convert the content
        # b_release = pod['release']
        # t_release = t_pod['release']
        t_release = cons.R_MITAKA
        b_release = cons.R_MITAKA

        s_ctx = hclient.get_pod_service_ctx(context,
                                            request.url,
                                            pod['pod_name'],
                                            s_type=cons.ST_CINDER)

        if s_ctx['b_url'] == '':
            LOG.error(
                _LE("Bottom Pod endpoint incorrect %s") % pod['pod_name'])
            return utils.format_cinder_error(
                500, _('Bottom Pod endpoint incorrect'))

        b_headers = hclient.convert_header(t_release, b_release,
                                           request.headers)

        t_vol = kw['volume']

        # add or remove key-value in the request for diff. version
        b_vol_req = hclient.convert_object(t_release,
                                           b_release,
                                           t_vol,
                                           res_type=cons.RT_VOLUME)

        # convert az to the configured one
        # remove the AZ parameter to bottom request for default one
        b_vol_req['availability_zone'] = pod['pod_az_name']
        if b_vol_req['availability_zone'] == '':
            b_vol_req.pop("availability_zone", None)

        b_body = jsonutils.dumps({'volume': b_vol_req})

        resp = hclient.forward_req(context, 'POST', b_headers, s_ctx['b_url'],
                                   b_body)
        b_status = resp.status_code
        b_ret_body = jsonutils.loads(resp.content)

        # build routing and convert response from the bottom pod
        # for different version.
        response.status = b_status
        if b_status == 202:
            if b_ret_body.get('volume') is not None:
                b_vol_ret = b_ret_body['volume']

                try:
                    with context.session.begin():
                        core.create_resource(
                            context, models.ResourceRouting, {
                                'top_id': b_vol_ret['id'],
                                'bottom_id': b_vol_ret['id'],
                                'pod_id': pod['pod_id'],
                                'project_id': self.tenant_id,
                                'resource_type': cons.RT_VOLUME
                            })
                except Exception as e:
                    LOG.exception(
                        _LE('Failed to create volume '
                            'resource routing'
                            'top_id: %(top_id)s ,'
                            'bottom_id: %(bottom_id)s ,'
                            'pod_id: %(pod_id)s ,'
                            '%(exception)s '), {
                                'top_id': b_vol_ret['id'],
                                'bottom_id': b_vol_ret['id'],
                                'pod_id': pod['pod_id'],
                                'exception': e
                            })
                    return utils.format_cinder_error(
                        500, _('Failed to create volume resource routing'))

                ret_vol = hclient.convert_object(b_release,
                                                 t_release,
                                                 b_vol_ret,
                                                 res_type=cons.RT_VOLUME)

                ret_vol['availability_zone'] = pod['az_name']

                return {'volume': ret_vol}

        return b_ret_body
Exemple #28
0
    def post(self, **kw):
        """Creates volume types."""
        context = t_context.extract_context_from_environ()

        if not context.is_admin:
            return utils.format_cinder_error(
                403,
                _("Policy doesn't allow volume_extension:types_manage "
                  "to be performed."))

        if 'volume_type' not in kw:
            return utils.format_cinder_error(
                400,
                _("Missing required element 'volume_type' in "
                  "request body."))

        projects = []

        if self.tenant_id is not None:
            projects = [self.tenant_id]

        vol_type = kw['volume_type']
        name = vol_type.get('name', None)
        description = vol_type.get('description')
        specs = vol_type.get('extra_specs', {})
        is_public = vol_type.pop('os-volume-type-access:is_public', True)

        if name is None or len(name.strip()) == 0:
            return utils.format_cinder_error(
                400, _("Volume type name can not be empty."))

        try:
            utils.check_string_length(name,
                                      'Type name',
                                      min_len=1,
                                      max_len=255)
        except exceptions.InvalidInput as e:
            return utils.format_cinder_error(400, e.message)

        if description is not None:
            try:
                utils.check_string_length(description,
                                          'Type description',
                                          min_len=0,
                                          max_len=255)
            except exceptions.InvalidInput as e:
                return utils.format_cinder_error(400, e.message)

        if not utils.is_valid_boolstr(is_public):
            msg = _("Invalid value '%(is_public)s' for is_public. "
                    "Accepted values: True or False.") % {
                        'is_public': is_public
                    }
            return utils.format_cinder_error(400, msg)

        vol_type['extra_specs'] = specs
        vol_type['is_public'] = is_public
        vol_type['id'] = uuidutils.generate_uuid()

        session = core.get_session()
        with session.begin():
            try:
                db_api.volume_type_get_by_name(context, vol_type['name'],
                                               session)
                return utils.format_cinder_error(
                    409,
                    _("Volume Type %(id)s already exists.") %
                    {'id': vol_type['id']})
            except exceptions.VolumeTypeNotFoundByName:
                pass
            try:
                extra_specs = vol_type['extra_specs']
                vol_type['extra_specs'] = \
                    self._metadata_refs(vol_type.get('extra_specs'),
                                        models.VolumeTypeExtraSpecs)
                volume_type_ref = models.VolumeTypes()
                volume_type_ref.update(vol_type)
                session.add(volume_type_ref)
                for project in set(projects):
                    access_ref = models.VolumeTypeProjects()
                    access_ref.update({
                        "volume_type_id": volume_type_ref.id,
                        "project_id": project
                    })
                    access_ref.save(session=session)
            except Exception as e:
                LOG.exception(
                    _LE('Fail to create volume type: %(name)s,'
                        '%(exception)s'), {
                            'name': vol_type['name'],
                            'exception': e
                        })
                return utils.format_cinder_error(
                    500, _('Fail to create volume type'))

            vol_type['extra_specs'] = extra_specs
            return {'volume_type': vol_type}
Exemple #29
0
        def handle_args(*args, **kwargs):
            if IN_TEST:
                # NOTE(zhiyuan) job mechanism will cause some unpredictable
                # result in unit test so we would like to bypass it. However
                # we have problem mocking a decorator which decorates member
                # functions, that's why we use this label, not an elegant
                # way though.
                func(*args, **kwargs)
                return
            ctx = args[1]
            payload = kwargs['payload']

            resource_id = payload[job_type]
            db_api.new_job(ctx, job_type, resource_id)
            start_time = datetime.datetime.now()

            while True:
                current_time = datetime.datetime.now()
                delta = current_time - start_time
                if delta.seconds >= CONF.worker_handle_timeout:
                    # quit when this handle is running for a long time
                    break
                time_new = db_api.get_latest_timestamp(ctx, constants.JS_New,
                                                       job_type, resource_id)
                time_success = db_api.get_latest_timestamp(
                    ctx, constants.JS_Success, job_type, resource_id)
                if time_success and time_success >= time_new:
                    break
                job = db_api.register_job(ctx, job_type, resource_id)
                if not job:
                    # fail to obtain the lock, let other worker handle the job
                    running_job = db_api.get_running_job(
                        ctx, job_type, resource_id)
                    if not running_job:
                        # there are two reasons that running_job is None. one
                        # is that the running job has just been finished, the
                        # other is that all workers fail to register the job
                        # due to deadlock exception. so we sleep and try again
                        eventlet.sleep(CONF.worker_sleep_time)
                        continue
                    job_time = running_job['timestamp']
                    current_time = datetime.datetime.now()
                    delta = current_time - job_time
                    if delta.seconds > CONF.job_run_expire:
                        # previous running job expires, we set its status to
                        # fail and try again to obtain the lock
                        db_api.finish_job(ctx, running_job['id'], False,
                                          time_new)
                        LOG.warning(
                            _LW('Job %(job)s of type %(job_type)s for '
                                'resource %(resource)s expires, set '
                                'its state to Fail'), {
                                    'job': running_job['id'],
                                    'job_type': job_type,
                                    'resource': resource_id
                                })
                        eventlet.sleep(CONF.worker_sleep_time)
                        continue
                    else:
                        # previous running job is still valid, we just leave
                        # the job to the worker who holds the lock
                        break
                # successfully obtain the lock, start to execute handler
                try:
                    func(*args, **kwargs)
                except Exception:
                    db_api.finish_job(ctx, job['id'], False, time_new)
                    LOG.error(
                        _LE('Job %(job)s of type %(job_type)s for '
                            'resource %(resource)s fails'), {
                                'job': job['id'],
                                'job_type': job_type,
                                'resource': resource_id
                            })
                    break
                db_api.finish_job(ctx, job['id'], True, time_new)
                eventlet.sleep(CONF.worker_sleep_time)
Exemple #30
0
    def post(self, **kw):
        context = t_context.extract_context_from_environ()

        action_handle = None
        action_type = None
        for _type in self.handle_map:
            if _type in kw:
                action_handle = self.handle_map[_type]
                action_type = _type
        if not action_handle:
            return utils.format_cinder_error(400,
                                             _('Volume action not supported'))

        volume_mappings = db_api.get_bottom_mappings_by_top_id(
            context, self.volume_id, constants.RT_VOLUME)
        if not volume_mappings:
            return utils.format_cinder_error(
                404,
                _('Volume %(volume_id)s could not be found.') %
                {'volume_id': self.volume_id})

        pod_name = volume_mappings[0][0]['pod_name']

        if action_type == 'os-attach':
            instance_uuid = kw['os-attach'].get('instance_uuid')
            if instance_uuid is not None:
                server_mappings = db_api.get_bottom_mappings_by_top_id(
                    context, instance_uuid, constants.RT_SERVER)
                if not server_mappings:
                    return utils.format_cinder_error(404,
                                                     _('Server not found'))
                server_pod_name = server_mappings[0][0]['pod_name']
                if server_pod_name != pod_name:
                    LOG.error(
                        _LE('Server %(server)s is in pod %(server_pod)s'
                            'and volume %(volume)s is in pod'
                            '%(volume_pod)s, which '
                            'are not the same.'), {
                                'server': instance_uuid,
                                'server_pod': server_pod_name,
                                'volume': self.volume_id,
                                'volume_pod': pod_name
                            })
                    return utils.format_cinder_error(
                        400, _('Server and volume not in the same pod'))

        try:
            resp, body = action_handle(context, pod_name, kw)
            pecan.response.status = resp.status_code
            if not body:
                return pecan.response
            else:
                return body
        except Exception as e:
            code = 500
            message = _('Action %(action)s on volume %(volume_id)s fails') % {
                'action': action_type,
                'volume_id': self.volume_id
            }
            if hasattr(e, 'code'):
                code = e.code
            ex_message = str(e)
            if ex_message:
                message = ex_message
            LOG.error(message)
            return utils.format_cinder_error(code, message)