From 874682f18df1463b5e81be7fae61678a75a420db Mon Sep 17 00:00:00 2001 From: Reid Mello <30907815+rjmello@users.noreply.github.com> Date: Wed, 13 Nov 2024 15:38:24 -0500 Subject: [PATCH 1/2] Add `ComputeClientV2` methods to manage endpoints Added `.register_endpoint()`, `.get_endpoint()`, `.get_endpoint_status()` `.get_endpoints()`, `.delete_endpoint()`, and `.lock_endpoint()` methods to the `ComputeClientV2` class. --- .../_testing/data/compute/_common.py | 5 ++ .../data/compute/v2/delete_endpoint.py | 13 +++ .../_testing/data/compute/v2/get_endpoint.py | 37 ++++++++ .../data/compute/v2/get_endpoint_status.py | 24 +++++ .../_testing/data/compute/v2/get_endpoints.py | 28 ++++++ .../_testing/data/compute/v2/lock_endpoint.py | 18 ++++ .../data/compute/v2/register_endpoint.py | 29 ++++++ src/globus_sdk/services/compute/client.py | 88 +++++++++++++++++++ .../compute/v2/test_delete_endpoint.py | 9 ++ .../services/compute/v2/test_get_endpoint.py | 9 ++ .../compute/v2/test_get_endpoint_status.py | 9 ++ .../services/compute/v2/test_get_endpoints.py | 12 +++ .../services/compute/v2/test_lock_endpoint.py | 11 +++ .../compute/v2/test_register_endpoint.py | 39 ++++++++ 14 files changed, 331 insertions(+) create mode 100644 src/globus_sdk/_testing/data/compute/v2/delete_endpoint.py create mode 100644 src/globus_sdk/_testing/data/compute/v2/get_endpoint.py create mode 100644 src/globus_sdk/_testing/data/compute/v2/get_endpoint_status.py create mode 100644 src/globus_sdk/_testing/data/compute/v2/get_endpoints.py create mode 100644 src/globus_sdk/_testing/data/compute/v2/lock_endpoint.py create mode 100644 src/globus_sdk/_testing/data/compute/v2/register_endpoint.py create mode 100644 tests/functional/services/compute/v2/test_delete_endpoint.py create mode 100644 tests/functional/services/compute/v2/test_get_endpoint.py create mode 100644 tests/functional/services/compute/v2/test_get_endpoint_status.py create mode 100644 tests/functional/services/compute/v2/test_get_endpoints.py create mode 100644 tests/functional/services/compute/v2/test_lock_endpoint.py create mode 100644 tests/functional/services/compute/v2/test_register_endpoint.py diff --git a/src/globus_sdk/_testing/data/compute/_common.py b/src/globus_sdk/_testing/data/compute/_common.py index ffdaac95..9e48a76e 100644 --- a/src/globus_sdk/_testing/data/compute/_common.py +++ b/src/globus_sdk/_testing/data/compute/_common.py @@ -1,6 +1,11 @@ import uuid +USER_ID = str(uuid.uuid1()) + +SUBSCRIPTION_ID = str(uuid.uuid1()) + ENDPOINT_ID = str(uuid.uuid1()) +ENDPOINT_ID_2 = str(uuid.uuid1()) FUNCTION_ID = str(uuid.uuid1()) FUNCTION_NAME = "howdy_world" diff --git a/src/globus_sdk/_testing/data/compute/v2/delete_endpoint.py b/src/globus_sdk/_testing/data/compute/v2/delete_endpoint.py new file mode 100644 index 00000000..e297ebc1 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/delete_endpoint.py @@ -0,0 +1,13 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID}, + default=RegisteredResponse( + service="compute", + path=f"/v2/endpoints/{ENDPOINT_ID}", + method="DELETE", + json={"result": 302}, + ), +) diff --git a/src/globus_sdk/_testing/data/compute/v2/get_endpoint.py b/src/globus_sdk/_testing/data/compute/v2/get_endpoint.py new file mode 100644 index 00000000..8895fb25 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/get_endpoint.py @@ -0,0 +1,37 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID, SUBSCRIPTION_ID + +ENDPOINT_CONFIG = """ +display_name: My Endpoint +engine: + type: GlobusComputeEngine +""" + +DEFAULT_RESPONSE_DOC = { + "uuid": ENDPOINT_ID, + "name": "my-endpoint", + "display_name": "My Endpoint", + "multi_user": False, + "public": False, + "endpoint_config": ENDPOINT_CONFIG.strip(), + "user_config_template": "", + "user_config_schema": {}, + "description": "My endpoint description", + "hostname": "my-hostname", + "local_user": "user1", + "ip_address": "140.221.112.13", + "endpoint_version": "2.31.0", + "sdk_version": "2.31.0", + "subscription_uuid": SUBSCRIPTION_ID, +} + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID}, + default=RegisteredResponse( + service="compute", + path=f"/v2/endpoints/{ENDPOINT_ID}", + method="GET", + json=DEFAULT_RESPONSE_DOC, + ), +) diff --git a/src/globus_sdk/_testing/data/compute/v2/get_endpoint_status.py b/src/globus_sdk/_testing/data/compute/v2/get_endpoint_status.py new file mode 100644 index 00000000..551b32d8 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/get_endpoint_status.py @@ -0,0 +1,24 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID + +DEFAULT_RESPONSE_DOC = { + "status": "online", + "details": { + "total_workers": 1, + "idle_workers": 0, + "pending_tasks": 0, + "outstanding_tasks": 0, + "managers": 1, + }, +} + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID}, + default=RegisteredResponse( + service="compute", + path=f"/v2/endpoints/{ENDPOINT_ID}/status", + method="GET", + json=DEFAULT_RESPONSE_DOC, + ), +) diff --git a/src/globus_sdk/_testing/data/compute/v2/get_endpoints.py b/src/globus_sdk/_testing/data/compute/v2/get_endpoints.py new file mode 100644 index 00000000..a98205b8 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/get_endpoints.py @@ -0,0 +1,28 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID, ENDPOINT_ID_2, USER_ID + +DEFAULT_RESPONSE_DOC = [ + { + "uuid": ENDPOINT_ID, + "name": "my-endpoint", + "display_name": "My Endpoint", + "owner": USER_ID, + }, + { + "uuid": ENDPOINT_ID_2, + "name": "my-second-endpoint", + "display_name": "My Second Endpoint", + "owner": USER_ID, + }, +] + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID, "endpoint_id_2": ENDPOINT_ID_2}, + default=RegisteredResponse( + service="compute", + path="/v2/endpoints", + method="GET", + json=DEFAULT_RESPONSE_DOC, + ), +) diff --git a/src/globus_sdk/_testing/data/compute/v2/lock_endpoint.py b/src/globus_sdk/_testing/data/compute/v2/lock_endpoint.py new file mode 100644 index 00000000..acb12e33 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/lock_endpoint.py @@ -0,0 +1,18 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID + +DEFAULT_RESPONSE_DOC = { + "endpoint_id": ENDPOINT_ID, + "lock_expiration_timestamp": "2021-07-01T00:00:00.000000", +} + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID}, + default=RegisteredResponse( + service="compute", + path=f"/v2/endpoints/{ENDPOINT_ID}/lock", + method="POST", + json=DEFAULT_RESPONSE_DOC, + ), +) diff --git a/src/globus_sdk/_testing/data/compute/v2/register_endpoint.py b/src/globus_sdk/_testing/data/compute/v2/register_endpoint.py new file mode 100644 index 00000000..a6d73dc2 --- /dev/null +++ b/src/globus_sdk/_testing/data/compute/v2/register_endpoint.py @@ -0,0 +1,29 @@ +from globus_sdk._testing.models import RegisteredResponse, ResponseSet + +from .._common import ENDPOINT_ID + +DEFAULT_RESPONSE_DOC = { + "endpoint_id": ENDPOINT_ID, + "task_queue_info": { + "connection_url": "amqps://user:password@mq.fqdn", + "exchange": "some_exchange", + "queue": "some_queue", + }, + "result_queue_info": { + "connection_url": "amqps://user:password@mq.fqdn", + "exchange": "some_exchange", + "queue": "some_queue", + "queue_publish_kwargs": {}, + }, + "warnings": [], +} + +RESPONSES = ResponseSet( + metadata={"endpoint_id": ENDPOINT_ID}, + default=RegisteredResponse( + service="compute", + path="/v2/endpoints", + method="POST", + json=DEFAULT_RESPONSE_DOC, + ), +) diff --git a/src/globus_sdk/services/compute/client.py b/src/globus_sdk/services/compute/client.py index 5ed3fc85..d2f641a6 100644 --- a/src/globus_sdk/services/compute/client.py +++ b/src/globus_sdk/services/compute/client.py @@ -24,6 +24,94 @@ class ComputeClientV2(client.BaseClient): scopes = ComputeScopes default_scope_requirements = [Scope(ComputeScopes.all)] + def register_endpoint(self, data: dict[str, t.Any]) -> GlobusHTTPResponse: + """Register a new endpoint. + + :param data: An endpoint registration document. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Register Endpoint + :service: compute + :ref: Endpoints/operation/register_endpoint_v2_endpoints_post + """ + return self.post("/v2/endpoints", data=data) + + def get_endpoint(self, endpoint_id: UUIDLike) -> GlobusHTTPResponse: + """Get information about a registered endpoint. + + :param endpoint_id: The ID of the Globus Compute endpoint. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Get Endpoint + :service: compute + :ref: Endpoints/operation/get_endpoint_v2_endpoints__endpoint_uuid__get + """ # noqa: E501 + return self.get(f"/v2/endpoints/{endpoint_id}") + + def get_endpoint_status(self, endpoint_id: UUIDLike) -> GlobusHTTPResponse: + """Get the status of a registered endpoint. + + :param endpoint_id: The ID of the Globus Compute endpoint. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Get Endpoint Status + :service: compute + :ref: Endpoints/operation/get_endpoint_status_v2_endpoints__endpoint_uuid__status_get + """ # noqa: E501 + return self.get(f"/v2/endpoints/{endpoint_id}/status") + + def get_endpoints(self) -> GlobusHTTPResponse: + """Get a list of registered endpoints associated with the authenticated user. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Get Endpoints + :service: compute + :ref: Endpoints/operation/get_endpoints_v2_endpoints_get + """ # noqa: E501 + return self.get("/v2/endpoints") + + def delete_endpoint(self, endpoint_id: UUIDLike) -> GlobusHTTPResponse: + """Delete a registered endpoint. + + :param endpoint_id: The ID of the Globus Compute endpoint. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Delete Endpoint + :service: compute + :ref: Endpoints/operation/delete_endpoint_v2_endpoints__endpoint_uuid__delete + """ # noqa: E501 + return self.delete(f"/v2/endpoints/{endpoint_id}") + + def lock_endpoint(self, endpoint_id: UUIDLike) -> GlobusHTTPResponse: + """Temporarily block registration requests for the endpoint. + + :param endpoint_id: The ID of the Globus Compute endpoint. + + .. tab-set:: + + .. tab-item:: API Info + + .. extdoclink:: Delete Endpoint + :service: compute + :ref: Endpoints/operation/lock_endpoint_v2_endpoints__endpoint_uuid__lock_post + """ # noqa: E501 + return self.post(f"/v2/endpoints/{endpoint_id}/lock") + def register_function( self, function_data: dict[str, t.Any], diff --git a/tests/functional/services/compute/v2/test_delete_endpoint.py b/tests/functional/services/compute/v2/test_delete_endpoint.py new file mode 100644 index 00000000..0ab61908 --- /dev/null +++ b/tests/functional/services/compute/v2/test_delete_endpoint.py @@ -0,0 +1,9 @@ +import globus_sdk +from globus_sdk._testing import load_response + + +def test_delete_endpoint(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.delete_endpoint).metadata + res = compute_client_v2.delete_endpoint(endpoint_id=meta["endpoint_id"]) + assert res.http_status == 200 + assert res.data == {"result": 302} diff --git a/tests/functional/services/compute/v2/test_get_endpoint.py b/tests/functional/services/compute/v2/test_get_endpoint.py new file mode 100644 index 00000000..58dd9801 --- /dev/null +++ b/tests/functional/services/compute/v2/test_get_endpoint.py @@ -0,0 +1,9 @@ +import globus_sdk +from globus_sdk._testing import load_response + + +def test_get_endpoint(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.get_endpoint).metadata + res = compute_client_v2.get_endpoint(endpoint_id=meta["endpoint_id"]) + assert res.http_status == 200 + assert res.data["uuid"] == meta["endpoint_id"] diff --git a/tests/functional/services/compute/v2/test_get_endpoint_status.py b/tests/functional/services/compute/v2/test_get_endpoint_status.py new file mode 100644 index 00000000..487530e6 --- /dev/null +++ b/tests/functional/services/compute/v2/test_get_endpoint_status.py @@ -0,0 +1,9 @@ +import globus_sdk +from globus_sdk._testing import load_response + + +def test_get_endpoint_status(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.get_endpoint_status).metadata + res = compute_client_v2.get_endpoint_status(endpoint_id=meta["endpoint_id"]) + assert res.http_status == 200 + assert res.data["status"] == "online" diff --git a/tests/functional/services/compute/v2/test_get_endpoints.py b/tests/functional/services/compute/v2/test_get_endpoints.py new file mode 100644 index 00000000..058aff78 --- /dev/null +++ b/tests/functional/services/compute/v2/test_get_endpoints.py @@ -0,0 +1,12 @@ +import globus_sdk +from globus_sdk._testing import load_response + + +def test_get_endpoints(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.get_endpoints).metadata + + res = compute_client_v2.get_endpoints() + + assert res.http_status == 200 + assert res.data[0]["uuid"] == meta["endpoint_id"] + assert res.data[1]["uuid"] == meta["endpoint_id_2"] diff --git a/tests/functional/services/compute/v2/test_lock_endpoint.py b/tests/functional/services/compute/v2/test_lock_endpoint.py new file mode 100644 index 00000000..1848212a --- /dev/null +++ b/tests/functional/services/compute/v2/test_lock_endpoint.py @@ -0,0 +1,11 @@ +import globus_sdk +from globus_sdk._testing import load_response + + +def test_lock_endpoint(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.lock_endpoint).metadata + + res = compute_client_v2.lock_endpoint(endpoint_id=meta["endpoint_id"]) + + assert res.http_status == 200 + assert res.data["endpoint_id"] == meta["endpoint_id"] diff --git a/tests/functional/services/compute/v2/test_register_endpoint.py b/tests/functional/services/compute/v2/test_register_endpoint.py new file mode 100644 index 00000000..6d9d094f --- /dev/null +++ b/tests/functional/services/compute/v2/test_register_endpoint.py @@ -0,0 +1,39 @@ +import uuid + +import globus_sdk +from globus_sdk._testing import load_response + +ENDPOINT_CONFIG = """ +display_name: My Endpoint +engine: + type: GlobusComputeEngine +""" + + +def test_register_endpoint(compute_client_v2: globus_sdk.ComputeClientV2): + meta = load_response(compute_client_v2.register_endpoint).metadata + register_doc = { + "endpoint_uuid": meta["endpoint_id"], + "endpoint_name": "my-endpoint", + "display_name": "My Endpoint", + "version": "2.31.0", + "multi_user": False, + "allowed_functions": [str(uuid.uuid1())], + "authentication_policy": str(uuid.uuid1()), + "metadata": { + "endpoint_config": ENDPOINT_CONFIG.strip(), + "user_config_template": "", + "user_config_schema": {}, + "description": "My endpoint description", + "ip_address": "140.221.112.13", + "hostname": "my-hostname", + "local_user": "user1", + "sdk_version": "2.31.0", + "endpoint_version": "2.31.0", + }, + } + + res = compute_client_v2.register_endpoint(data=register_doc) + + assert res.http_status == 200 + assert res.data["endpoint_id"] == meta["endpoint_id"] From 077e0e27db068c40158f09f9867048f585cffc0f Mon Sep 17 00:00:00 2001 From: Reid Mello <30907815+rjmello@users.noreply.github.com> Date: Thu, 14 Nov 2024 14:39:14 -0500 Subject: [PATCH 2/2] Add changelog for `ComputeClientV2` endpoint methods --- ...30907815+rjmello_compute_client_endpoint_methods_v2.rst | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 changelog.d/20241114_142914_30907815+rjmello_compute_client_endpoint_methods_v2.rst diff --git a/changelog.d/20241114_142914_30907815+rjmello_compute_client_endpoint_methods_v2.rst b/changelog.d/20241114_142914_30907815+rjmello_compute_client_endpoint_methods_v2.rst new file mode 100644 index 00000000..d1f2a0a0 --- /dev/null +++ b/changelog.d/20241114_142914_30907815+rjmello_compute_client_endpoint_methods_v2.rst @@ -0,0 +1,7 @@ +Added +~~~~~ + +- Added the ``ComputeClientV2.register_endpoint()``, ``ComputeClientV2.get_endpoint()`` + ``ComputeClientV2.get_endpoint_status()``, ``ComputeClientV2.get_endpoints()``, + ``ComputeClientV2.delete_endpoint()``, and ``ComputeClientV2.lock_endpoint()`` + methods. (:pr:`NUMBER`) \ No newline at end of file