diff --git a/CHANGELOG.md b/CHANGELOG.md index e2834f9d..f38cd88a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `POST /_plugins/_ml/memory`, `POST /_plugins/_ml/memory/_search`, `{memory_id}/_search`, `{memory_id}/messages`, `PUT /_plugins/_ml/memory/{memory_id}`, `message/{message_id}`, `GET /_plugins/_ml/memory`, `GET /_plugins/_ml/memory/{memory_id}`, `_search`, `message/{message_id}`, `{memory_id}/messages`, `{memory_id}/_search`, `message/{message_id}/traces`, and `DELETE /_plugins/_ml/memory/{memory_id}` ([#771](https://github.com/opensearch-project/opensearch-api-specification/pull/771)) - Added support for evaluating response payloads in prologues and epilogues ([#772](https://github.com/opensearch-project/opensearch-api-specification/pull/772)) - Added `GET /_plugins/_ml/models/{model_id}`, `POST /_plugins/_ml/models/_search`, `POST /_plugins/_ml/models/_unload`, `_undeploy`, `_upload`, `meta`, `_register_meta`, `POST /_plugins/_ml/models/{model_id}/_load`, `_predict`, `_unload`, `chunk/{chunk_number}`, `upload_chunk/{chunk_number}`, and `PUT /_plugins/_ml/models/{model_id}` ([#733](https://github.com/opensearch-project/opensearch-api-specification/pull/733)) +- Added `GET`, `POST`, `PUT`, `DELETE /_plugins/_ml/controllers/{model_id}` ([#779](https://github.com/opensearch-project/opensearch-api-specification/pull/779)) ### Removed - Removed unsupported `_common.mapping:SourceField`'s `mode` field and associated `_common.mapping:SourceFieldMode` enum ([#652](https://github.com/opensearch-project/opensearch-api-specification/pull/652)) diff --git a/spec/namespaces/ml.yaml b/spec/namespaces/ml.yaml index bae59a07..06f16daf 100644 --- a/spec/namespaces/ml.yaml +++ b/spec/namespaces/ml.yaml @@ -585,6 +585,51 @@ paths: responses: '200': $ref: '#/components/responses/ml.get_message_traces@200' + /_plugins/_ml/controllers/{model_id}: + get: + operationId: ml.get_controller.0 + x-operation-group: ml.get_controller + x-version-added: '2.12' + description: Retrieves a controller. + parameters: + - $ref: '#/components/parameters/ml.get_controller::path.model_id' + responses: + '200': + $ref: '#/components/responses/ml.get_controller@200' + post: + operationId: ml.create_controller.0 + x-operation-group: ml.create_controller + x-version-added: '2.12' + description: Creates a controller. + requestBody: + $ref: '#/components/requestBodies/ml.create_controller' + parameters: + - $ref: '#/components/parameters/ml.create_controller::path.model_id' + responses: + '200': + $ref: '#/components/responses/ml.create_controller@200' + put: + operationId: ml.update_controller.0 + x-operation-group: ml.update_controller + x-version-added: '2.12' + description: Updates a controller. + requestBody: + $ref: '#/components/requestBodies/ml.update_controller' + parameters: + - $ref: '#/components/parameters/ml.update_controller::path.model_id' + responses: + '200': + $ref: '#/components/responses/ml.update_controller@200' + delete: + operationId: ml.delete_controller.0 + x-operation-group: ml.delete_controller + x-version-added: '2.12' + description: Deletes a controller. + parameters: + - $ref: '#/components/parameters/ml.delete_controller::path.model_id' + responses: + '200': + $ref: '#/components/responses/ml.delete_controller@200' components: requestBodies: ml.register_model_group: @@ -1171,6 +1216,24 @@ components: items: $ref: '../schemas/ml._common.yaml#/components/schemas/SortMessage' description: The sort order. + ml.create_controller: + content: + application/json: + schema: + type: object + properties: + user_rate_limiter: + $ref: '../schemas/ml._common.yaml#/components/schemas/UserRateLimiter' + ml.update_controller: + content: + application/json: + schema: + type: object + properties: + user_rate_limiter: + $ref: '../schemas/ml._common.yaml#/components/schemas/UserRateLimiter' + model_id: + $ref: '../schemas/_common.yaml#/components/schemas/Name' responses: ml.register_model_group@200: content: @@ -1478,6 +1541,36 @@ components: application/json: schema: $ref: '../schemas/ml._common.yaml#/components/schemas/GetMessageTracesResponse' + ml.get_controller@200: + content: + application/json: + schema: + type: object + properties: + user_rate_limiter: + $ref: '../schemas/ml._common.yaml#/components/schemas/UserRateLimiter' + model_id: + $ref: '../schemas/_common.yaml#/components/schemas/Name' + ml.create_controller@200: + content: + application/json: + schema: + type: object + properties: + model_id: + $ref: '../schemas/_common.yaml#/components/schemas/Name' + status: + $ref: '../schemas/ml._common.yaml#/components/schemas/Status' + ml.update_controller@200: + content: + application/json: + schema: + $ref: '../schemas/_common.yaml#/components/schemas/WriteResponseBase' + ml.delete_controller@200: + content: + application/json: + schema: + $ref: '../schemas/_common.yaml#/components/schemas/WriteResponseBase' parameters: ml.get_model_group::path.model_group_id: name: model_group_id @@ -1683,5 +1776,29 @@ components: name: message_id in: path required: true + schema: + type: string + ml.get_controller::path.model_id: + name: model_id + in: path + required: true + schema: + type: string + ml.create_controller::path.model_id: + name: model_id + in: path + required: true + schema: + type: string + ml.update_controller::path.model_id: + name: model_id + in: path + required: true + schema: + type: string + ml.delete_controller::path.model_id: + name: model_id + in: path + required: true schema: type: string \ No newline at end of file diff --git a/spec/schemas/ml._common.yaml b/spec/schemas/ml._common.yaml index 281fe255..3a043bb6 100644 --- a/spec/schemas/ml._common.yaml +++ b/spec/schemas/ml._common.yaml @@ -1233,4 +1233,27 @@ components: traces: type: array items: - $ref: '#/components/schemas/Message' \ No newline at end of file + $ref: '#/components/schemas/Message' + UserRateLimiter: + type: object + properties: + user1: + $ref: '#/components/schemas/User' + additionalProperties: true + User: + type: object + properties: + limit: + type: [integer, string] + description: Max Predict API calls per user per time unit. + unit: + type: string + description: The unit of time. + enum: + - DAYS + - HOURS + - MICROSECONDS + - MILLISECONDS + - MINUTES + - NANOSECONDS + - SECONDS \ No newline at end of file diff --git a/tests/plugins/ml/ml/controller/create.yaml b/tests/plugins/ml/ml/controller/create.yaml new file mode 100644 index 00000000..2e1f6d30 --- /dev/null +++ b/tests/plugins/ml/ml/controller/create.yaml @@ -0,0 +1,65 @@ +$schema: ../../../../../json_schemas/test_story.schema.yaml + +description: Test the creation of a controller. +version: '>= 2.12' +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id + - path: /_plugins/_ml/tasks/{task_id} + id: get_completed_task + method: GET + parameters: + task_id: ${register_model.task_id} + retry: + count: 3 + wait: 10000 + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id +epilogues: + - path: /_plugins/_ml/controllers/{model_id} + parameters: + model_id: ${create_controller.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/tasks/{task_id} + parameters: + task_id: ${register_model.task_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Create a controller. + id: create_controller + path: /_plugins/_ml/controllers/{model_id} + method: POST + parameters: + model_id: ${get_completed_task.model_id} + request: + payload: + user_rate_limiter: + user1: + limit: 4 + unit: MINUTES + user2: + limit: 4 + unit: MINUTES + response: + status: 200 + output: + model_id: payload.model_id diff --git a/tests/plugins/ml/ml/controller/delete.yaml b/tests/plugins/ml/ml/controller/delete.yaml new file mode 100644 index 00000000..9e7426aa --- /dev/null +++ b/tests/plugins/ml/ml/controller/delete.yaml @@ -0,0 +1,69 @@ +$schema: ../../../../../json_schemas/test_story.schema.yaml + +description: Test the deletion of a controller. +version: '>= 2.12' +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id + - path: /_plugins/_ml/tasks/{task_id} + id: get_completed_task + method: GET + parameters: + task_id: ${register_model.task_id} + retry: + count: 3 + wait: 10000 + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + - path: /_plugins/_ml/controllers/{model_id} + id: create_controller + method: POST + parameters: + model_id: ${get_completed_task.model_id} + request: + payload: + user_rate_limiter: + user1: + limit: 4 + unit: MINUTES + user2: + limit: 4 + unit: MINUTES + output: + model_id: payload.model_id +epilogues: + - path: /_plugins/_ml/controllers/{model_id} + parameters: + model_id: ${create_controller.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/tasks/{task_id} + parameters: + task_id: ${register_model.task_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Delete a controller. + path: /_plugins/_ml/controllers/{model_id} + method: DELETE + parameters: + model_id: ${create_controller.model_id} + response: + status: 200 \ No newline at end of file diff --git a/tests/plugins/ml/ml/controller/get.yaml b/tests/plugins/ml/ml/controller/get.yaml new file mode 100644 index 00000000..0707953c --- /dev/null +++ b/tests/plugins/ml/ml/controller/get.yaml @@ -0,0 +1,69 @@ +$schema: ../../../../../json_schemas/test_story.schema.yaml + +description: Test the retrieval of a controller. +version: '>= 2.12' +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id + - path: /_plugins/_ml/tasks/{task_id} + id: get_completed_task + method: GET + parameters: + task_id: ${register_model.task_id} + retry: + count: 3 + wait: 10000 + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + - path: /_plugins/_ml/controllers/{model_id} + id: create_controller + method: POST + parameters: + model_id: ${get_completed_task.model_id} + request: + payload: + user_rate_limiter: + user1: + limit: 4 + unit: MINUTES + user2: + limit: 4 + unit: MINUTES + output: + model_id: payload.model_id +epilogues: + - path: /_plugins/_ml/controllers/{model_id} + parameters: + model_id: ${create_controller.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/tasks/{task_id} + parameters: + task_id: ${register_model.task_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Get a controller. + path: /_plugins/_ml/controllers/{model_id} + method: GET + parameters: + model_id: ${create_controller.model_id} + response: + status: 200 \ No newline at end of file diff --git a/tests/plugins/ml/ml/controller/update.yaml b/tests/plugins/ml/ml/controller/update.yaml new file mode 100644 index 00000000..a259d74b --- /dev/null +++ b/tests/plugins/ml/ml/controller/update.yaml @@ -0,0 +1,75 @@ +$schema: ../../../../../json_schemas/test_story.schema.yaml + +description: Test updating a controller. +version: '>= 2.12' +prologues: + - path: /_plugins/_ml/models/_register + id: register_model + method: POST + request: + payload: + name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b + version: 1.0.1 + model_format: TORCH_SCRIPT + output: + task_id: payload.task_id + - path: /_plugins/_ml/tasks/{task_id} + id: get_completed_task + method: GET + parameters: + task_id: ${register_model.task_id} + retry: + count: 3 + wait: 10000 + response: + status: 200 + payload: + state: COMPLETED + output: + model_id: payload.model_id + - path: /_plugins/_ml/controllers/{model_id} + id: create_controller + method: POST + parameters: + model_id: ${get_completed_task.model_id} + request: + payload: + user_rate_limiter: + user1: + limit: 4 + unit: MINUTES + user2: + limit: 4 + unit: MINUTES + output: + model_id: payload.model_id +epilogues: + - path: /_plugins/_ml/controllers/{model_id} + parameters: + model_id: ${create_controller.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/models/{model_id} + parameters: + model_id: ${get_completed_task.model_id} + method: DELETE + status: [200, 404] + - path: /_plugins/_ml/tasks/{task_id} + parameters: + task_id: ${register_model.task_id} + method: DELETE + status: [200, 404] +chapters: + - synopsis: Update a controller. + path: /_plugins/_ml/controllers/{model_id} + method: PUT + parameters: + model_id: ${create_controller.model_id} + request: + payload: + user_rate_limiter: + user1: + limit: 6 + unit: MINUTES + response: + status: 200