def _validate_arq_patch(self, patch): """Validate a single patch for an ARQ. :param patch: a JSON PATCH document. The patch must be of the form [{..}], as specified in the value field of arq_uuid in patch() method below. :returns: dict of valid fields """ valid_fields = { 'hostname': None, 'device_rp_uuid': None, 'instance_uuid': None } if ((not all(p['op'] == 'add' for p in patch)) and (not all(p['op'] == 'remove' for p in patch))): raise exception.PatchError(reason='Every op must be add or remove') for p in patch: path = p['path'].lstrip('/') if path not in valid_fields.keys(): reason = 'Invalid path in patch {}'.format(p['path']) raise exception.PatchError(reason=reason) if p['op'] == 'add': valid_fields[path] = p['value'] not_found = [ field for field, value in valid_fields.items() if value is None ] if patch[0]['op'] == 'add' and len(not_found) > 0: msg = ','.join(not_found) reason = _('Fields absent in patch {}').format(msg) raise exception.PatchError(reason=reason) return valid_fields
def patch(self, uuid, patch): """Update a deployable. :param uuid: UUID of a deployable. :param patch: a json PATCH document to apply to this deployable. """ context = pecan.request.context obj_dep = objects.Deployable.get(context, uuid) try: api_dep = Deployable( **api_utils.apply_jsonpatch(obj_dep.as_dict(), patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) # Update only the fields that have changed for field in objects.Deployable.fields: try: patch_val = getattr(api_dep, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if obj_dep[field] != patch_val: obj_dep[field] = patch_val new_dep = pecan.request.conductor_api.deployable_update( context, obj_dep) return Deployable.convert_with_links(new_dep)
def patch(self, uuid, patch): """Update an accelerator. :param uuid: UUID of an accelerator. :param patch: a json PATCH document to apply to this accelerator. """ obj_acc = self._resource or self._get_resource(uuid) try: api_acc = Accelerator( **api_utils.apply_jsonpatch(obj_acc.as_dict(), patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) # Update only the fields that have changed for field in objects.Accelerator.fields: try: patch_val = getattr(api_acc, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if obj_acc[field] != patch_val: obj_acc[field] = patch_val context = pecan.request.context new_acc = pecan.request.conductor_api.accelerator_update( context, obj_acc) return Accelerator.convert_with_links(new_acc)
def put(self, uuid, patch): """Update an port's property. : param uuid: UUID of a port. : param patch: a json PATCH document to apply to this port. """ obj_port = self._resource or self._get_resource(uuid) try: api_port = Port( **api_utils.apply_jsonpatch(obj_port.as_dict(), patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: raise exception.PatchError(patch=patch, reason=e) #update only the fields that have changed. for field in objects.Port.fields: try: patch_val = getattr(api_port, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if obj_port[field] != patch_val: obj_port[field] = patch_val context = pecan.request.context new_port = pecan.request.conductor_api.port_update(context, obj_port) return Port.convert_with_links(new_port)
def _validate_arq_patch(self, patch): """Validate a single patch for an ARQ. :param patch: a JSON PATCH document. The patch must be of the form [{..}], as specified in the value field of arq_uuid in patch() method below. :returns: dict of valid fields """ valid_fields = { 'hostname': None, 'device_rp_uuid': None, 'instance_uuid': None } if utils.allow_project_id(): valid_fields['project_id'] = None if ((not all(p['op'] == 'add' for p in patch)) and (not all(p['op'] == 'remove' for p in patch))): raise exception.PatchError(reason='Every op must be add or remove') for p in patch: path = p['path'].lstrip('/') if path == 'project_id' and not utils.allow_project_id(): raise exception.NotAcceptable( _("Request not acceptable. The minimal required API " "version should be %(base)s.%(opr)s") % { 'base': versions.BASE_VERSION, 'opr': versions.MINOR_1_PROJECT_ID }) if path not in valid_fields.keys(): reason = 'Invalid path in patch {}'.format(p['path']) raise exception.PatchError(reason=reason) if p['op'] == 'add': valid_fields[path] = p['value'] not_found = [ field for field, value in valid_fields.items() if value is None ] if patch[0]['op'] == 'add' and len(not_found) > 0: msg = ','.join(not_found) reason = _('Fields absent in patch {}').format(msg) raise exception.PatchError(reason=reason) return valid_fields
def _check_if_already_bound(context, valid_fields): patch_fields = list(valid_fields.values())[0] instance_uuid = patch_fields['instance_uuid'] extarqs = objects.ExtARQ.list(context) extarqs_for_instance = [ extarq for extarq in extarqs if extarq.arq['instance_uuid'] == instance_uuid ] if extarqs_for_instance: # duplicate binding request msg = _('Instance {} already has accelerator requests. ' 'Cannot bind additional ARQs.') reason = msg.format(instance_uuid) raise exception.PatchError(reason=reason)
def patch(self, uuid, patch): """Update a deployable. Usage: curl -X PATCH {ip}:{port}/v1/accelerators/deployables/ {deployable_uuid} -d '[{"path":"/instance_uuid","value": {instance_uuid}, "op":"replace"}]' -H "Content-type: application/json" :param uuid: UUID of a deployable. :param patch: a json PATCH document to apply to this deployable. """ context = pecan.request.context reservations = None obj_dep = objects.Deployable.get(context, uuid) try: # TODO(xinran): need more discussion on quota's granularity. # Now we count by board. for p in patch: if p["path"] == "/instance_uuid" and p["op"] == "replace": if not p["value"]: obj_dep["assignable"] = True reserve_opts = {obj_dep["board"]: -1} else: obj_dep["assignable"] = False reserve_opts = {obj_dep["board"]: 1} reservations = QUOTAS.reserve(context, reserve_opts) api_dep = Deployable( **api_utils.apply_jsonpatch(obj_dep.as_dict(), patch)) except api_utils.JSONPATCH_EXCEPTIONS as e: QUOTAS.rollback(context, reservations, project_id=None) raise exception.PatchError(patch=patch, reason=e) QUOTAS.commit(context, reservations) # Update only the fields that have changed for field in objects.Deployable.fields: try: patch_val = getattr(api_dep, field) except AttributeError: # Ignore fields that aren't exposed in the API continue if patch_val == wtypes.Unset: patch_val = None if obj_dep[field] != patch_val: obj_dep[field] = patch_val new_dep = pecan.request.conductor_api.deployable_update( context, obj_dep) return Deployable.convert_with_links(new_dep)