proximl 0.5.4__tar.gz → 0.5.6__tar.gz

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.
Files changed (111) hide show
  1. {proximl-0.5.4/proximl.egg-info → proximl-0.5.6}/PKG-INFO +1 -1
  2. {proximl-0.5.4 → proximl-0.5.6}/proximl/__init__.py +1 -1
  3. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/__init__.py +3 -6
  4. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/__init__.py +1 -1
  5. proximl-0.5.6/proximl/cli/cloudbender/service.py +129 -0
  6. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/project.py +10 -15
  7. proximl-0.5.6/proximl/cli/volume.py +235 -0
  8. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/cloudbender.py +2 -2
  9. proximl-0.5.4/proximl/cloudbender/reservations.py → proximl-0.5.6/proximl/cloudbender/services.py +28 -39
  10. {proximl-0.5.4 → proximl-0.5.6}/proximl/exceptions.py +21 -12
  11. {proximl-0.5.4 → proximl-0.5.6}/proximl/jobs.py +36 -39
  12. {proximl-0.5.4 → proximl-0.5.6}/proximl/projects.py +19 -30
  13. {proximl-0.5.4 → proximl-0.5.6}/proximl/proximl.py +7 -15
  14. proximl-0.5.6/proximl/volumes.py +255 -0
  15. {proximl-0.5.4 → proximl-0.5.6/proximl.egg-info}/PKG-INFO +1 -1
  16. {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/SOURCES.txt +8 -3
  17. {proximl-0.5.4 → proximl-0.5.6}/pyproject.toml +5 -6
  18. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_checkpoints_integration.py +7 -5
  19. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_datasets_integration.py +4 -5
  20. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_jobs_integration.py +40 -2
  21. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_models_integration.py +8 -10
  22. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_projects_integration.py +2 -6
  23. proximl-0.5.6/tests/integration/test_volumes_integration.py +100 -0
  24. proximl-0.5.6/tests/unit/cli/cloudbender/test_cli_reservation_unit.py +34 -0
  25. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_project_unit.py +5 -9
  26. proximl-0.5.6/tests/unit/cli/test_cli_volume_unit.py +20 -0
  27. proximl-0.5.6/tests/unit/cloudbender/test_services_unit.py +161 -0
  28. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/conftest.py +94 -21
  29. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_projects_unit.py +34 -48
  30. proximl-0.5.6/tests/unit/test_volumes_unit.py +447 -0
  31. proximl-0.5.4/proximl/cli/cloudbender/reservation.py +0 -159
  32. proximl-0.5.4/tests/unit/cli/cloudbender/test_cli_reservation_unit.py +0 -38
  33. proximl-0.5.4/tests/unit/cloudbender/test_reservations_unit.py +0 -173
  34. {proximl-0.5.4 → proximl-0.5.6}/LICENSE +0 -0
  35. {proximl-0.5.4 → proximl-0.5.6}/README.md +0 -0
  36. {proximl-0.5.4 → proximl-0.5.6}/examples/__init__.py +0 -0
  37. {proximl-0.5.4 → proximl-0.5.6}/examples/create_dataset_and_training_job.py +0 -0
  38. {proximl-0.5.4 → proximl-0.5.6}/examples/local_storage.py +0 -0
  39. {proximl-0.5.4 → proximl-0.5.6}/examples/training_inference_pipeline.py +0 -0
  40. {proximl-0.5.4 → proximl-0.5.6}/proximl/__main__.py +0 -0
  41. {proximl-0.5.4 → proximl-0.5.6}/proximl/auth.py +0 -0
  42. {proximl-0.5.4 → proximl-0.5.6}/proximl/checkpoints.py +0 -0
  43. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/checkpoint.py +0 -0
  44. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/datastore.py +0 -0
  45. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/device.py +0 -0
  46. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/node.py +0 -0
  47. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/provider.py +0 -0
  48. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/cloudbender/region.py +0 -0
  49. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/connection.py +0 -0
  50. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/dataset.py +0 -0
  51. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/environment.py +0 -0
  52. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/gpu.py +0 -0
  53. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/job/__init__.py +0 -0
  54. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/job/create.py +0 -0
  55. {proximl-0.5.4 → proximl-0.5.6}/proximl/cli/model.py +0 -0
  56. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/__init__.py +0 -0
  57. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/datastores.py +0 -0
  58. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/device_configs.py +0 -0
  59. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/devices.py +0 -0
  60. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/nodes.py +0 -0
  61. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/providers.py +0 -0
  62. {proximl-0.5.4 → proximl-0.5.6}/proximl/cloudbender/regions.py +0 -0
  63. {proximl-0.5.4 → proximl-0.5.6}/proximl/connections.py +0 -0
  64. {proximl-0.5.4 → proximl-0.5.6}/proximl/datasets.py +0 -0
  65. {proximl-0.5.4 → proximl-0.5.6}/proximl/environments.py +0 -0
  66. {proximl-0.5.4 → proximl-0.5.6}/proximl/gpu_types.py +0 -0
  67. {proximl-0.5.4 → proximl-0.5.6}/proximl/models.py +0 -0
  68. {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/dependency_links.txt +0 -0
  69. {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/entry_points.txt +0 -0
  70. {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/requires.txt +0 -0
  71. {proximl-0.5.4 → proximl-0.5.6}/proximl.egg-info/top_level.txt +0 -0
  72. {proximl-0.5.4 → proximl-0.5.6}/setup.cfg +0 -0
  73. {proximl-0.5.4 → proximl-0.5.6}/setup.py +0 -0
  74. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/__init__.py +0 -0
  75. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/cloudbender/__init__.py +0 -0
  76. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/cloudbender/test_providers_integration.py +0 -0
  77. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/conftest.py +0 -0
  78. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_environments_integration.py +0 -0
  79. {proximl-0.5.4 → proximl-0.5.6}/tests/integration/test_gpu_types_integration.py +0 -0
  80. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/__init__.py +0 -0
  81. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/__init__.py +0 -0
  82. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/__init__.py +0 -0
  83. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_datastore_unit.py +0 -0
  84. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_device_unit.py +0 -0
  85. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_node_unit.py +0 -0
  86. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_provider_unit.py +0 -0
  87. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/cloudbender/test_cli_region_unit.py +0 -0
  88. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/conftest.py +0 -0
  89. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_checkpoint_unit.py +0 -0
  90. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_datasets_unit.py +0 -0
  91. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_environment_unit.py +0 -0
  92. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_gpu_unit.py +0 -0
  93. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_job_unit.py +0 -0
  94. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cli/test_cli_model_unit.py +0 -0
  95. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/__init__.py +0 -0
  96. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_datastores_unit.py +0 -0
  97. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_device_configs_unit.py +0 -0
  98. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_devices_unit.py +0 -0
  99. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_nodes_unit.py +0 -0
  100. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_providers_unit.py +0 -0
  101. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/cloudbender/test_regions_unit.py +0 -0
  102. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_auth.py +0 -0
  103. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_checkpoints_unit.py +0 -0
  104. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_connections_unit.py +0 -0
  105. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_datasets_unit.py +0 -0
  106. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_environments_unit.py +0 -0
  107. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_exceptions.py +0 -0
  108. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_gpu_types_unit.py +0 -0
  109. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_jobs_unit.py +0 -0
  110. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_models_unit.py +0 -0
  111. {proximl-0.5.4 → proximl-0.5.6}/tests/unit/test_proximl.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: proximl
3
- Version: 0.5.4
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
@@ -13,5 +13,5 @@ logging.basicConfig(
13
13
  logger = logging.getLogger(__name__)
14
14
 
15
15
 
16
- __version__ = "0.5.4"
16
+ __version__ = "0.5.6"
17
17
  __all__ = "ProxiML"
@@ -142,9 +142,7 @@ def configure(config):
142
142
  project for project in projects if project.id == active_project_id
143
143
  ]
144
144
 
145
- active_project_name = (
146
- active_project[0].name if len(active_project) else "UNSET"
147
- )
145
+ active_project_name = active_project[0].name if len(active_project) else "UNSET"
148
146
 
149
147
  click.echo(f"Current Active Project: {active_project_name}")
150
148
 
@@ -154,9 +152,7 @@ def configure(config):
154
152
  show_choices=True,
155
153
  default=active_project_name,
156
154
  )
157
- selected_project = [
158
- project for project in projects if project.name == name
159
- ]
155
+ selected_project = [project for project in projects if project.name == name]
160
156
  config.proximl.client.set_active_project(selected_project[0].id)
161
157
 
162
158
 
@@ -164,6 +160,7 @@ from proximl.cli.connection import connection
164
160
  from proximl.cli.dataset import dataset
165
161
  from proximl.cli.model import model
166
162
  from proximl.cli.checkpoint import checkpoint
163
+ from proximl.cli.volume import volume
167
164
  from proximl.cli.environment import environment
168
165
  from proximl.cli.gpu import gpu
169
166
  from proximl.cli.job import job
@@ -15,4 +15,4 @@ from proximl.cli.cloudbender.region import region
15
15
  from proximl.cli.cloudbender.node import node
16
16
  from proximl.cli.cloudbender.device import device
17
17
  from proximl.cli.cloudbender.datastore import datastore
18
- from proximl.cli.cloudbender.reservation import reservation
18
+ from proximl.cli.cloudbender.service import service
@@ -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())
@@ -115,40 +115,35 @@ def list_datastores(config):
115
115
 
116
116
  @project.command()
117
117
  @pass_config
118
- def list_reservations(config):
119
- """List project reservations."""
118
+ def list_services(config):
119
+ """List project services."""
120
120
  data = [
121
- ["ID", "NAME", "TYPE", "RESOURCE", "HOSTNAME", "REGION_UUID"],
121
+ ["ID", "NAME", "HOSTNAME", "REGION_UUID"],
122
122
  [
123
123
  "-" * 80,
124
124
  "-" * 80,
125
125
  "-" * 80,
126
126
  "-" * 80,
127
- "-" * 80,
128
- "-" * 80,
129
127
  ],
130
128
  ]
131
129
  project = config.proximl.run(
132
130
  config.proximl.client.projects.get(config.proximl.client.project)
133
131
  )
134
132
 
135
- reservations = config.proximl.run(project.list_reservations())
133
+ services = config.proximl.run(project.list_services())
136
134
 
137
- for reservation in reservations:
135
+ for service in services:
138
136
  data.append(
139
137
  [
140
- reservation.id,
141
- reservation.name,
142
- reservation.type,
143
- reservation.resource,
144
- reservation.hostname,
145
- reservation.region_uuid,
138
+ service.id,
139
+ service.name,
140
+ service.hostname,
141
+ service.region_uuid,
146
142
  ]
147
143
  )
148
144
 
149
145
  for row in data:
150
146
  click.echo(
151
- "{: >38.36} {: >30.28} {: >8.6} {: >15.13} {: >30.28} {: >38.36}"
152
- "".format(*row),
147
+ "{: >38.36} {: >30.28} {: >30.28} {: >38.36}" "".format(*row),
153
148
  file=config.stdout,
154
149
  )
@@ -0,0 +1,235 @@
1
+ import click
2
+ from proximl.cli import cli, pass_config, search_by_id_name
3
+
4
+
5
+ def pretty_size(num):
6
+ if not num:
7
+ num = 0.0
8
+ s = (" B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB")
9
+ n = 0
10
+ while num > 1023:
11
+ num = num / 1024
12
+ n += 1
13
+ return f"{num:.2f} {s[n]}"
14
+
15
+
16
+ @cli.group()
17
+ @pass_config
18
+ def volume(config):
19
+ """proxiML volume commands."""
20
+ pass
21
+
22
+
23
+ @volume.command()
24
+ @click.argument("volume", type=click.STRING)
25
+ @pass_config
26
+ def attach(config, volume):
27
+ """
28
+ Attach to volume and show creation logs.
29
+
30
+ VOLUME may be specified by name or ID, but ID is preferred.
31
+ """
32
+ volumes = config.proximl.run(config.proximl.client.volumes.list())
33
+
34
+ found = search_by_id_name(volume, volumes)
35
+ if None is found:
36
+ raise click.UsageError("Cannot find specified volume.")
37
+
38
+ try:
39
+ config.proximl.run(found.attach())
40
+ return config.proximl.run(found.disconnect())
41
+ except:
42
+ try:
43
+ config.proximl.run(found.disconnect())
44
+ except:
45
+ pass
46
+ raise
47
+
48
+
49
+ @volume.command()
50
+ @click.option(
51
+ "--attach/--no-attach",
52
+ default=True,
53
+ show_default=True,
54
+ help="Auto attach to volume and show creation logs.",
55
+ )
56
+ @click.argument("volume", type=click.STRING)
57
+ @pass_config
58
+ def connect(config, volume, attach):
59
+ """
60
+ Connect local source to volume and begin upload.
61
+
62
+ VOLUME may be specified by name or ID, but ID is preferred.
63
+ """
64
+ volumes = config.proximl.run(config.proximl.client.volumes.list())
65
+
66
+ found = search_by_id_name(volume, volumes)
67
+ if None is found:
68
+ raise click.UsageError("Cannot find specified volume.")
69
+
70
+ try:
71
+ if attach:
72
+ config.proximl.run(found.connect(), found.attach())
73
+ return config.proximl.run(found.disconnect())
74
+ else:
75
+ return config.proximl.run(found.connect())
76
+ except:
77
+ try:
78
+ config.proximl.run(found.disconnect())
79
+ except:
80
+ pass
81
+ raise
82
+
83
+
84
+ @volume.command()
85
+ @click.option(
86
+ "--attach/--no-attach",
87
+ default=True,
88
+ show_default=True,
89
+ help="Auto attach to volume and show creation logs.",
90
+ )
91
+ @click.option(
92
+ "--connect/--no-connect",
93
+ default=True,
94
+ show_default=True,
95
+ help="Auto connect source and start volume creation.",
96
+ )
97
+ @click.option(
98
+ "--source",
99
+ "-s",
100
+ type=click.Choice(["local"], case_sensitive=False),
101
+ default="local",
102
+ show_default=True,
103
+ help="Dataset source type.",
104
+ )
105
+ @click.argument("name", type=click.STRING)
106
+ @click.argument("capacity", type=click.INT)
107
+ @click.argument(
108
+ "path", type=click.Path(exists=True, file_okay=False, resolve_path=True)
109
+ )
110
+ @pass_config
111
+ def create(config, attach, connect, source, name, capacity, path):
112
+ """
113
+ Create a volume.
114
+
115
+ A volume with maximum size CAPACITY is created with the specified NAME using a local source at the PATH
116
+ specified. PATH should be a local directory containing the source data for
117
+ a local source or a URI for all other source types.
118
+ """
119
+
120
+ if source == "local":
121
+ volume = config.proximl.run(
122
+ config.proximl.client.volumes.create(
123
+ name=name, source_type="local", source_uri=path, capacity=capacity
124
+ )
125
+ )
126
+
127
+ try:
128
+ if connect and attach:
129
+ config.proximl.run(volume.attach(), volume.connect())
130
+ return config.proximl.run(volume.disconnect())
131
+ elif connect:
132
+ return config.proximl.run(volume.connect())
133
+ else:
134
+ raise click.UsageError(
135
+ "Abort!\n"
136
+ "No logs to show for local sourced volume without connect."
137
+ )
138
+ except:
139
+ try:
140
+ config.proximl.run(volume.disconnect())
141
+ except:
142
+ pass
143
+ raise
144
+
145
+
146
+ @volume.command()
147
+ @click.argument("volume", type=click.STRING)
148
+ @pass_config
149
+ def disconnect(config, volume):
150
+ """
151
+ Disconnect and clean-up volume upload.
152
+
153
+ VOLUME may be specified by name or ID, but ID is preferred.
154
+ """
155
+ volumes = config.proximl.run(config.proximl.client.volumes.list())
156
+
157
+ found = search_by_id_name(volume, volumes)
158
+ if None is found:
159
+ raise click.UsageError("Cannot find specified volume.")
160
+
161
+ return config.proximl.run(found.disconnect())
162
+
163
+
164
+ @volume.command()
165
+ @pass_config
166
+ def list(config):
167
+ """List volumes."""
168
+ data = [
169
+ ["ID", "STATUS", "NAME", "CAPACITY"],
170
+ ["-" * 80, "-" * 80, "-" * 80, "-" * 80],
171
+ ]
172
+
173
+ volumes = config.proximl.run(config.proximl.client.volumes.list())
174
+
175
+ for volume in volumes:
176
+ data.append(
177
+ [
178
+ volume.id,
179
+ volume.status,
180
+ volume.name,
181
+ volume.capacity,
182
+ ]
183
+ )
184
+ for row in data:
185
+ click.echo(
186
+ "{: >38.36} {: >13.11} {: >40.38} {: >14.12}" "".format(*row),
187
+ file=config.stdout,
188
+ )
189
+
190
+
191
+ @volume.command()
192
+ @click.option(
193
+ "--force/--no-force",
194
+ default=False,
195
+ show_default=True,
196
+ help="Force removal.",
197
+ )
198
+ @click.argument("volume", type=click.STRING)
199
+ @pass_config
200
+ def remove(config, volume, force):
201
+ """
202
+ Remove a volume.
203
+
204
+ VOLUME may be specified by name or ID, but ID is preferred.
205
+ """
206
+ volumes = config.proximl.run(config.proximl.client.volumes.list())
207
+
208
+ found = search_by_id_name(volume, volumes)
209
+ if None is found:
210
+ if force:
211
+ config.proximl.run(found.client.volumes.remove(volume))
212
+ else:
213
+ raise click.UsageError("Cannot find specified volume.")
214
+
215
+ return config.proximl.run(found.remove(force=force))
216
+
217
+
218
+ @volume.command()
219
+ @click.argument("volume", type=click.STRING)
220
+ @click.argument("name", type=click.STRING)
221
+ @pass_config
222
+ def rename(config, volume, name):
223
+ """
224
+ Renames a volume.
225
+
226
+ VOLUME may be specified by name or ID, but ID is preferred.
227
+ """
228
+ try:
229
+ volume = config.proximl.run(config.proximl.client.volumes.get(volume))
230
+ if volume is None:
231
+ raise click.UsageError("Cannot find specified volume.")
232
+ except:
233
+ raise click.UsageError("Cannot find specified volume.")
234
+
235
+ return config.proximl.run(volume.rename(name=name))
@@ -3,7 +3,7 @@ from .regions import Regions
3
3
  from .nodes import Nodes
4
4
  from .devices import Devices
5
5
  from .datastores import Datastores
6
- from .reservations import Reservations
6
+ from .services import Services
7
7
  from .device_configs import DeviceConfigs
8
8
 
9
9
 
@@ -15,5 +15,5 @@ class Cloudbender(object):
15
15
  self.nodes = Nodes(proximl)
16
16
  self.devices = Devices(proximl)
17
17
  self.datastores = Datastores(proximl)
18
- self.reservations = Reservations(proximl)
18
+ self.services = Services(proximl)
19
19
  self.device_configs = DeviceConfigs(proximl)
@@ -2,77 +2,70 @@ import json
2
2
  import logging
3
3
 
4
4
 
5
- class Reservations(object):
5
+ class Services(object):
6
6
  def __init__(self, proximl):
7
7
  self.proximl = proximl
8
8
 
9
9
  async def get(self, provider_uuid, region_uuid, id, **kwargs):
10
10
  resp = await self.proximl._query(
11
- f"/provider/{provider_uuid}/region/{region_uuid}/reservation/{id}",
11
+ f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
12
12
  "GET",
13
13
  kwargs,
14
14
  )
15
- return Reservation(self.proximl, **resp)
15
+ return Service(self.proximl, **resp)
16
16
 
17
17
  async def list(self, provider_uuid, region_uuid, **kwargs):
18
18
  resp = await self.proximl._query(
19
- f"/provider/{provider_uuid}/region/{region_uuid}/reservation",
19
+ f"/provider/{provider_uuid}/region/{region_uuid}/service",
20
20
  "GET",
21
21
  kwargs,
22
22
  )
23
- reservations = [
24
- Reservation(self.proximl, **reservation) for reservation in resp
25
- ]
26
- return reservations
23
+ services = [Service(self.proximl, **service) for service in resp]
24
+ return services
27
25
 
28
26
  async def create(
29
27
  self,
30
28
  provider_uuid,
31
29
  region_uuid,
32
30
  name,
33
- type,
34
- resource,
35
- hostname,
31
+ public,
36
32
  **kwargs,
37
33
  ):
38
- logging.info(f"Creating Reservation {name}")
34
+ logging.info(f"Creating Service {name}")
39
35
  data = dict(
40
36
  name=name,
41
- type=type,
42
- resource=resource,
43
- hostname=hostname,
37
+ public=public,
44
38
  **kwargs,
45
39
  )
46
40
  payload = {k: v for k, v in data.items() if v is not None}
47
41
  resp = await self.proximl._query(
48
- f"/provider/{provider_uuid}/region/{region_uuid}/reservation",
42
+ f"/provider/{provider_uuid}/region/{region_uuid}/service",
49
43
  "POST",
50
44
  None,
51
45
  payload,
52
46
  )
53
- reservation = Reservation(self.proximl, **resp)
54
- logging.info(f"Created Reservation {name} with id {reservation.id}")
55
- return reservation
47
+ service = Service(self.proximl, **resp)
48
+ logging.info(f"Created Service {name} with id {service.id}")
49
+ return service
56
50
 
57
51
  async def remove(self, provider_uuid, region_uuid, id, **kwargs):
58
52
  await self.proximl._query(
59
- f"/provider/{provider_uuid}/region/{region_uuid}/reservation/{id}",
53
+ f"/provider/{provider_uuid}/region/{region_uuid}/service/{id}",
60
54
  "DELETE",
61
55
  kwargs,
62
56
  )
63
57
 
64
58
 
65
- class Reservation:
59
+ class Service:
66
60
  def __init__(self, proximl, **kwargs):
67
61
  self.proximl = proximl
68
- self._reservation = kwargs
69
- self._id = self._reservation.get("reservation_id")
70
- self._provider_uuid = self._reservation.get("provider_uuid")
71
- self._region_uuid = self._reservation.get("region_uuid")
72
- self._type = self._reservation.get("type")
73
- self._name = self._reservation.get("name")
74
- self._resource = self._reservation.get("resource")
75
- self._hostname = self._reservation.get("hostname")
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")
76
69
 
77
70
  @property
78
71
  def id(self) -> str:
@@ -87,39 +80,35 @@ class Reservation:
87
80
  return self._region_uuid
88
81
 
89
82
  @property
90
- def type(self) -> str:
91
- return self._type
83
+ def public(self) -> bool:
84
+ return self._public
92
85
 
93
86
  @property
94
87
  def name(self) -> str:
95
88
  return self._name
96
89
 
97
- @property
98
- def resource(self) -> str:
99
- return self._resource
100
-
101
90
  @property
102
91
  def hostname(self) -> str:
103
92
  return self._hostname
104
93
 
105
94
  def __str__(self):
106
- return json.dumps({k: v for k, v in self._reservation.items()})
95
+ return json.dumps({k: v for k, v in self._service.items()})
107
96
 
108
97
  def __repr__(self):
109
- return f"Reservation( proximl , **{self._reservation.__repr__()})"
98
+ return f"Service( proximl , **{self._service.__repr__()})"
110
99
 
111
100
  def __bool__(self):
112
101
  return bool(self._id)
113
102
 
114
103
  async def remove(self):
115
104
  await self.proximl._query(
116
- f"/provider/{self._provider_uuid}/region/{self._region_uuid}/reservation/{self._id}",
105
+ f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
117
106
  "DELETE",
118
107
  )
119
108
 
120
109
  async def refresh(self):
121
110
  resp = await self.proximl._query(
122
- f"/provider/{self._provider_uuid}/region/{self._region_uuid}/reservation/{self._id}",
111
+ f"/provider/{self._provider_uuid}/region/{self._region_uuid}/service/{self._id}",
123
112
  "GET",
124
113
  )
125
114
  self.__init__(self.proximl, **resp)
@@ -97,14 +97,27 @@ class CheckpointError(ProxiMLException):
97
97
  return self._status
98
98
 
99
99
  def __repr__(self):
100
- return "CheckpointError({self.status}, {self.message})".format(
101
- self=self
102
- )
100
+ return "CheckpointError({self.status}, {self.message})".format(self=self)
103
101
 
104
102
  def __str__(self):
105
- return "CheckpointError({self.status}, {self.message})".format(
106
- self=self
107
- )
103
+ return "CheckpointError({self.status}, {self.message})".format(self=self)
104
+
105
+
106
+ class VolumeError(ProxiMLException):
107
+ def __init__(self, status, data, *args):
108
+ super().__init__(data, *args)
109
+ self._status = status
110
+ self._message = data
111
+
112
+ @property
113
+ def status(self) -> str:
114
+ return self._status
115
+
116
+ def __repr__(self):
117
+ return "VolumeError({self.status}, {self.message})".format(self=self)
118
+
119
+ def __str__(self):
120
+ return "VolumeError({self.status}, {self.message})".format(self=self)
108
121
 
109
122
 
110
123
  class ConnectionError(ProxiMLException):
@@ -130,11 +143,7 @@ class SpecificationError(ProxiMLException):
130
143
  return self._attribute
131
144
 
132
145
  def __repr__(self):
133
- return "SpecificationError({self.attribute}, {self.message})".format(
134
- self=self
135
- )
146
+ return "SpecificationError({self.attribute}, {self.message})".format(self=self)
136
147
 
137
148
  def __str__(self):
138
- return "SpecificationError({self.attribute}, {self.message})".format(
139
- self=self
140
- )
149
+ return "SpecificationError({self.attribute}, {self.message})".format(self=self)