def test_patch_many(self, patch_many_dict, bg_patch, bg_patch2, kwargs): """Parametrize for the 'many' kwarg because the parser should ignore it""" patches = SchemaParser.parse_patch(patch_many_dict, **kwargs) sorted_patches = sorted(patches, key=lambda x: x.operation) for index, patch in enumerate([bg_patch, bg_patch2]): assert_patch_equal(patch, sorted_patches[index])
async def patch(self): """ --- summary: Initiate administrative actions description: | The body of the request needs to contain a set of instructions detailing the operations to perform. Currently the supported operations are `rescan`: ```JSON [ { "operation": "rescan" } ] ``` * Will remove from the registry and database any currently stopped plugins who's directory has been removed. * Will add and start any new plugin directories. And reloading the plugin logging configuration: ```JSON [ { "operation": "reload", "path": "/config/logging/plugin" } ] ``` parameters: - name: patch in: body required: true description: Instructions for operations schema: $ref: '#/definitions/Patch' responses: 204: description: Operation successfully initiated 50x: $ref: '#/definitions/50xError' tags: - Admin """ self.verify_user_permission_for_object(GARDEN_UPDATE, local_garden()) operations = SchemaParser.parse_patch( self.request.decoded_body, many=True, from_string=True ) for op in operations: if op.operation == "rescan": await self.client(Operation(operation_type="RUNNER_RESCAN")) elif op.operation == "reload": if op.path == "/config/logging/plugin": await self.client(Operation(operation_type="PLUGIN_LOG_RELOAD")) else: raise ModelValidationError(f"Unsupported path '{op.path}'") else: raise ModelValidationError(f"Unsupported operation '{op.operation}'") self.set_status(204)
async def patch(self): """ --- summary: Partially update a Garden description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * sync ```JSON [ { "operation": "" } ] ``` parameters: - name: garden_name in: path required: true description: Garden to use type: string - name: patch in: body required: true description: Instructions for how to update the Garden schema: $ref: '#/definitions/Patch' responses: 200: description: Execute Patch action against Gardens schema: $ref: '#/definitions/Garden' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Garden """ patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation == "sync": response = await self.client( Operation( operation_type="GARDEN_SYNC", ) ) else: raise ModelValidationError(f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
def test_patch_serialized_start(self, patch_dict_no_envelop): """Patches are always parsed into a list, so they need a tweak to test""" serialized = SchemaParser.serialize( SchemaParser.parse_patch(patch_dict_no_envelop, from_string=False), to_string=False, ) assert len(serialized) == 1 assert serialized[0] == patch_dict_no_envelop
async def patch(self): """ --- summary: Update runners description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * reload ```JSON [ { "operation": "reload", "path": "echo-3.0.0" } ] ``` parameters: - name: patch in: body required: true description: Instructions for how to update the Runner schema: $ref: '#/definitions/Patch' responses: 200: description: Reloaded Runners schema: $ref: '#/definitions/Runner' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Runners """ patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation == "reload": response = await self.client( Operation(operation_type="RUNNER_RELOAD", kwargs={"path": op.path})) else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self): """ --- summary: Reload the plugin logging configuration deprecated: true description: | The body of the request needs to contain a set of instructions detailing the operation to make. Currently supported operations are below: ```JSON { "operation": "reload" } ``` parameters: - name: patch in: body required: true description: Operation to perform schema: $ref: '#/definitions/Patch' responses: 200: description: Updated plugin logging configuration schema: $ref: '#/definitions/LoggingConfig' 50x: $ref: '#/definitions/50xError' tags: - Deprecated """ self.verify_user_permission_for_object(GARDEN_UPDATE, local_garden()) patch = SchemaParser.parse_patch(self.request.decoded_body, many=True, from_string=True) response = None for op in patch: if op.operation == "reload": response = await self.client( Operation(operation_type="PLUGIN_LOG_RELOAD")) else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self, instance_id): """ --- summary: Partially update an Instance description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * initialize * start * stop * heartbeat * replace ```JSON [ { "operation": "" } ] ``` parameters: - name: instance_id in: path required: true description: The ID of the Instance type: string - name: patch in: body required: true description: Instructions for how to update the Instance schema: $ref: '#/definitions/Patch' responses: 200: description: Instance with the given ID schema: $ref: '#/definitions/Instance' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Instances """ _ = self.get_or_raise(System, SYSTEM_UPDATE, instances__id=instance_id) patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation == "initialize": runner_id = None if op.value: runner_id = op.value.get("runner_id") response = await self.client( Operation( operation_type="INSTANCE_INITIALIZE", args=[instance_id], kwargs={"runner_id": runner_id}, )) elif operation == "start": response = await self.client( Operation(operation_type="INSTANCE_START", args=[instance_id])) elif operation == "stop": response = await self.client( Operation(operation_type="INSTANCE_STOP", args=[instance_id])) elif operation == "heartbeat": response = await self.client( Operation(operation_type="INSTANCE_HEARTBEAT", args=[instance_id])) elif operation == "replace": if op.path.lower() == "/status": response = await self.client( Operation( operation_type="INSTANCE_UPDATE", args=[instance_id], kwargs={"new_status": op.value}, )) else: raise ModelValidationError(f"Unsupported path '{op.path}'") elif operation == "update": if op.path.lower() == "/metadata": response = await self.client( Operation( operation_type="INSTANCE_UPDATE", args=[instance_id], kwargs={"metadata": op.value}, )) else: raise ModelValidationError(f"Unsupported path '{op.path}'") else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self, system_id): """ --- summary: Partially update a System description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently supported operations are below: ```JSON [ { "operation": "add", "path": "/instance", "value": "" }, { "operation": "replace", "path": "/commands", "value": "" }, { "operation": "replace", "path": "/description", "value": "new description"}, { "operation": "replace", "path": "/display_name", "value": "new display name"}, { "operation": "replace", "path": "/icon_name", "value": "new icon name"}, { "operation": "update", "path": "/metadata", "value": {"foo": "bar"}} ] ``` Where `value` is a list of new Commands. parameters: - name: system_id in: path required: true description: The ID of the System type: string - name: patch in: body required: true description: Instructions for how to update the System schema: $ref: '#/definitions/Patch' responses: 200: description: System with the given ID schema: $ref: '#/definitions/System' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Systems """ _ = self.get_or_raise(System, SYSTEM_UPDATE, id=system_id) kwargs = {} do_reload = False response = "" for op in SchemaParser.parse_patch(self.request.decoded_body, from_string=True): if op.operation == "replace": if op.path == "/commands": kwargs["new_commands"] = SchemaParser.parse_command( op.value, many=True) elif op.path in [ "/description", "/icon_name", "/display_name", "/template", ]: kwargs[op.path.strip("/")] = op.value else: raise ModelValidationError( f"Unsupported path for replace '{op.path}'") elif op.operation == "add": if op.path == "/instance": if not kwargs.get("add_instances"): kwargs["add_instances"] = [] kwargs["add_instances"].append( SchemaParser.parse_instance(op.value)) else: raise ModelValidationError( f"Unsupported path for add '{op.path}'") elif op.operation == "update": if op.path == "/metadata": kwargs["metadata"] = op.value else: raise ModelValidationError( f"Unsupported path for update '{op.path}'") elif op.operation == "reload": do_reload = True else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") if kwargs: response = await self.client( Operation(operation_type="SYSTEM_UPDATE", args=[system_id], kwargs=kwargs)) if do_reload: await self.client( Operation(operation_type="SYSTEM_RELOAD", args=[system_id])) self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self, request_id): """ --- summary: Partially update a Request description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operation supported is `replace`, with paths `/status`, `/output`, and `/error_class`: ```JSON [ { "operation": "replace", "path": "/status", "value": "" }, { "operation": "replace", "path": "/output", "value": "" }, { "operation": "replace", "path": "/error_class", "value": "" } ] ``` parameters: - name: request_id in: path required: true description: The ID of the Request type: string - name: patch in: body required: true description: Instructions for how to update the Request schema: $ref: '#/definitions/Patch' responses: 200: description: Request with the given ID schema: $ref: '#/definitions/Request' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Requests """ _ = self.get_or_raise(Request, REQUEST_UPDATE, id=request_id) operation = Operation(args=[request_id]) patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: if op.operation == "replace": if op.path == "/status": # If we get a start just assume there's no other op in patch if op.value.upper() == "IN_PROGRESS": operation.operation_type = "REQUEST_START" operation.kwargs = {} break elif op.value.upper() in BrewtilsRequest.COMPLETED_STATUSES: operation.operation_type = "REQUEST_COMPLETE" operation.kwargs["status"] = op.value else: raise ModelValidationError( f"Unsupported status value '{op.value}'" ) elif op.path == "/output": operation.kwargs["output"] = op.value elif op.path == "/error_class": operation.kwargs["error_class"] = op.value else: raise ModelValidationError(f"Unsupported path '{op.path}'") else: raise ModelValidationError(f"Unsupported operation '{op.operation}'") response = await self.client(operation) self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self, garden_name): """ --- summary: Partially update a Garden description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * initializing * running * stopped * block * update ```JSON [ { "operation": "" } ] ``` parameters: - name: garden_name in: path required: true description: Garden to use type: string - name: patch in: body required: true description: Instructions for how to update the Garden schema: $ref: '#/definitions/Patch' responses: 200: description: Garden with the given garden_name schema: $ref: '#/definitions/Garden' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Garden """ patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation in ["initializing", "running", "stopped", "block"]: response = await self.client( Operation( operation_type="GARDEN_UPDATE_STATUS", args=[garden_name, operation.upper()], ) ) elif operation == "heartbeat": response = await self.client( Operation( operation_type="GARDEN_UPDATE_STATUS", args=[garden_name, "RUNNING"], ) ) elif operation == "config": response = await self.client( Operation( operation_type="GARDEN_UPDATE_CONFIG", args=[SchemaParser.parse_garden(op.value, from_string=False)], ) ) elif operation == "sync": response = await self.client( Operation( operation_type="GARDEN_SYNC", kwargs={"sync_target": garden_name}, ) ) else: raise ModelValidationError(f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
def test_patch(self, bg_patch, data, kwargs): """Parametrize for the 'many' kwarg because the parser should ignore it""" assert_patch_equal( SchemaParser.parse_patch(data, **kwargs)[0], bg_patch)
def test_parse_patch_many(patch_many_dict, bg_patch1, bg_patch2): parser = SchemaParser() patches = sorted(parser.parse_patch(patch_many_dict, many=True), key=lambda x: x.operation) for index, patch in enumerate([bg_patch1, bg_patch2]): assert_patch_equal(patch, patches[index])
def test_parse_patch(bg_patch1, data, kwargs): parser = SchemaParser() actual = parser.parse_patch(data, **kwargs)[0] assert_patch_equal(actual, bg_patch1)
async def patch(self, job_id): """ --- summary: Pause/Resume a job description: | The body of the request needs to contain a set of instructions detailing the actions to take. Currently the only operation supported is `update` with `path` of `/status`. You can pause a job with: ```JSON { "operation": "update", "path": "/status", "value": "PAUSED" } ``` And resume it with: ```JSON { "operation": "update", "path": "/status", "value": "RUNNING" } ``` parameters: - name: job_id in: path required: true description: The ID of the Job type: string - name: patch in: body required: true description: Instructions for the actions to take schema: $ref: '#/definitions/Patch' responses: 200: description: Job with the given ID schema: $ref: '#/definitions/Job' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Jobs """ patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: if op.operation == "update": if op.path == "/status": if str(op.value).upper() == "PAUSED": response = await self.client( Operation(operation_type="JOB_PAUSE", args=[job_id])) elif str(op.value).upper() == "RUNNING": response = await self.client( Operation(operation_type="JOB_RESUME", args=[job_id])) else: raise ModelValidationError( f"Unsupported status value '{op.value}'") elif op.path == "/job": response = await self.client( Operation( operation_type="JOB_UPDATE", args=[SchemaParser.parse_job(op.value)], )) else: raise ModelValidationError( f"Unsupported path value '{op.path}'") else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)
async def patch(self): """ --- summary: Partially update a Garden description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * sync * sync_users ```JSON [ { "operation": "" } ] ``` parameters: - name: garden_name in: path required: true description: Garden to use type: string - name: patch in: body required: true description: Instructions for how to update the Garden schema: $ref: '#/definitions/Patch' responses: 204: description: Patch operation has been successfully forwarded 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Garden """ self.verify_user_permission_for_object(GARDEN_UPDATE, local_garden()) patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation == "sync": await self.client(Operation(operation_type="GARDEN_SYNC", )) elif operation == "sync_users": # requires GARDEN_UPDATE for all gardens for garden in Garden.objects.all(): self.verify_user_permission_for_object( GARDEN_UPDATE, garden) initiate_user_sync() else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_status(204)
async def patch(self, runner_id): """ --- summary: Partially update a Runner description: | The body of the request needs to contain a set of instructions detailing the updates to apply. Currently the only operations are: * start * stop ```JSON [ { "operation": "" } ] ``` parameters: - name: runner_id in: path required: true description: The ID of the Instance type: string - name: patch in: body required: true description: Instructions for how to update the Runner schema: $ref: '#/definitions/Patch' responses: 200: description: Runner with the given ID schema: $ref: '#/definitions/Runner' 400: $ref: '#/definitions/400Error' 404: $ref: '#/definitions/404Error' 50x: $ref: '#/definitions/50xError' tags: - Runners """ patch = SchemaParser.parse_patch(self.request.decoded_body, from_string=True) for op in patch: operation = op.operation.lower() if operation == "start": response = await self.client( Operation(operation_type="RUNNER_START", kwargs={"runner_id": runner_id})) elif operation == "stop": response = await self.client( Operation( operation_type="RUNNER_STOP", kwargs={"runner_id": runner_id}, )) else: raise ModelValidationError( f"Unsupported operation '{op.operation}'") self.set_header("Content-Type", "application/json; charset=UTF-8") self.write(response)