oscar-python 1.2.1__tar.gz → 1.3.0__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 (31) hide show
  1. {oscar_python-1.2.1 → oscar_python-1.3.0}/PKG-INFO +21 -2
  2. {oscar_python-1.2.1 → oscar_python-1.3.0}/README.md +3 -0
  3. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_providers/_minio.py +4 -3
  4. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_providers/_onedata.py +16 -13
  5. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_providers/_providers_base.py +4 -3
  6. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_providers/_s3.py +15 -13
  7. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_providers/_webdav.py +7 -7
  8. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/_utils.py +26 -20
  9. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/client.py +27 -21
  10. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/client_anon.py +3 -2
  11. oscar_python-1.3.0/oscar_python/default_client.py +39 -0
  12. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/local_test.py +1 -1
  13. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/storage.py +14 -14
  14. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/PKG-INFO +22 -3
  15. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/SOURCES.txt +8 -1
  16. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/requires.txt +1 -0
  17. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/top_level.txt +1 -0
  18. {oscar_python-1.2.1 → oscar_python-1.3.0}/setup.py +3 -2
  19. oscar_python-1.3.0/tests/test_client.py +129 -0
  20. oscar_python-1.3.0/tests/test_default_client.py +61 -0
  21. oscar_python-1.3.0/tests/test_onedata.py +66 -0
  22. oscar_python-1.3.0/tests/test_s3.py +48 -0
  23. oscar_python-1.3.0/tests/test_storage.py +51 -0
  24. oscar_python-1.3.0/tests/test_utils.py +94 -0
  25. oscar_python-1.3.0/tests/test_webdav.py +50 -0
  26. oscar_python-1.2.1/oscar_python/default_client.py +0 -35
  27. {oscar_python-1.2.1 → oscar_python-1.3.0}/LICENSE +0 -0
  28. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python/__init__.py +0 -0
  29. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/dependency_links.txt +0 -0
  30. {oscar_python-1.2.1 → oscar_python-1.3.0}/oscar_python.egg-info/not-zip-safe +0 -0
  31. {oscar_python-1.2.1 → oscar_python-1.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: oscar_python
3
- Version: 1.2.1
3
+ Version: 1.3.0
4
4
  Summary: OSCAR API for python
5
5
  Home-page: https://github.com/grycap/oscar_python
6
6
  Author: GRyCAP - Universitat Politecnica de Valencia
@@ -10,6 +10,22 @@ Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: Apache Software License
11
11
  Description-Content-Type: text/markdown
12
12
  License-File: LICENSE
13
+ Requires-Dist: webdavclient3==3.14.6
14
+ Requires-Dist: requests
15
+ Requires-Dist: boto3
16
+ Requires-Dist: setuptools>=40.8.0
17
+ Requires-Dist: pyyaml
18
+ Requires-Dist: aiohttp
19
+ Requires-Dist: liboidcagent
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: home-page
26
+ Dynamic: license
27
+ Dynamic: requires-dist
28
+ Dynamic: summary
13
29
 
14
30
  ## Python OSCAR client
15
31
 
@@ -170,6 +186,9 @@ response = client.remove_service("service_name") # returns an http response
170
186
  ``` python
171
187
  # make a synchronous execution
172
188
  response = client.run_service("service_name", input="input", output="out.png", timeout=100) # returns an http response
189
+
190
+ # make an asynchronous execution
191
+ response = client.run_service("service_name", input="input", async_call=True) # returns an http response
173
192
  ```
174
193
 
175
194
  #### Logs methods
@@ -157,6 +157,9 @@ response = client.remove_service("service_name") # returns an http response
157
157
  ``` python
158
158
  # make a synchronous execution
159
159
  response = client.run_service("service_name", input="input", output="out.png", timeout=100) # returns an http response
160
+
161
+ # make an asynchronous execution
162
+ response = client.run_service("service_name", input="input", async_call=True) # returns an http response
160
163
  ```
161
164
 
162
165
  #### Logs methods
@@ -10,15 +10,16 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  import boto3
16
16
  from oscar_python._providers._s3 import S3
17
17
 
18
18
  _DEFAULT_MINIO_ENDPOINT = 'http://minio-service.minio:9000'
19
19
 
20
+
20
21
  class Minio(S3):
21
-
22
+
22
23
  def _get_client(self, c):
23
24
  """Return Minio client with user configuration."""
24
25
  if c["endpoint"] == '':
@@ -30,4 +31,4 @@ class Minio(S3):
30
31
  region_name=c["region"],
31
32
  verify=c["verify"],
32
33
  aws_access_key_id=c["access_key"],
33
- aws_secret_access_key=c["secret_key"])
34
+ aws_secret_access_key=c["secret_key"])
@@ -10,29 +10,30 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  from oscar_python._providers._providers_base import StorageProvider
16
16
  import requests
17
17
  import json
18
18
 
19
- #TODO fix error returns
19
+
20
+ # TODO fix error returns
20
21
  class Onedata(StorageProvider):
21
-
22
+
22
23
  _CDMI_PATH = '/cdmi'
23
24
  _CDMI_VERSION_HEADER = {'X-CDMI-Specification-Version': '1.1.1'}
24
25
 
25
26
  def __init__(self, credentials) -> None:
26
27
  super().__init__()
27
28
  self._get_client(credentials)
28
-
29
+
29
30
  def _get_client(self, c):
30
31
  self.oneprovider_space = c["space"]
31
32
  self.oneprovider_host = c["oneprovider_host"]
32
33
  self.headers = {'X-Auth-Token': c["token"]}
33
34
  self.url = (f'https://{self.oneprovider_host}{self._CDMI_PATH}/'
34
35
  f'{self.oneprovider_space}/')
35
-
36
+
36
37
  def upload_file(self, local_path, remote_path):
37
38
  file_name = local_path.split('/')[-1]
38
39
  if not self._folder_exists(remote_path):
@@ -57,12 +58,13 @@ class Onedata(StorageProvider):
57
58
  file_name = remote_path.split('/')[-1]
58
59
  url = self.url+remote_path
59
60
  res = requests.get(url=url, headers=self.headers)
60
- if res.status_code == 200: print("Saving file to {0}/{1}".format(local_path, file_name))
61
+ if res.status_code == 200:
62
+ print("Saving file to {0}/{1}".format(local_path, file_name))
61
63
  self._save_file(local_path+"/"+file_name, res.content, mode='wb')
62
-
64
+
63
65
  def list_files_from_path(self, path):
64
66
  headers = {**self._CDMI_VERSION_HEADER, **self.headers}
65
- return requests.get(url = self.url+path+"/", headers=headers)
67
+ return requests.get(url=self.url+path+"/", headers=headers)
66
68
 
67
69
  def _save_file(self, path, content, mode='w'):
68
70
  with open(path, mode) as fwc:
@@ -72,12 +74,13 @@ class Onedata(StorageProvider):
72
74
 
73
75
  def _folder_exists(self, folder_name):
74
76
  headers = {**self._CDMI_VERSION_HEADER, **self.headers}
75
- response = requests.get(url = self.url+folder_name+"/", headers=headers)
77
+ response = requests.get(url=self.url+folder_name+"/", headers=headers)
76
78
  if response.status_code == 200:
77
79
  return True
78
80
  return False
79
-
81
+
80
82
  def _create_folder(self, folder_name):
81
- response = requests.put(url = self.url+folder_name+"/", headers=self.headers)
82
- if response.status_code != 201:
83
- return False
83
+ response = requests.put(url=self.url+folder_name+"/", headers=self.headers)
84
+ if response.status_code == 201:
85
+ return True
86
+ return False
@@ -10,10 +10,11 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  import abc
16
16
 
17
+
17
18
  class StorageProvider(abc.ABC):
18
19
  @abc.abstractmethod
19
20
  def download_file(self, local_path, remote_path):
@@ -22,11 +23,11 @@ class StorageProvider(abc.ABC):
22
23
  @abc.abstractmethod
23
24
  def upload_file(self, local_path, remote_path):
24
25
  """Generic method to be implemented by all the storage providers."""
25
-
26
+
26
27
  @abc.abstractmethod
27
28
  def list_files_from_path(self, path):
28
29
  """Generic method to be implemented by all the storage providers."""
29
30
 
30
31
  @abc.abstractmethod
31
32
  def _get_client(self):
32
- """Generic method to be implemented by all the storage providers."""
33
+ """Generic method to be implemented by all the storage providers."""
@@ -10,19 +10,19 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  from aiohttp import ClientError
16
- import logging
17
16
  import boto3
18
17
  from oscar_python._providers._providers_base import StorageProvider
19
18
 
19
+
20
20
  class S3(StorageProvider):
21
21
  def __init__(self, credentials) -> None:
22
22
  super().__init__()
23
23
  self.client = self._get_client(credentials)
24
24
  self.resource = self._get_resource(credentials)
25
-
25
+
26
26
  def _get_client(self, c):
27
27
  """Returns S3 client with default configuration."""
28
28
  if c is None:
@@ -42,39 +42,41 @@ class S3(StorageProvider):
42
42
  if region == '':
43
43
  region = None
44
44
  return boto3.resource('s3',
45
- region_name=region,
46
- aws_access_key_id=c["access_key"],
47
- aws_secret_access_key=c["secret_key"])
45
+ region_name=region,
46
+ aws_access_key_id=c["access_key"],
47
+ aws_secret_access_key=c["secret_key"])
48
48
 
49
49
  def list_files_from_path(self, path):
50
50
  prefix = ""
51
51
  path_split = path.split('/')
52
52
  bucket = path_split[0]
53
53
  if len(path_split) > 1:
54
- prefix = path.split('/',2)[1]
55
- print("Reading content from path:",path)
54
+ prefix = path.split('/', 2)[1]
55
+ print("Reading content from path:", path)
56
56
  return self.client.list_objects(Bucket=bucket, Prefix=prefix)
57
-
57
+
58
58
  def upload_file(self, local_path, remote_path):
59
59
  bucket_name = remote_path.split('/')[0]
60
- file_key = remote_path.split('/',1)[1]
60
+ file_key = remote_path.split('/', 1)[1]
61
61
  file_name = local_path.split('/')[-1]
62
62
  print("Uploading to bucket '{0}' with key '{1}'".format(bucket_name,file_key))
63
63
  with open(local_path, 'rb') as data:
64
64
  try:
65
- self.client.upload_fileobj(data, bucket_name, file_key+"/"+file_name)
65
+ self.client.upload_fileobj(data, bucket_name, file_key + "/" + file_name)
66
+ return True
66
67
  except ClientError as err:
67
68
  print("Error uploading file: ", err)
68
69
  return False
69
70
 
70
71
  def download_file(self, local_path, remote_path):
71
72
  bucket_name = remote_path.split('/')[0]
72
- file_key = remote_path.split('/',1)[1]
73
+ file_key = remote_path.split('/', 1)[1]
73
74
  file_path = local_path+"/"+remote_path.split('/')[-1]
74
75
  print("Downloading from bucket '{0}' to path '{1}' with key '{2}'".format(bucket_name, file_path, file_key))
75
76
  with open(file_path, 'wb') as data:
76
77
  try:
77
78
  self.client.download_fileobj(bucket_name, file_key, data)
79
+ return True
78
80
  except ClientError as err:
79
81
  print("Error downloading file: ", err)
80
- return False
82
+ return False
@@ -10,12 +10,13 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  from oscar_python._providers._providers_base import StorageProvider
16
16
  from webdav3.client import Client
17
17
  from webdav3.exceptions import WebDavException
18
18
 
19
+
19
20
  class WebDav(StorageProvider):
20
21
  def __init__(self, credentials) -> None:
21
22
  self.client = self._get_client(credentials)
@@ -26,9 +27,9 @@ class WebDav(StorageProvider):
26
27
  if 'https://' not in hostname:
27
28
  hostname = 'https://'+hostname
28
29
  options = {
29
- 'webdav_hostname': hostname,
30
- 'webdav_login': c["login"],
31
- 'webdav_password': c["password"]
30
+ 'webdav_hostname': hostname,
31
+ 'webdav_login': c["login"],
32
+ 'webdav_password': c["password"]
32
33
  }
33
34
  return Client(options=options)
34
35
 
@@ -45,13 +46,12 @@ class WebDav(StorageProvider):
45
46
  except WebDavException as exception:
46
47
  print("error uploading file to path '{0}': {1}".format(remote_path+"/"+file_name, exception))
47
48
 
48
-
49
49
  def download_file(self, local_path, remote_path):
50
50
  file_name = remote_path.split('/')[-1]
51
51
  try:
52
52
  self.client.download_sync(remote_path, local_path+"/"+file_name)
53
53
  except WebDavException as exception:
54
54
  print("error downloading file from path '{0}': {1}".format(remote_path, exception))
55
-
55
+
56
56
  def list_files_from_path(self, path):
57
- return self.client.list(path)
57
+ return self.client.list(path)
@@ -10,7 +10,7 @@
10
10
  # distributed under the License is distributed on an "AS IS" BASIS,
11
11
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  # See the License for the specific language governing permissions and
13
- # limitations under the License.
13
+ # limitations under the License.
14
14
 
15
15
  import base64
16
16
  import os
@@ -18,18 +18,19 @@ import requests
18
18
  import liboidcagent as agent
19
19
  _DEFAULT_TIMEOUT = 60
20
20
 
21
- """ Generic http request """
22
- def make_request(c , path, method, **kwargs):
23
21
 
24
- headers = get_headers(c)
22
+ def make_request(c, path, method, **kwargs):
23
+ """ Generic http request """
25
24
 
26
- if "timeout" in kwargs.keys() and kwargs["timeout"]:
25
+ headers = get_headers(c)
26
+
27
+ if "timeout" in kwargs.keys() and kwargs["timeout"]:
27
28
  timeout = kwargs["timeout"]
28
- else:
29
+ else:
29
30
  timeout = _DEFAULT_TIMEOUT
30
31
 
31
32
  url = c.endpoint+path
32
-
33
+
33
34
  if method in ["post", "put"]:
34
35
  if "token" in kwargs.keys() and kwargs["token"]:
35
36
  headers = get_headers_with_token(kwargs["token"])
@@ -40,37 +41,42 @@ def make_request(c , path, method, **kwargs):
40
41
 
41
42
  if "handle" in kwargs.keys() and kwargs["handle"] == False:
42
43
  return result
43
-
44
+
44
45
  result.raise_for_status()
45
46
  return result
46
47
 
47
- """ Function to generate headers with basic authentication or OIDC """
48
+
48
49
  def get_headers(c):
50
+ """ Function to generate headers with basic authentication or OIDC """
49
51
  if c._AUTH_TYPE == "basicauth":
50
- usr_pass_as_bytes = bytes(c.user+":"+c.password,"utf-8")
52
+ usr_pass_as_bytes = bytes(c.user + ":" + c.password, "utf-8")
51
53
  usr_pass_base_64 = base64.b64encode(usr_pass_as_bytes).decode("utf-8")
52
- return {"Authorization": "Basic "+ usr_pass_base_64}
54
+ return {"Authorization": "Basic " + usr_pass_base_64}
53
55
  if c._AUTH_TYPE == "oidc-agent":
54
56
  token = agent.get_access_token(c.shortname)
55
57
  return get_headers_with_token(token)
56
58
  if c._AUTH_TYPE == "oidc":
57
59
  return get_headers_with_token(c.oidc_token)
58
60
 
59
- """ Function to generate headers with token auth """
61
+
60
62
  def get_headers_with_token(token):
61
- return {"Authorization": "Bearer "+ str(token)}
63
+ """ Function to generate headers with token auth """
64
+ return {"Authorization": "Bearer " + str(token)}
65
+
62
66
 
63
67
  def write_text_file(content, file_path):
64
68
  with open(file_path, 'w') as f:
65
69
  f.write(content)
66
70
 
71
+
67
72
  def isBase64(st):
68
73
  try:
69
74
  base64.b64decode(st)
70
75
  return True
71
- except:
76
+ except Exception:
72
77
  return False
73
78
 
79
+
74
80
  def decode_b64(b64_str, file_out):
75
81
  file_extension = os.path.splitext(file_out)[1]
76
82
  try:
@@ -80,7 +86,7 @@ def decode_b64(b64_str, file_out):
80
86
  decode = 'w'
81
87
  decoded_data = decoded_data.decode("utf-8")
82
88
  else:
83
- decode = 'wb'
89
+ decode = 'wb'
84
90
 
85
91
  with open(file_out, decode) as f:
86
92
  f.write(decoded_data)
@@ -90,6 +96,7 @@ def decode_b64(b64_str, file_out):
90
96
  except OSError:
91
97
  print('Error decoding output: Failed to write decoded data to file.')
92
98
 
99
+
93
100
  def encode_input(data):
94
101
  if os.path.isfile(data):
95
102
  try:
@@ -103,12 +110,11 @@ def encode_input(data):
103
110
  message_bytes = data.encode('ascii')
104
111
  return base64.b64encode(message_bytes)
105
112
 
113
+
106
114
  def decode_output(output, file_path):
107
- if(isBase64(output)):
115
+ if isBase64(output):
108
116
  decode_b64(output, file_path)
109
117
  return
110
- if(isinstance(output,str)):
111
- write_text_file(output,file_path)
118
+ if isinstance(output, str):
119
+ write_text_file(output, file_path)
112
120
  return
113
-
114
-
@@ -11,7 +11,7 @@
11
11
  # distributed under the License is distributed on an "AS IS" BASIS,
12
12
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  # See the License for the specific language governing permissions and
14
- # limitations under the License.
14
+ # limitations under the License.
15
15
 
16
16
  import json
17
17
  import os
@@ -26,7 +26,10 @@ _CONFIG_PATH = "/system/config"
26
26
  _SVC_PATH = "/system/services"
27
27
  _LOGS_PATH = "/system/logs"
28
28
  _RUN_PATH = "/run"
29
- #_JOB_PATH = "/job"
29
+ _STATUS_PATH="/system/status"
30
+
31
+
32
+ # _JOB_PATH = "/job"
30
33
 
31
34
 
32
35
  _GET = "get"
@@ -34,8 +37,9 @@ _POST = "post"
34
37
  _PUT = "put"
35
38
  _DELETE = "delete"
36
39
 
40
+
37
41
  class Client(DefaultClient):
38
- #Cluster info
42
+ # Cluster info
39
43
  def __init__(self, options) -> None:
40
44
  self.set_auth_type(options)
41
45
  if self._AUTH_TYPE == 'basicauth':
@@ -57,7 +61,7 @@ class Client(DefaultClient):
57
61
  self.endpoint = options['endpoint']
58
62
  self.shortname = options['shortname']
59
63
  self.ssl = bool(options['ssl'])
60
-
64
+
61
65
  def oidc_client(self, options):
62
66
  self.id = options['cluster_id']
63
67
  self.endpoint = options['endpoint']
@@ -78,7 +82,7 @@ class Client(DefaultClient):
78
82
  else:
79
83
  raise ValueError("Unrecognized authentication credentials in options")
80
84
 
81
- """ Creates a generic storage client to interact with the storage providers
85
+ """ Creates a generic storage client to interact with the storage providers
82
86
  defined on a specific service of the refered OSCAR cluster """
83
87
  def create_storage_client(self, svc):
84
88
  return Storage(
@@ -96,7 +100,7 @@ class Client(DefaultClient):
96
100
  """ List all services from the current cluster """
97
101
  def list_services(self):
98
102
  return utils.make_request(self, _SVC_PATH, _GET)
99
-
103
+
100
104
  """ Retreive a specific service """
101
105
  def get_service(self, name):
102
106
  return utils.make_request(self, _SVC_PATH+"/"+name, _GET)
@@ -111,15 +115,15 @@ class Client(DefaultClient):
111
115
  try:
112
116
  svc = element[self.id]
113
117
  except KeyError as err:
114
- raise("FDL clusterID does not match current clusterID: {0}".format(err))
118
+ raise Exception("FDL clusterID does not match current clusterID: {0}".format(err))
115
119
  try:
116
120
  with open(svc["script"]) as s:
117
121
  svc["script"] = s.read()
118
- except IOError as err:
119
- raise("Couldn't read script")
120
-
122
+ except IOError:
123
+ raise Exception("Couldn't read script")
124
+
121
125
  # cpu parameter has to be string on the request
122
- if type(svc["cpu"]) is int or type(svc["cpu"]) is float: svc["cpu"]= str(svc["cpu"])
126
+ if type(svc["cpu"]) is int or type(svc["cpu"]) is float: svc["cpu"] = str(svc["cpu"])
123
127
 
124
128
  except ValueError as err:
125
129
  print(err)
@@ -127,7 +131,11 @@ class Client(DefaultClient):
127
131
  else:
128
132
  raise ValueError("Bad yaml format: {0}".format(fdl))
129
133
  return svc
130
-
134
+
135
+ """ Get status of a cluster (CPU and Memory) """
136
+ def get_cluster_status(self):
137
+ return utils.make_request(self, _STATUS_PATH, _GET)
138
+
131
139
  """ Make the request to create a new service """
132
140
  def _apply_service(self, svc, method):
133
141
  # Check if service already exists when the function is called from create_service
@@ -136,18 +144,16 @@ class Client(DefaultClient):
136
144
  if svc_exists.status_code == 200:
137
145
  raise ValueError("A service with name '{0}' is already present on the cluster".format(svc["name"]))
138
146
  return utils.make_request(self, _SVC_PATH, method, data=json.dumps(svc))
139
-
147
+
140
148
  """ Create a service on the current cluster from a FDL file or a JSON definition """
141
149
  def create_service(self, service_definition):
142
150
  if type(service_definition) is dict:
143
151
  return self._apply_service(service_definition, _POST)
144
152
  if os.path.isfile(service_definition):
145
- try:
146
- service = self._check_fdl_definition(service_definition)
147
- except Exception:
148
- raise
153
+ service = self._check_fdl_definition(service_definition)
149
154
  return self._apply_service(service, _POST)
150
-
155
+ raise ValueError("Service definition must be a dictionary or a file path")
156
+
151
157
  """ Update a specific service from a FDL file or a JSON definition """
152
158
  def update_service(self, name, new_service):
153
159
  # Check if service exists before update
@@ -158,7 +164,7 @@ class Client(DefaultClient):
158
164
  return self._apply_service(new_service, _PUT)
159
165
  if os.path.isfile(new_service):
160
166
  try:
161
- service = self._check_fdl_definition(new_service)
167
+ service = self._check_fdl_definition(new_service)
162
168
  except Exception:
163
169
  raise
164
170
  return self._apply_service(service, _PUT)
@@ -178,11 +184,11 @@ class Client(DefaultClient):
178
184
  except ValueError as err:
179
185
  return err
180
186
  return fdl_yaml
181
-
187
+
182
188
  """ Get logs of a service job """
183
189
  def get_job_logs(self, svc, job):
184
190
  return utils.make_request(self, _LOGS_PATH+"/"+svc+"/"+job, _GET)
185
-
191
+
186
192
  """ List a service jobs """
187
193
  def list_jobs(self, svc):
188
194
  return utils.make_request(self, _LOGS_PATH+"/"+svc, _GET)
@@ -1,9 +1,10 @@
1
1
  from oscar_python.default_client import DefaultClient
2
2
 
3
+
3
4
  class AnonymousClient(DefaultClient):
4
- #Cluster info
5
+ # Cluster info
5
6
  def __init__(self, options) -> None:
6
7
  self.id = options['cluster_id']
7
8
  self.endpoint = options["endpoint"]
8
9
  self.ssl = bool(options['ssl'])
9
- self._AUTH_TYPE = "anon"
10
+ self._AUTH_TYPE = "anon"
@@ -0,0 +1,39 @@
1
+ import abc
2
+ import oscar_python._utils as utils
3
+
4
+ _RUN_PATH = "/run"
5
+ _JOB_PATH = "/job"
6
+ _POST = "post"
7
+
8
+
9
+ class DefaultClient(metaclass=abc.ABCMeta):
10
+
11
+ _AUTH_TYPE = ''
12
+
13
+ """ Run an execution.
14
+ If async is set to True the execution is run asynchronously.
15
+ If an output is provided the result is decoded onto the file.
16
+ In both cases the function returns the HTTP response."""
17
+ def run_service(self, name, **kwargs):
18
+ if kwargs.get("token"):
19
+ token = kwargs["token"]
20
+ else:
21
+ token = self._get_token(name)
22
+
23
+ send_data = None
24
+ if kwargs.get("input"):
25
+ send_data = kwargs["input"]
26
+ if not isinstance(send_data, dict):
27
+ send_data = utils.encode_input(send_data)
28
+
29
+ path = _RUN_PATH + "/"+name
30
+ if kwargs.get("async_call"):
31
+ path = _JOB_PATH + "/" + name
32
+
33
+ response = utils.make_request(self, path, _POST, data=send_data,
34
+ token=token, timeout=kwargs.get("timeout"))
35
+
36
+ if kwargs.get("output"):
37
+ utils.decode_output(response.text, kwargs["output"])
38
+
39
+ return response
@@ -7,4 +7,4 @@ if res:
7
7
  print(res.status_code)
8
8
  print(res.content)
9
9
  else:
10
- print("empty")
10
+ print("empty")