def delete(self, _id): context = t_context.extract_context_from_environ() # TODO(joehuang): get the release of top and bottom t_release = cons.R_MITAKA b_release = cons.R_MITAKA s_ctx = hclient.get_res_routing_ref(context, _id, request.url, cons.ST_CINDER) if not s_ctx: return utils.format_cinder_error( 404, _('Volume %s could not be found.') % _id) if s_ctx['b_url'] == '': return utils.format_cinder_error( 404, _('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 find # No content in the resp actually return response
def get_one(self, _id): context = t_context.extract_context_from_environ() if _id == 'detail': return {'volumes': self._get_all(context)} # 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) s_ctx = hclient.get_res_routing_ref(context, _id, request.url, cons.ST_CINDER) if not s_ctx: return utils.format_cinder_error( 404, _('Volume %s could not be found.') % _id) if s_ctx['b_url'] == '': return utils.format_cinder_error( 404, _('Bottom Pod endpoint incorrect')) resp = hclient.forward_req(context, 'GET', b_headers, s_ctx['b_url'], request.body) b_ret_body = jsonutils.loads(resp.content) b_status = resp.status_code response.status = b_status if b_status == 200: if b_ret_body.get('volume') is not None: b_vol_ret = b_ret_body['volume'] ret_vol = hclient.convert_object(b_release, t_release, b_vol_ret, res_type=cons.RT_VOLUME) pod = utils.get_pod_by_top_id(context, _id) if pod: ret_vol['availability_zone'] = pod['az_name'] return {'volume': ret_vol} # resource not find but routing exist, remove the routing if b_status == 404: filters = [{ 'key': 'top_id', 'comparator': 'eq', 'value': _id }, { 'key': 'resource_type', 'comparator': 'eq', 'value': cons.RT_VOLUME }] with context.session.begin(): core.delete_resources(context, models.ResourceRouting, filters) return b_ret_body
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
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
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
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
def put(self, _id, **kw): context = t_context.extract_context_from_environ() # TODO(joehuang): Implement API multi-version compatibility # currently _convert_header and _convert_object are both dummy # functions and API versions are hard coded. After multi-version # compatibility is implemented, API versions will be retrieved from # top and bottom API server, also, _convert_header and _convert_object # will do the real job to convert the request header and body # according to the API versions. t_release = cons.R_MITAKA b_release = cons.R_MITAKA s_ctx = hclient.get_res_routing_ref(context, _id, request.url, cons.ST_CINDER) if not s_ctx: return utils.format_cinder_error( 404, _('Volume %s could not be found.') % _id) if s_ctx['b_url'] == '': return utils.format_cinder_error( 404, _('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) b_body = jsonutils.dumps({'volume': b_vol_req}) resp = hclient.forward_req(context, 'PUT', b_headers, s_ctx['b_url'], b_body) b_status = resp.status_code b_ret_body = jsonutils.loads(resp.content) response.status = b_status if b_status == 200: if b_ret_body.get('volume') is not None: b_vol_ret = b_ret_body['volume'] ret_vol = hclient.convert_object(b_release, t_release, b_vol_ret, res_type=cons.RT_VOLUME) pod = utils.get_pod_by_top_id(context, _id) if pod: ret_vol['availability_zone'] = pod['az_name'] return {'volume': ret_vol} # resource not found but routing exist, remove the routing if b_status == 404: filters = [{ 'key': 'top_id', 'comparator': 'eq', 'value': _id }, { 'key': 'resource_type', 'comparator': 'eq', 'value': cons.RT_VOLUME }] with context.session.begin(): core.delete_resources(context, models.ResourceRouting, filters) return b_ret_body
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
def put(self, **kw): """Update volume metadata. :param kw: dictionary of values to be updated :returns: updated volume type """ 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.")) 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, _('Resource not found')) except Exception as e: LOG.exception(_LE('Fail to update metadata for a volume: ' '%(volume_id)s' '%(exception)s'), {'volume_id': self.volume_id, 'exception': e}) return utils.format_cinder_error( 500, _('Fail to update 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) 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, 'PUT', b_headers, s_ctx['b_url'], b_body) b_status = resp.status_code b_body_ret = jsonutils.loads(resp.content) 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