proximl 0.5.5__py3-none-any.whl → 0.5.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,129 @@
1
+ import click
2
+ from proximl.cli import cli, pass_config, search_by_id_name
3
+ from proximl.cli.cloudbender import cloudbender
4
+
5
+
6
+ @cloudbender.group()
7
+ @pass_config
8
+ def service(config):
9
+ """proxiML CloudBender service commands."""
10
+ pass
11
+
12
+
13
+ @service.command()
14
+ @click.option(
15
+ "--provider",
16
+ "-p",
17
+ type=click.STRING,
18
+ required=True,
19
+ help="The provider ID of the region.",
20
+ )
21
+ @click.option(
22
+ "--region",
23
+ "-r",
24
+ type=click.STRING,
25
+ required=True,
26
+ help="The region ID to list services for.",
27
+ )
28
+ @pass_config
29
+ def list(config, provider, region):
30
+ """List services."""
31
+ data = [
32
+ ["ID", "NAME", "HOSTNAME"],
33
+ [
34
+ "-" * 80,
35
+ "-" * 80,
36
+ "-" * 80,
37
+ ],
38
+ ]
39
+
40
+ services = config.proximl.run(
41
+ config.proximl.client.cloudbender.services.list(
42
+ provider_uuid=provider, region_uuid=region
43
+ )
44
+ )
45
+
46
+ for service in services:
47
+ data.append(
48
+ [
49
+ service.id,
50
+ service.name,
51
+ service.hostname,
52
+ ]
53
+ )
54
+
55
+ for row in data:
56
+ click.echo(
57
+ "{: >25.24} {: >29.28} {: >40.39}" "".format(*row),
58
+ file=config.stdout,
59
+ )
60
+
61
+
62
+ @service.command()
63
+ @click.option(
64
+ "--provider",
65
+ "-p",
66
+ type=click.STRING,
67
+ required=True,
68
+ help="The provider ID of the region.",
69
+ )
70
+ @click.option(
71
+ "--region",
72
+ "-r",
73
+ type=click.STRING,
74
+ required=True,
75
+ help="The region ID to create the service in.",
76
+ )
77
+ @click.option(
78
+ "--public/--no-public",
79
+ default=True,
80
+ show_default=True,
81
+ help="Service should be accessible from the public internet.",
82
+ )
83
+ @click.argument("name", type=click.STRING, required=True)
84
+ @pass_config
85
+ def create(config, provider, region, public, name):
86
+ """
87
+ Creates a service.
88
+ """
89
+ return config.proximl.run(
90
+ config.proximl.client.cloudbender.services.create(
91
+ provider_uuid=provider, region_uuid=region, name=name, public=public
92
+ )
93
+ )
94
+
95
+
96
+ @service.command()
97
+ @click.option(
98
+ "--provider",
99
+ "-p",
100
+ type=click.STRING,
101
+ required=True,
102
+ help="The provider ID of the region.",
103
+ )
104
+ @click.option(
105
+ "--region",
106
+ "-r",
107
+ type=click.STRING,
108
+ required=True,
109
+ help="The region ID to remove the service from.",
110
+ )
111
+ @click.argument("service", type=click.STRING)
112
+ @pass_config
113
+ def remove(config, provider, region, service):
114
+ """
115
+ Remove a service.
116
+
117
+ RESERVATION may be specified by name or ID, but ID is preferred.
118
+ """
119
+ services = config.proximl.run(
120
+ config.proximl.client.cloudbender.services.list(
121
+ provider_uuid=provider, region_uuid=region
122
+ )
123
+ )
124
+
125
+ found = search_by_id_name(service, services)
126
+ if None is found:
127
+ raise click.UsageError("Cannot find specified service.")
128
+
129
+ return config.proximl.run(found.remove())
@@ -0,0 +1,115 @@
1
+ import json
2
+ import logging
3
+
4
+
5
+ class Services(object):
6
+ def __init__(self, proximl):
7
+ self.proximl = proximl
8
+
9
+ async def get(self, provider_uuid, region_uuid, id, **kwargs):
10
+ resp = await self.proximl._query(
11
+ f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
12
+ "GET",
13
+ kwargs,
14
+ )
15
+ return Service(self.proximl, **resp)
16
+
17
+ async def list(self, provider_uuid, region_uuid, **kwargs):
18
+ resp = await self.proximl._query(
19
+ f"/provider/{provider_uuid}/region/{region_uuid}/service",
20
+ "GET",
21
+ kwargs,
22
+ )
23
+ services = [Service(self.proximl, **service) for service in resp]
24
+ return services
25
+
26
+ async def create(
27
+ self,
28
+ provider_uuid,
29
+ region_uuid,
30
+ name,
31
+ public,
32
+ **kwargs,
33
+ ):
34
+ logging.info(f"Creating Service {name}")
35
+ data = dict(
36
+ name=name,
37
+ public=public,
38
+ **kwargs,
39
+ )
40
+ payload = {k: v for k, v in data.items() if v is not None}
41
+ resp = await self.proximl._query(
42
+ f"/provider/{provider_uuid}/region/{region_uuid}/service",
43
+ "POST",
44
+ None,
45
+ payload,
46
+ )
47
+ service = Service(self.proximl, **resp)
48
+ logging.info(f"Created Service {name} with id {service.id}")
49
+ return service
50
+
51
+ async def remove(self, provider_uuid, region_uuid, id, **kwargs):
52
+ await self.proximl._query(
53
+ f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
54
+ "DELETE",
55
+ kwargs,
56
+ )
57
+
58
+
59
+ class Service:
60
+ def __init__(self, proximl, **kwargs):
61
+ self.proximl = proximl
62
+ self._service = kwargs
63
+ self._id = self._service.get("service_id")
64
+ self._provider_uuid = self._service.get("provider_uuid")
65
+ self._region_uuid = self._service.get("region_uuid")
66
+ self._public = self._service.get("public")
67
+ self._name = self._service.get("name")
68
+ self._hostname = self._service.get("hostname")
69
+
70
+ @property
71
+ def id(self) -> str:
72
+ return self._id
73
+
74
+ @property
75
+ def provider_uuid(self) -> str:
76
+ return self._provider_uuid
77
+
78
+ @property
79
+ def region_uuid(self) -> str:
80
+ return self._region_uuid
81
+
82
+ @property
83
+ def public(self) -> bool:
84
+ return self._public
85
+
86
+ @property
87
+ def name(self) -> str:
88
+ return self._name
89
+
90
+ @property
91
+ def hostname(self) -> str:
92
+ return self._hostname
93
+
94
+ def __str__(self):
95
+ return json.dumps({k: v for k, v in self._service.items()})
96
+
97
+ def __repr__(self):
98
+ return f"Service( proximl , **{self._service.__repr__()})"
99
+
100
+ def __bool__(self):
101
+ return bool(self._id)
102
+
103
+ async def remove(self):
104
+ await self.proximl._query(
105
+ f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
106
+ "DELETE",
107
+ )
108
+
109
+ async def refresh(self):
110
+ resp = await self.proximl._query(
111
+ f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
112
+ "GET",
113
+ )
114
+ self.__init__(self.proximl, **resp)
115
+ return self
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: proximl
3
- Version: 0.5.5
3
+ Version: 0.5.6
4
4
  Summary: proxiML client SDK and command line utilities
5
5
  Home-page: https://github.com/proxiML/python-sdk
6
6
  Author: proxiML
@@ -32,6 +32,7 @@ proximl/cli/cloudbender/node.py,sha256=xxzj68YvpRey2vZQasgYTnwv3x7TnwpuPSSf8Ma5a
32
32
  proximl/cli/cloudbender/provider.py,sha256=qhWbDK1tWi00wQWEYqGw7yGoZx0nEjV40GLHRuuE86c,1726
33
33
  proximl/cli/cloudbender/region.py,sha256=WnSkY4dXKRJ-FNaoxMfmoh6iuUx5dXCNJmEFT34Xtao,2892
34
34
  proximl/cli/cloudbender/reservation.py,sha256=xzHs5l8BbmYgKUq6kfFU-jEtRQY0j_vYnmRVcL4wwDo,3569
35
+ proximl/cli/cloudbender/service.py,sha256=YimwXQml82-PKKQIqu9Cvggo9wOKLVTJPxMvDf4pgn8,2869
35
36
  proximl/cli/job/__init__.py,sha256=s8mU2PvCWDcv4gGT3EmjHn8MIZlXBAoayoZKmnKpXnY,6545
36
37
  proximl/cli/job/create.py,sha256=sGvbenY0yxvxHo-FZVbdw8FaZx5D4ekTCjD7P4YHG4g,34288
37
38
  proximl/cloudbender/__init__.py,sha256=iE29obtC0_9f0IhRvHQcG5aY58fVhVYipTakpjAhdss,64
@@ -43,6 +44,7 @@ proximl/cloudbender/nodes.py,sha256=QeWUaWW1HNvCune1lhakcve6LJyMzOy7cjCtvyOiaTs,
43
44
  proximl/cloudbender/providers.py,sha256=cH5lCew5WCFpXYS93vuoGNWkZyx7T_mdMH6YNWp2QGs,2036
44
45
  proximl/cloudbender/regions.py,sha256=Nu1LT6nuLD8Nt-5-7_FLlxDNZoDDAY6QduTdEBqfxJA,3570
45
46
  proximl/cloudbender/reservations.py,sha256=14ImJRLWQGG7CXDYhDnOI2W8pnP6CVVG2aVpysQVN0E,3586
47
+ proximl/cloudbender/services.py,sha256=KR0EQ-BUVk1ov9Q195NsnfiSiMb9vOYD8XyxD87RRvw,3222
46
48
  tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
49
  tests/integration/conftest.py,sha256=zRWpherX-yfbpk7xqZk9bIZCyJ-dwVeszY_7kekn2M4,1134
48
50
  tests/integration/test_checkpoints_integration.py,sha256=DUA6ZlX0gsnKCEvFmWCKbKkfJG3dQG6uD8T3fgo7y0M,3230
@@ -94,9 +96,10 @@ tests/unit/cloudbender/test_nodes_unit.py,sha256=ehOHkNroiLKNTR09SbnBPpwELE72GcG
94
96
  tests/unit/cloudbender/test_providers_unit.py,sha256=y63VCqHXb4Yu8sh0kW30-ojRvv9aUa5j1jNkmb46KTc,4373
95
97
  tests/unit/cloudbender/test_regions_unit.py,sha256=9bvP268gpNyygjh1IEpSSiUt2aP6okv7QOsV1XoaIS0,6299
96
98
  tests/unit/cloudbender/test_reservations_unit.py,sha256=ICuFT5sexnLvS7taoC18yQYuDZHpBRrNuCj3Uq_Arwo,5624
97
- proximl-0.5.5.dist-info/LICENSE,sha256=ADFxLEZDxKY0j4MdyUd5GNuhQ18rnWH5rOz1ZG7yiOA,1069
98
- proximl-0.5.5.dist-info/METADATA,sha256=ddskyt_dpYJW72fTThnwbbICvztVKb0eFgM2-crCFeg,7344
99
- proximl-0.5.5.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
100
- proximl-0.5.5.dist-info/entry_points.txt,sha256=HmI311IIabkZReMCXu-nGbvIEW-KfaduAOyfiSqt5SY,63
101
- proximl-0.5.5.dist-info/top_level.txt,sha256=-TWqc9tAaxmWmW4c7uYsmzPEYUIoh6z02xxqPbv7Kys,23
102
- proximl-0.5.5.dist-info/RECORD,,
99
+ tests/unit/cloudbender/test_services_unit.py,sha256=iYaQpyCXDg77GQEIhmgiVwKX83jyvIf-4-4oya5WA_o,5043
100
+ proximl-0.5.6.dist-info/LICENSE,sha256=ADFxLEZDxKY0j4MdyUd5GNuhQ18rnWH5rOz1ZG7yiOA,1069
101
+ proximl-0.5.6.dist-info/METADATA,sha256=wS2y66puGjq7ZkG2GsyFIJWCiSjbDiA5uUdA8PzlIqw,7344
102
+ proximl-0.5.6.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
103
+ proximl-0.5.6.dist-info/entry_points.txt,sha256=HmI311IIabkZReMCXu-nGbvIEW-KfaduAOyfiSqt5SY,63
104
+ proximl-0.5.6.dist-info/top_level.txt,sha256=-TWqc9tAaxmWmW4c7uYsmzPEYUIoh6z02xxqPbv7Kys,23
105
+ proximl-0.5.6.dist-info/RECORD,,
@@ -0,0 +1,161 @@
1
+ import re
2
+ import json
3
+ import logging
4
+ from unittest.mock import AsyncMock, patch
5
+ from pytest import mark, fixture, raises
6
+ from aiohttp import WSMessage, WSMsgType
7
+
8
+ import proximl.cloudbender.services as specimen
9
+ from proximl.exceptions import (
10
+ ApiError,
11
+ SpecificationError,
12
+ ProxiMLException,
13
+ )
14
+
15
+ pytestmark = [mark.sdk, mark.unit, mark.cloudbender, mark.services]
16
+
17
+
18
+ @fixture
19
+ def services(mock_proximl):
20
+ yield specimen.Services(mock_proximl)
21
+
22
+
23
+ @fixture
24
+ def service(mock_proximl):
25
+ yield specimen.Service(
26
+ mock_proximl,
27
+ provider_uuid="1",
28
+ region_uuid="a",
29
+ service_id="x",
30
+ name="On-Prem Service",
31
+ public=False,
32
+ hostname="app1.proximl.cloud",
33
+ )
34
+
35
+
36
+ class RegionsTests:
37
+ @mark.asyncio
38
+ async def test_get_service(
39
+ self,
40
+ services,
41
+ mock_proximl,
42
+ ):
43
+ api_response = dict()
44
+ mock_proximl._query = AsyncMock(return_value=api_response)
45
+ await services.get("1234", "5687", "91011")
46
+ mock_proximl._query.assert_called_once_with(
47
+ "/provider/1234/region/5687/service/91011", "GET", {}
48
+ )
49
+
50
+ @mark.asyncio
51
+ async def test_list_services(
52
+ self,
53
+ services,
54
+ mock_proximl,
55
+ ):
56
+ api_response = dict()
57
+ mock_proximl._query = AsyncMock(return_value=api_response)
58
+ await services.list("1234", "5687")
59
+ mock_proximl._query.assert_called_once_with(
60
+ "/provider/1234/region/5687/service", "GET", {}
61
+ )
62
+
63
+ @mark.asyncio
64
+ async def test_remove_service(
65
+ self,
66
+ services,
67
+ mock_proximl,
68
+ ):
69
+ api_response = dict()
70
+ mock_proximl._query = AsyncMock(return_value=api_response)
71
+ await services.remove("1234", "4567", "8910")
72
+ mock_proximl._query.assert_called_once_with(
73
+ "/provider/1234/region/4567/service/8910", "DELETE", {}
74
+ )
75
+
76
+ @mark.asyncio
77
+ async def test_create_service(self, services, mock_proximl):
78
+ requested_config = dict(
79
+ provider_uuid="provider-id-1",
80
+ region_uuid="region-id-1",
81
+ name="On-Prem Service",
82
+ public=False,
83
+ )
84
+ expected_payload = dict(
85
+ name="On-Prem Service",
86
+ public=False,
87
+ )
88
+ api_response = {
89
+ "provider_uuid": "provider-id-1",
90
+ "region_uuid": "region-id-1",
91
+ "service_id": "service-id-1",
92
+ "name": "On-Prem Service",
93
+ "public": False,
94
+ "hostname": "app1.proximl.cloud",
95
+ "createdAt": "2020-12-31T23:59:59.000Z",
96
+ }
97
+
98
+ mock_proximl._query = AsyncMock(return_value=api_response)
99
+ response = await services.create(**requested_config)
100
+ mock_proximl._query.assert_called_once_with(
101
+ "/provider/provider-id-1/region/region-id-1/service",
102
+ "POST",
103
+ None,
104
+ expected_payload,
105
+ )
106
+ assert response.id == "service-id-1"
107
+
108
+
109
+ class serviceTests:
110
+ def test_service_properties(self, service):
111
+ assert isinstance(service.id, str)
112
+ assert isinstance(service.provider_uuid, str)
113
+ assert isinstance(service.region_uuid, str)
114
+ assert isinstance(service.public, bool)
115
+ assert isinstance(service.name, str)
116
+ assert isinstance(service.hostname, str)
117
+
118
+ def test_service_str(self, service):
119
+ string = str(service)
120
+ regex = r"^{.*\"service_id\": \"" + service.id + r"\".*}$"
121
+ assert isinstance(string, str)
122
+ assert re.match(regex, string)
123
+
124
+ def test_service_repr(self, service):
125
+ string = repr(service)
126
+ regex = r"^Service\( proximl , \*\*{.*'service_id': '" + service.id + r"'.*}\)$"
127
+ assert isinstance(string, str)
128
+ assert re.match(regex, string)
129
+
130
+ def test_service_bool(self, service, mock_proximl):
131
+ empty_service = specimen.Service(mock_proximl)
132
+ assert bool(service)
133
+ assert not bool(empty_service)
134
+
135
+ @mark.asyncio
136
+ async def test_service_remove(self, service, mock_proximl):
137
+ api_response = dict()
138
+ mock_proximl._query = AsyncMock(return_value=api_response)
139
+ await service.remove()
140
+ mock_proximl._query.assert_called_once_with(
141
+ "/provider/1/region/a/service/x", "DELETE"
142
+ )
143
+
144
+ @mark.asyncio
145
+ async def test_service_refresh(self, service, mock_proximl):
146
+ api_response = {
147
+ "provider_uuid": "provider-id-1",
148
+ "region_uuid": "region-id-1",
149
+ "service_id": "service-id-1",
150
+ "name": "On-Prem Service",
151
+ "public": False,
152
+ "hostname": "app1.proximl.cloud",
153
+ "createdAt": "2020-12-31T23:59:59.000Z",
154
+ }
155
+ mock_proximl._query = AsyncMock(return_value=api_response)
156
+ response = await service.refresh()
157
+ mock_proximl._query.assert_called_once_with(
158
+ f"/provider/1/region/a/service/x", "GET"
159
+ )
160
+ assert service.id == "service-id-1"
161
+ assert response.id == "service-id-1"