Skip to content

Commit acdcd4c

Browse files
committed
Merge remote-tracking branch 'origin/release/9.0' into release/10.0
2 parents 7f461cf + ce02b13 commit acdcd4c

File tree

3 files changed

+262
-13
lines changed

3 files changed

+262
-13
lines changed

dataikuapi/dss/admin.py

Lines changed: 246 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -695,13 +695,18 @@ def set_definition(self, env):
695695
696696
* env.permissions, env.usableByAll, env.desc.owner
697697
* env.specCondaEnvironment, env.specPackageList, env.externalCondaEnvName, env.desc.installCorePackages,
698-
env.desc.installJupyterSupport, env.desc.yarnPythonBin
698+
env.desc.corePackagesSet, env.desc.installJupyterSupport, env.desc.yarnPythonBin, env.desc.yarnRBin
699+
env.desc.envSettings, env.desc.allContainerConfs, env.desc.containerConfs,
700+
env.desc.allSparkKubernetesConfs, env.desc.sparkKubernetesConfs
699701
700702
Fields that can be updated in automation node (where {version} is the updated version):
701703
702-
* env.permissions, env.usableByAll, env.owner
704+
* env.permissions, env.usableByAll, env.owner, env.envSettings
703705
* env.{version}.specCondaEnvironment, env.{version}.specPackageList, env.{version}.externalCondaEnvName,
704-
env.{version}.desc.installCorePackages, env.{version}.desc.installJupyterSupport, env.{version}.desc.yarnPythonBin
706+
env.{version}.desc.installCorePackages, env.{version}.corePackagesSet, env.{version}.desc.installJupyterSupport
707+
env.{version}.desc.yarnPythonBin, env.{version}.desc.yarnRBin, env.{version}.desc.allContainerConfs,
708+
env.{version}.desc.containerConfs, env.{version}.desc.allSparkKubernetesConfs,
709+
env.{version}.{version}.desc.sparkKubernetesConfs
705710
706711
Note: this call requires an API key with admin rights
707712
@@ -722,6 +727,39 @@ def get_version_for_project(self, project_key):
722727
return self.client._perform_json(
723728
"GET", "/admin/code-envs/%s/%s/%s/version" % (self.env_lang, self.env_name, project_key))
724729

730+
731+
def get_settings(self):
732+
"""
733+
Returns the settings of this code env as a :class:`DSSCodeEnvSettings`, or one of its subclasses.
734+
735+
Known subclasses of :class:`DSSCodeEnvSettings` include :class:`DSSDesignCodeEnvSettings`
736+
and :class:`DSSAutomationCodeEnvSettings`
737+
738+
You must use :meth:`~DSSCodeEnvSettings.save()` on the returned object to make your changes effective
739+
on the code env.
740+
741+
.. code-block:: python
742+
743+
# Example: setting the required packagd
744+
codeenv = client.get_code_env("PYTHON", "code_env_name")
745+
settings = codeenv.get_settings()
746+
settings.set_required_packages("dash==2.0.0", "bokeh<2.0")
747+
settings.save()
748+
# then proceed to update_packages()
749+
750+
:rtype: :class:`DSSCodeEnvSettings`
751+
"""
752+
data = self.client._perform_json(
753+
"GET", "/admin/code-envs/%s/%s" % (self.env_lang, self.env_name))
754+
755+
# you can't just use deploymentMode to check if it's an automation code
756+
# env, because some modes are common to both types of nodes. So we rely
757+
# on a non-null field that only the automation code envs have
758+
if data.get("versions", None) is not None:
759+
return DSSAutomationCodeEnvSettings(self, data)
760+
else:
761+
return DSSDesignCodeEnvSettings(self, data)
762+
725763

726764
########################################################
727765
# Code env actions
@@ -806,6 +844,171 @@ def get_log(self, log_name):
806844
"GET", "/admin/code-envs/%s/%s/logs/%s" % (self.env_lang, self.env_name, log_name))
807845

808846

847+
class DSSCodeEnvSettings(object):
848+
"""
849+
Base settings class for a DSS code env.
850+
Do not instantiate this class directly, use :meth:`DSSCodeEnv.get_settings`
851+
852+
Use :meth:`save` to save your changes
853+
"""
854+
855+
def __init__(self, codeenv, settings):
856+
self.codeenv = codeenv
857+
self.settings = settings
858+
859+
def get_raw(self):
860+
"""Get the raw code env settings as a dict"""
861+
return self.settings
862+
863+
@property
864+
def env_lang(self):
865+
return self.codeenv.env_lang
866+
867+
@property
868+
def env_name(self):
869+
return self.codeenv.env_name
870+
871+
def save(self):
872+
self.codeenv.client._perform_json(
873+
"PUT", "/admin/code-envs/%s/%s" % (self.env_lang, self.env_name), body=self.settings)
874+
875+
class DSSCodeEnvPackageListBearer(object):
876+
def get_required_packages(self, as_list=False):
877+
"""
878+
Return the list of required packages, as a single string
879+
880+
:param boolean as_list: if True, return the spec as a list of lines; if False, return as a single multiline string
881+
"""
882+
x = self.settings.get("specPackageList", "")
883+
return x.split('\n') if as_list else x
884+
def set_required_packages(self, *packages):
885+
"""
886+
Set the list of required packages
887+
"""
888+
self.settings["specPackageList"] = '\n'.join(packages)
889+
890+
def get_required_conda_spec(self, as_list=False):
891+
"""
892+
Return the list of required conda packages, as a single string
893+
894+
:param boolean as_list: if True, return the spec as a list of lines; if False, return as a single multiline string
895+
"""
896+
x = self.settings.get("specCondaEnvironment", "")
897+
return x.split('\n') if as_list else x
898+
def set_required_conda_spec(self, *spec):
899+
"""
900+
Set the list of required conda packages
901+
"""
902+
self.settings["specCondaEnvironment"] = '\n'.join(packages)
903+
904+
class DSSCodeEnvContainerConfsBearer(object):
905+
def get_built_for_all_container_confs(self):
906+
"""
907+
Return whether the code env creates an image for each container config
908+
"""
909+
return self.settings.get("allContainerConfs", False)
910+
def get_built_container_confs(self):
911+
"""
912+
Return the list of container configs for which the code env builds an image (if not all)
913+
"""
914+
return self.settings.get("containerConfs", [])
915+
def set_built_container_confs(self, *configs, **kwargs):
916+
"""
917+
Set the list of container configs for which the code env builds an image
918+
919+
:param boolean all: if True, an image is built for each config
920+
:param list configs: list of configuration names to build images for
921+
"""
922+
all = kwargs.get("all", False)
923+
self.settings['allContainerConfs'] = all
924+
if not all:
925+
self.settings['containerConfs'] = configs
926+
def built_for_all_spark_kubernetes_confs(self):
927+
"""
928+
Return whether the code env creates an image for each managed Spark over Kubernetes config
929+
"""
930+
return self.settings.get("allSparkKubernetesConfs", False)
931+
def get_built_spark_kubernetes_confs(self):
932+
"""
933+
Return the list of managed Spark over Kubernetes configs for which the code env builds an image (if not all)
934+
"""
935+
return self.settings.get("sparkKubernetesConfs", [])
936+
def set_built_spark_kubernetes_confs(self, *configs, **kwargs):
937+
"""
938+
Set the list of managed Spark over Kubernetes configs for which the code env builds an image
939+
940+
:param boolean all: if True, an image is built for each config
941+
:param list configs: list of configuration names to build images for
942+
"""
943+
all = kwargs.get("all", False)
944+
self.settings['allSparkKubernetesConfs'] = all
945+
if not all:
946+
self.settings['sparkKubernetesConfs'] = configs
947+
948+
949+
class DSSDesignCodeEnvSettings(DSSCodeEnvSettings, DSSCodeEnvPackageListBearer, DSSCodeEnvContainerConfsBearer):
950+
"""
951+
Base settings class for a DSS code env on a design node.
952+
Do not instantiate this class directly, use :meth:`DSSCodeEnv.get_settings`
953+
954+
Use :meth:`save` to save your changes
955+
"""
956+
957+
def __init__(self, codeenv, settings):
958+
super(DSSDesignCodeEnvSettings, self).__init__(codeenv, settings)
959+
960+
961+
class DSSAutomationCodeEnvSettings(DSSCodeEnvSettings, DSSCodeEnvContainerConfsBearer):
962+
"""
963+
Base settings class for a DSS code env on an automation node.
964+
Do not instantiate this class directly, use :meth:`DSSCodeEnv.get_settings`
965+
966+
Use :meth:`save` to save your changes
967+
"""
968+
969+
def __init__(self, codeenv, settings):
970+
super(DSSAutomationCodeEnvSettings, self).__init__(codeenv, settings)
971+
972+
973+
def get_version(self, version_id=None):
974+
"""
975+
Get a specific code env version (for versioned envs) or the single
976+
version
977+
978+
:param string version_id: for versioned code env, identifier of the desired version
979+
980+
:rtype: :class:`DSSAutomationCodeEnvVersionSettings`
981+
"""
982+
deployment_mode = self.settings.get("deploymentMode", None)
983+
if deployment_mode in ['AUTOMATION_SINGLE']:
984+
return DSSAutomationCodeEnvVersionSettings(self.codeenv, self.settings.get('currentVersion', {}))
985+
elif deployment_mode in ['AUTOMATION_VERSIONED']:
986+
versions = self.settings.get("versions", [])
987+
version_ids = [v.get('versionId') for v in versions]
988+
if version_id is None:
989+
raise Exception("A version id is required in a versioned code env. Existing ids: %s" % ', '.join(version_ids))
990+
for version in versions:
991+
if version_id == version.get("versionId"):
992+
return DSSAutomationCodeEnvVersionSettings(self.codeenv, version)
993+
raise Exception("Version %s not found in : %s" % (version_id, ', '.join(version_ids)))
994+
elif deployment_mode in ['PLUGIN_NON_MANAGED', 'PLUGIN_MANAGED', 'AUTOMATION_NON_MANAGED_PATH', 'EXTERNAL_CONDA_NAMED']:
995+
return DSSAutomationCodeEnvVersionSettings(self.codeenv, self.settings.get('noVersion', {}))
996+
else:
997+
raise Exception("Unexpected deployment mode %s for an automation node code env. Alter the settings directly with get_raw()", deployment_mode)
998+
999+
class DSSAutomationCodeEnvVersionSettings(DSSCodeEnvPackageListBearer):
1000+
"""
1001+
Base settings class for a DSS code env version on an automation node.
1002+
Do not instantiate this class directly, use :meth:`DSSAutomationCodeEnvSettings.get_version`
1003+
1004+
Use :meth:`save` on the :class:`DSSAutomationCodeEnvSettings` to save your changes
1005+
"""
1006+
1007+
def __init__(self, codeenv_settings, version_settings):
1008+
self.codeenv_settings = codeenv_settings
1009+
self.settings = version_settings
1010+
1011+
8091012
class DSSGlobalApiKey(object):
8101013
"""
8111014
A global API key on the DSS instance
@@ -1004,3 +1207,43 @@ def get_raw(self):
10041207
Gets the whole status as a raw dictionary.
10051208
"""
10061209
return self.status
1210+
1211+
class DSSGlobalUsageSummary(object):
1212+
"""
1213+
The summary of the usage of the DSS instance.
1214+
Do not create this directly, use :meth:`dataikuapi.dss.DSSClient.get_global_usage_summary`
1215+
"""
1216+
def __init__(self, data):
1217+
self.data = data
1218+
1219+
@property
1220+
def raw(self):
1221+
return self.data
1222+
1223+
@property
1224+
def projects_count(self):
1225+
return self.data["projects"]
1226+
1227+
@property
1228+
def total_datasets_count(self):
1229+
return self.data["datasets"]["all"]
1230+
1231+
@property
1232+
def total_recipes_count(self):
1233+
return self.data["recipes"]["all"]
1234+
1235+
@property
1236+
def total_jupyter_notebooks_count(self):
1237+
return self.data["notebooks"]["nbJupyterNotebooks"]
1238+
1239+
@property
1240+
def total_sql_notebooks_count(self):
1241+
return self.data["notebooks"]["nbSqlNotebooks"]
1242+
1243+
@property
1244+
def total_scenarios_count(self):
1245+
return self.data["scenarios"]["all"]
1246+
1247+
@property
1248+
def total_active_with_trigger_scenarios_count(self):
1249+
return self.data["scenarios"]["activeWithTriggers"]

dataikuapi/dss/tools/codegen.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json, copy, re
2-
from dataikuapi.dss.recipe import *
3-
from dataikuapi.dss.dataset import *
2+
from ..recipe import *
3+
from ..dataset import *
44

55
class _IndentContext(object):
66
def __init__(self, flow_code_generator):

dataikuapi/dssclient.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
from requests import exceptions
55
from requests.auth import HTTPBasicAuth
66

7-
from dataikuapi.dss.notebook import DSSNotebook
7+
from .dss.notebook import DSSNotebook
88
from .dss.future import DSSFuture
99
from .dss.projectfolder import DSSProjectFolder
1010
from .dss.project import DSSProject
1111
from .dss.app import DSSApp
1212
from .dss.plugin import DSSPlugin
13-
from .dss.admin import DSSUser, DSSOwnUser, DSSGroup, DSSConnection, DSSGeneralSettings, DSSCodeEnv, DSSGlobalApiKey, DSSCluster
13+
from .dss.admin import DSSUser, DSSOwnUser, DSSGroup, DSSConnection, DSSGeneralSettings, DSSCodeEnv, DSSGlobalApiKey, DSSCluster, DSSGlobalUsageSummary
1414
from .dss.meaning import DSSMeaning
1515
from .dss.sqlquery import DSSSQLQuery
1616
from .dss.discussion import DSSObjectDiscussions
@@ -486,22 +486,28 @@ def create_connection(self, name, type, params=None, usable_by='ALL', allowed_gr
486486
# Code envs
487487
########################################################
488488

489-
def list_code_envs(self):
489+
def list_code_envs(self, as_objects=False):
490490
"""
491491
List all code envs setup on the DSS instance
492492
493493
Note: this call requires an API key with admin rights
494494
495+
:param boolean as_objects: if True, each returned item will be a :class:`dataikuapi.dss.future.DSSCodeEnv`
495496
:returns: a list of code envs. Each code env is a dict containing at least "name", "type" and "language"
496497
"""
497-
return self._perform_json(
498+
list = self._perform_json(
498499
"GET", "/admin/code-envs/")
500+
if as_objects:
501+
return [DSSCodeEnv(self, e.get("envLang"), e.get("envName")) for e in list]
502+
else:
503+
return list
499504

500505
def get_code_env(self, env_lang, env_name):
501506
"""
502507
Get a handle to interact with a specific code env
503508
504-
:param str name: the name of the desired code env
509+
:param env_lang: the language (PYTHON or R) of the new code env
510+
:param env_name: the name of the new code env
505511
:returns: A :class:`dataikuapi.dss.admin.DSSCodeEnv` code env handle
506512
"""
507513
return DSSCodeEnv(self, env_lang, env_name)
@@ -757,12 +763,12 @@ def log_custom_audit(self, custom_type, custom_params=None):
757763

758764
def get_global_usage_summary(self, with_per_project=False):
759765
"""
760-
Summarize the contents of the instance
761-
766+
Gets a summary of the global usage of this DSS instance (number of projects, datasets, ...)
762767
:returns: a summary object
763768
"""
764-
return self._perform_json(
769+
data = self._perform_json(
765770
"GET", "/admin/monitoring/global-usage-summary", params={'withPerProject':with_per_project})
771+
return DSSGlobalUsageSummary(data)
766772

767773
########################################################
768774
# Variables

0 commit comments

Comments
 (0)