Skip to content

Commit 44db93c

Browse files
committed
Merge branch 'master' into feature/mes
2 parents a151ca7 + c6b6f11 commit 44db93c

File tree

15 files changed

+1214
-57
lines changed

15 files changed

+1214
-57
lines changed

HISTORY.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
==========
33

4+
7.0.0 (2020-07-21)
5+
------------------
6+
7+
* Initial release for DSS 7.0
8+
49
5.1.0 (2019-03-01)
510
------------------
611

dataikuapi/dss/admin.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ def remove_connection_credential(self,connection):
290290

291291
def set_basic_plugin_credential(self, plugin_id, param_set_id, preset_id, param_name, user, password):
292292
"""Sets per-user-credentials for a plugin preset that takes a user/password pair"""
293-
name = json.dumps(["PLUGIN", pluginId, paramSetId, presetId, paramName])[1:-1]
293+
name = json.dumps(["PLUGIN", plugin_id, param_set_id, preset_id, param_name])[1:-1]
294294

295295
self.settings["credentials"][name] = {
296296
"type": "BASIC",
@@ -300,7 +300,7 @@ def set_basic_plugin_credential(self, plugin_id, param_set_id, preset_id, param_
300300

301301
def set_oauth2_plugin_credential(self, plugin_id, param_set_id, preset_id, param_name, refresh_token):
302302
"""Sets per-user-credentials for a plugin preset that takes a OAuth refresh token"""
303-
name = json.dumps(["PLUGIN", pluginId, paramSetId, presetId, paramName])[1:-1]
303+
name = json.dumps(["PLUGIN", plugin_id, param_set_id, preset_id, param_name])[1:-1]
304304

305305
self.settings["credentials"][name] = {
306306
"type": "OAUTH_REFRESH_TOKEN",
@@ -309,7 +309,7 @@ def set_oauth2_plugin_credential(self, plugin_id, param_set_id, preset_id, param
309309

310310
def remove_plugin_credential(self, plugin_id, param_set_id, preset_id, param_name):
311311
"""Removes per-user-credentials for a plugin preset"""
312-
name = json.dumps(["PLUGIN", pluginId, paramSetId, presetId, paramName])[1:-1]
312+
name = json.dumps(["PLUGIN", plugin_id, param_set_id, preset_id, param_name])[1:-1]
313313

314314
if name in self.settings["credentials"]:
315315
del self.settings["credentials"][name]
@@ -732,14 +732,15 @@ def set_jupyter_support(self, active):
732732
raise Exception('Env update failed : %s' % (json.dumps(resp.get('messages', {}).get('messages', {}))))
733733
return resp
734734

735-
def update_packages(self):
735+
def update_packages(self, force_rebuild_env=False):
736736
"""
737737
Update the code env packages so that it matches its spec
738738
739739
Note: this call requires an API key with admin rights
740740
"""
741741
resp = self.client._perform_json(
742-
"POST", "/admin/code-envs/%s/%s/packages" % (self.env_lang, self.env_name))
742+
"POST", "/admin/code-envs/%s/%s/packages" % (self.env_lang, self.env_name),
743+
params={"forceRebuildEnv": force_rebuild_env})
743744
if resp is None:
744745
raise Exception('Env update returned no data')
745746
if resp.get('messages', {}).get('error', False):
@@ -797,6 +798,7 @@ def set_definition(self, definition):
797798
"PUT", "/admin/globalAPIKeys/%s" % self.key,
798799
body = definition)
799800

801+
800802
class DSSCluster(object):
801803
"""
802804
A handle to interact with a cluster on the DSS instance
@@ -873,7 +875,7 @@ def start(self):
873875
resp = self.client._perform_json(
874876
"POST", "/admin/clusters/%s/actions/start" % (self.cluster_id))
875877
if resp is None:
876-
raise Exception('Env update returned no data')
878+
raise Exception('Cluster operation returned no data')
877879
if resp.get('messages', {}).get('error', False):
878880
raise Exception('Cluster operation failed : %s' % (json.dumps(resp.get('messages', {}).get('messages', {}))))
879881
return resp
@@ -895,6 +897,9 @@ def stop(self, terminate=True):
895897
return resp
896898

897899
class DSSClusterSettings(object):
900+
"""
901+
The settings of a cluster
902+
"""
898903
def __init__(self, client, cluster_id, settings):
899904
"""Do not call directly, use :meth:`DSSCluster.get_settings`"""
900905
self.client = client
@@ -927,6 +932,9 @@ def save(self):
927932
"PUT", "/admin/clusters/%s" % (self.cluster_id), body=self.settings)
928933

929934
class DSSClusterStatus(object):
935+
"""
936+
The status of a cluster
937+
"""
930938
def __init__(self, client, cluster_id, status):
931939
"""Do not call directly, use :meth:`DSSCluster.get_Status`"""
932940
self.client = client
@@ -937,4 +945,4 @@ def get_raw(self):
937945
"""
938946
Gets the whole status as a raw dictionary.
939947
"""
940-
return self.status
948+
return self.status

dataikuapi/dss/apideployer.py

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
from .future import DSSFuture
33

4+
45
class DSSAPIDeployer(object):
56
"""
67
Handle to interact with the API Deployer.
@@ -10,7 +11,7 @@ class DSSAPIDeployer(object):
1011
def __init__(self, client):
1112
self.client = client
1213

13-
def list_deployments(self, as_objects = True):
14+
def list_deployments(self, as_objects=True):
1415
"""
1516
Lists deployments on the API Deployer
1617
@@ -55,7 +56,16 @@ def create_deployment(self, deployment_id, service_id, infra_id, version):
5556
self.client._perform_json("POST", "/api-deployer/deployments", body=settings)
5657
return self.get_deployment(deployment_id)
5758

58-
def list_infras(self, as_objects = True):
59+
def list_stages(self):
60+
"""
61+
Lists infrastructure stages of the API Deployer
62+
63+
:rtype: a list of dict. Each dict contains a field "id" for the stage identifier and "desc" for its description.
64+
:rtype: list
65+
"""
66+
return self.client._perform_json("GET", "/api-deployer/stages")
67+
68+
def list_infras(self, as_objects=True):
5969
"""
6070
Lists deployment infrastructures on the API Deployer
6171
@@ -97,7 +107,7 @@ def get_infra(self, infra_id):
97107
"""
98108
return DSSAPIDeployerInfra(self.client, infra_id)
99109

100-
def list_services(self, as_objects = True):
110+
def list_services(self, as_objects=True):
101111
"""
102112
Lists API services on the API Deployer
103113
@@ -121,7 +131,7 @@ def create_service(self, service_id):
121131
:rtype: :class:`DSSAPIDeployerService`
122132
"""
123133
settings = {
124-
"serviceId" : service_id
134+
"publishedServiceId" : service_id
125135
}
126136
self.client._perform_json("POST", "/api-deployer/services", body=settings)
127137
return self.get_service(service_id)
@@ -331,6 +341,7 @@ def save(self):
331341
"PUT", "/api-deployer/deployments/%s/settings" % (self.deployment_id),
332342
body = self.settings)
333343

344+
334345
class DSSAPIDeployerDeploymentStatus(object):
335346
"""The status of an API Deployer deployment.
336347
@@ -386,7 +397,6 @@ def get_health_messages(self):
386397
return self.heavy_status["healthMessages"]
387398

388399

389-
390400
###############################################
391401
# Published Service
392402
###############################################
@@ -414,16 +424,15 @@ def get_status(self):
414424
light = self.client._perform_json("GET", "/api-deployer/services/%s" % (self.service_id))
415425
return DSSAPIDeployerServiceStatus(self.client, self.service_id, light)
416426

417-
def import_version(self, version_id, fp):
427+
def import_version(self, fp):
418428
"""
419429
Imports a new version for an API service from a file-like object pointing
420430
to a version package Zip file
421431
422-
:param string version_id: identifier of the new version
423432
:param string fp: A file-like object pointing to a version package Zip file
424433
"""
425434
return self.client._perform_empty("POST",
426-
"/api-deployer/services/%s/packages/%s" % (self.service_id, version_id), files={"file":fp})
435+
"/api-deployer/services/%s/versions" % (self.service_id), files={"file":fp})
427436

428437
def get_settings(self):
429438
"""
@@ -440,6 +449,23 @@ def get_settings(self):
440449

441450
return DSSAPIDeployerServiceSettings(self.client, self.service_id, settings)
442451

452+
def delete_version(self, version):
453+
"""
454+
Deletes a version from this service
455+
:param string version: The version to delete
456+
"""
457+
self.client._perform_empty(
458+
"DELETE", "/api-deployer/services/%s/versions/%s" % (self.service_id, version))
459+
460+
def delete(self):
461+
"""
462+
Deletes this service
463+
464+
You may only delete a service if it has no deployments on it anymore.
465+
"""
466+
return self.client._perform_empty(
467+
"DELETE", "/api-deployer/services/%s" % (self.service_id))
468+
443469

444470
class DSSAPIDeployerServiceSettings(object):
445471
"""The settings of an API Deployer Service.
@@ -466,6 +492,7 @@ def save(self):
466492
"PUT", "/api-deployer/services/%s/settings" % (self.service_id),
467493
body = self.settings)
468494

495+
469496
class DSSAPIDeployerServiceStatus(object):
470497
"""The status of an API Deployer Service.
471498

dataikuapi/dss/app.py

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,42 @@
1-
import sys
1+
import random
22
import re
3-
import os.path as osp
3+
import string
4+
45
from .future import DSSFuture
5-
from dataikuapi.utils import DataikuException
6-
import random, string
6+
77

88
def random_string(length):
99
return ''.join(random.choice(string.ascii_letters) for _ in range(length))
1010

11+
1112
class DSSApp(object):
1213
"""
13-
A handle to interact with a app on the DSS instance.
14-
Do not create this class directly, instead use :meth:`dataikuapi.DSSClient.get_app``
14+
A handle to interact with an application on the DSS instance.
15+
Do not create this class directly, instead use :meth:`dataikuapi.DSSClient.get_app`
1516
"""
1617
def __init__(self, client, app_id):
17-
self.client = client
18-
self.app_id = app_id
18+
self.client = client
19+
self.app_id = app_id
1920

2021
########################################################
2122
# Instances
2223
########################################################
2324

2425
def create_instance(self, instance_key, instance_name, wait=True):
2526
"""
26-
Creates a new instance of this app. Each instance. must have a globally unique
27+
Creates a new instance of this application. Each instance. must have a globally unique
2728
instance key, separate from any project key across the whole DSS instance
2829
2930
:return:
3031
"""
3132
future_resp = self.client._perform_json(
3233
"POST", "/apps/%s/instances" % self.app_id, body={
33-
"targetProjectKey" : instance_key,
34-
"targetProjectName" : instance_name
35-
})
34+
"targetProjectKey": instance_key,
35+
"targetProjectName": instance_name
36+
})
3637
future = DSSFuture(self.client, future_resp.get("jobId", None), future_resp)
3738
if wait:
38-
result = future.wait_for_result()
39+
future.wait_for_result()
3940
return DSSAppInstance(self.client, instance_key)
4041
else:
4142
return future
@@ -46,13 +47,13 @@ def make_random_project_key(self):
4647

4748
def create_temporary_instance(self):
4849
"""
49-
Creates a new temporary instance of this app.
50+
Creates a new temporary instance of this application.
5051
The return value should be used as a Python context manager. Upon exit, the temporary app
5152
instance is deleted
5253
:return a :class:`TemporaryDSSAppInstance`
5354
"""
5455
key = self.make_random_project_key()
55-
instance = self.create_instance(key, key, True)
56+
self.create_instance(key, key, True)
5657
return TemporaryDSSAppInstance(self.client, key)
5758

5859
def list_instance_keys(self):
@@ -85,7 +86,7 @@ def get_manifest(self):
8586
class DSSAppManifest(object):
8687

8788
def __init__(self, client, raw_data, project_key=None):
88-
"""The manifest for an app. Do not create this class directly"""
89+
"""The manifest for an application. Do not create this class directly"""
8990
self.client = client
9091
self.raw_data = raw_data
9192
self.project_key = project_key
@@ -110,34 +111,34 @@ def save(self):
110111
class DSSAppInstance(object):
111112

112113
def __init__(self, client, project_key):
113-
self.client = client
114-
self.project_key = project_key
114+
self.client = client
115+
self.project_key = project_key
115116

116117
def get_as_project(self):
117118
"""
118-
Get the :class:`dataikuapi.dss.project DSSProject` corresponding to this app instance
119+
Get the :class:`dataikuapi.dss.project DSSProject` corresponding to this application instance
119120
"""
120121
return self.client.get_project(self.project_key)
121122

122123
def get_manifest(self):
123124
"""
124-
Get the app manifest for this instance, as a :class:`DSSAppManifest`
125+
Get the application manifest for this instance, as a :class:`DSSAppManifest`
125126
"""
126127
raw_data = self.client._perform_json("GET", "/projects/%s/app-manifest" % self.project_key)
127128
return DSSAppManifest(self.client, raw_data)
128129

130+
129131
class TemporaryDSSAppInstance(DSSAppInstance):
130132
"""internal class"""
131133

132134
def __init__(self, client, project_key):
133135
DSSAppInstance.__init__(self, client,project_key)
134136

135-
136137
def close(self):
137138
self.get_as_project().delete(drop_data=True)
138139

139140
def __enter__(self,):
140141
return self
141142

142143
def __exit__(self, type, value, traceback):
143-
self.close()
144+
self.close()

dataikuapi/dss/continuousactivity.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import time
22
import sys
3-
from dataikuapi.utils import DataikuException
3+
from ..utils import DataikuException
44

55
class DSSContinuousActivity(object):
66
"""
@@ -40,4 +40,4 @@ def get_recipe(self):
4040
Return a handle on the associated recipe
4141
"""
4242
from .recipe import DSSRecipe
43-
return DSSRecipe(self.client, self.project_key, self.recipe_id)
43+
return DSSRecipe(self.client, self.project_key, self.recipe_id)

dataikuapi/dss/flow.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,9 @@ def get_successor_computables(self, node, as_type="dict"):
518518
return self._convert_nodes_list(computables, as_type)
519519

520520
def _convert_nodes_list(self, nodes, as_type):
521+
actual_nodes = [node for node in nodes if node['type'] != 'RUNNABLE_IMPLICIT_RECIPE']
521522
if as_type == "object" or as_type == "objects":
522-
return [self._get_object_from_graph_node(node) for node in nodes]
523+
return [self._get_object_from_graph_node(node) for node in actual_nodes]
523524
else:
524525
return nodes
525526

@@ -532,6 +533,8 @@ def _get_object_from_graph_node(self, node):
532533
return DSSManagedFolder(self.flow.client, self.flow.project.project_key, node["ref"])
533534
elif node["type"] == "COMPUTABLE_SAVED_MODEL":
534535
return DSSSavedModel(self.flow.client, self.flow.project.project_key, node["ref"])
536+
elif node["type"] == "COMPUTABLE_STREAMING_ENDPOINT":
537+
return DSSStreamingEndpoint(self.flow.client, self.flow.project.project_key, node["ref"])
535538
else:
536539
# TODO add streaming elements
537540
raise Exception("unsupported node type: %s" % node["type"])

0 commit comments

Comments
 (0)