diff --git a/python-clusters/attach-aks-cluster/cluster.json b/python-clusters/attach-aks-cluster/cluster.json index 15d5f67..30dd398 100644 --- a/python-clusters/attach-aks-cluster/cluster.json +++ b/python-clusters/attach-aks-cluster/cluster.json @@ -4,7 +4,7 @@ "description" : "Attach to a running AKS cluster", "icon" : "icon-puzzle-piece" }, - + "paramsPythonSetup": "aks_access_modes.py", "architecture" : "KUBERNETES", "params": [ @@ -22,6 +22,16 @@ "parameterSetId" : "connection-info-v2", "mandatory" : true }, + { + "name": "aksAccessMode", + "label": "AKS access mode", + "description": "Choose how DSS should access this AKS cluster. Depending on the mode, DSS will request the corresponding AKS access configuration.", + "type": "SELECT", + "getChoicesFromPython": true, + "disableAutoReload": true, + "mandatory": true, + "defaultValue": "admin" + }, { "name": "cluster", "label" : "Custom AKS cluster name", diff --git a/python-clusters/attach-aks-cluster/cluster.py b/python-clusters/attach-aks-cluster/cluster.py index c18c539..210ebd7 100644 --- a/python-clusters/attach-aks-cluster/cluster.py +++ b/python-clusters/attach-aks-cluster/cluster.py @@ -3,7 +3,7 @@ from azure.mgmt.containerservice import ContainerServiceClient from dku_utils.access import _is_none_or_blank -from dku_utils.cluster import make_overrides +from dku_utils.cluster import make_overrides, fetch_cluster_kubeconfig, get_aks_access_mode from dku_azure.auth import get_credentials_from_connection_info, get_credentials_from_connection_infoV2 from dku_azure.utils import run_and_process_cloud_error, get_instance_metadata, get_subscription_id @@ -45,12 +45,9 @@ def start(self): clusters_client = ContainerServiceClient(credentials, subscription_id) - # Get kubeconfig - logging.info("Fetching kubeconfig for cluster %s in %s", cluster_name, resource_group) - def do_fetch(): - return clusters_client.managed_clusters.list_cluster_admin_credentials(resource_group, cluster_name) - get_credentials_result = run_and_process_cloud_error(do_fetch) - kube_config_content = get_credentials_result.kubeconfigs[0].value.decode('utf8') + # Get kubeconfig + aks_access_mode = get_aks_access_mode(self.config) + kube_config_content = fetch_cluster_kubeconfig(clusters_client, resource_group, cluster_name, aks_access_mode) kube_config_path = os.path.join(os.getcwd(), 'kube_config') with open(kube_config_path, 'w') as f: f.write(kube_config_content) @@ -65,4 +62,3 @@ def do_inspect(): def stop(self, data): pass - diff --git a/python-clusters/create-aks-cluster/cluster.json b/python-clusters/create-aks-cluster/cluster.json index eb4061b..dabbc3e 100644 --- a/python-clusters/create-aks-cluster/cluster.json +++ b/python-clusters/create-aks-cluster/cluster.json @@ -4,6 +4,7 @@ "description": "Create AKS clusters", "icon": "icon-puzzle-piece" }, + "paramsPythonSetup": "aks_access_modes.py", "architecture": "KUBERNETES", "params": [ { @@ -204,6 +205,16 @@ "type": "TEXTAREA", "mandatory": false }, + { + "name": "aksAccessMode", + "label": "AKS access mode", + "description": "Choose how DSS should access this AKS cluster. Depending on the mode, DSS will request the corresponding AKS access configuration.", + "type": "SELECT", + "getChoicesFromPython": true, + "disableAutoReload": true, + "mandatory": true, + "defaultValue": "admin" + }, { "name": "s-legacy", "type": "SEPARATOR", diff --git a/python-clusters/create-aks-cluster/cluster.py b/python-clusters/create-aks-cluster/cluster.py index 61e81d4..5c54829 100644 --- a/python-clusters/create-aks-cluster/cluster.py +++ b/python-clusters/create-aks-cluster/cluster.py @@ -9,7 +9,7 @@ from azure.core.exceptions import ResourceNotFoundError, HttpResponseError from dku_utils.access import _is_none_or_blank -from dku_utils.cluster import make_overrides +from dku_utils.cluster import make_overrides, fetch_cluster_kubeconfig, get_aks_access_mode from dku_utils.taints import Toleration from dku_kube.nvidia_utils import add_gpu_driver_if_needed from dku_azure.auth import get_credentials_from_connection_info, get_credentials_from_connection_infoV2 @@ -406,11 +406,9 @@ def do_creation(): "role_assignment": vnet_role_assignment.as_dict(), }) - logging.info("Fetching kubeconfig for cluster {} in {}...".format(self.cluster_name, resource_group)) - def do_fetch(): - return clusters_client.managed_clusters.list_cluster_admin_credentials(resource_group, self.cluster_name) - get_credentials_result = run_and_process_cloud_error(do_fetch) - kube_config_content = get_credentials_result.kubeconfigs[0].value.decode("utf8") + aks_access_mode = get_aks_access_mode(self.config) + kube_config_content = fetch_cluster_kubeconfig(clusters_client, resource_group, self.cluster_name, aks_access_mode) + logging.info("Writing kubeconfig file...") kube_config_path = os.path.join(os.getcwd(), "kube_config") with open(kube_config_path, 'w') as f: diff --git a/python-lib/dku_utils/aks_access.py b/python-lib/dku_utils/aks_access.py new file mode 100644 index 0000000..d522c77 --- /dev/null +++ b/python-lib/dku_utils/aks_access.py @@ -0,0 +1,11 @@ +AKS_ACCESS_MODE_CLUSTER_ADMIN = "cluster-admin" +AKS_ACCESS_MODE_CLUSTER_USER = "cluster-user" + +DEFAULT_AKS_ACCESS_MODE = AKS_ACCESS_MODE_CLUSTER_ADMIN +AKS_ACCESS_MODE_CHOICES = [ + {"value": AKS_ACCESS_MODE_CLUSTER_ADMIN, "label": "Cluster Admin"}, + {"value": AKS_ACCESS_MODE_CLUSTER_USER, "label": "Cluster User"}, +] +AKS_ACCESS_MODES = { + choice["value"] for choice in AKS_ACCESS_MODE_CHOICES +} diff --git a/python-lib/dku_utils/cluster.py b/python-lib/dku_utils/cluster.py index 6f4cb45..4d19c12 100644 --- a/python-lib/dku_utils/cluster.py +++ b/python-lib/dku_utils/cluster.py @@ -3,7 +3,12 @@ from azure.mgmt.containerservice import ContainerServiceClient from dataiku.core.intercom import backend_json_call from dku_azure.auth import get_credentials_from_connection_info, get_credentials_from_connection_infoV2 -from dku_azure.utils import get_subscription_id +from dku_azure.utils import get_subscription_id, run_and_process_cloud_error +from dku_utils.aks_access import ( + AKS_ACCESS_MODE_CLUSTER_USER, + DEFAULT_AKS_ACCESS_MODE, + AKS_ACCESS_MODES, +) from dku_utils.access import _is_none_or_blank @@ -20,6 +25,28 @@ def make_overrides(config, kube_config, kube_config_path, acr_name=None): return {'container':container_settings} +def get_aks_access_mode(config): + access_mode = config.get("aksAccessMode", DEFAULT_AKS_ACCESS_MODE) + if access_mode not in AKS_ACCESS_MODES: + logging.warning("Unknown AKS access mode %s, defaulting to %s", access_mode, DEFAULT_AKS_ACCESS_MODE) + return DEFAULT_AKS_ACCESS_MODE + return access_mode + + +def fetch_cluster_kubeconfig(clusters_client, resource_group, cluster_name, aks_access_mode): + logging.info("Fetching kubeconfig for cluster %s in %s using AKS access mode %s", cluster_name, resource_group, aks_access_mode) + + def do_fetch(): + if aks_access_mode == AKS_ACCESS_MODE_CLUSTER_USER: + return clusters_client.managed_clusters.list_cluster_user_credentials(resource_group, cluster_name) + return clusters_client.managed_clusters.list_cluster_admin_credentials(resource_group, cluster_name) + + get_credentials_result = run_and_process_cloud_error(do_fetch) + if len(get_credentials_result.kubeconfigs) == 0: + raise Exception("Azure did not return any kubeconfig for cluster %s in %s" % (cluster_name, resource_group)) + return get_credentials_result.kubeconfigs[0].value.decode("utf8") + + def get_cluster_from_connection_info(config, plugin_config): """ Return a ContainerServiceClient after authenticating using the connection info. diff --git a/resource/aks_access_modes.py b/resource/aks_access_modes.py new file mode 100644 index 0000000..e7b82e0 --- /dev/null +++ b/resource/aks_access_modes.py @@ -0,0 +1,5 @@ +from dku_utils.aks_access import AKS_ACCESS_MODE_CHOICES + + +def do(payload, config, plugin_config, inputs): + return {"choices": AKS_ACCESS_MODE_CHOICES}