From 06776ced35b7d2fe031006bfeaeb8fc3940e0737 Mon Sep 17 00:00:00 2001 From: "Johannes M. Scheuermann" Date: Mon, 25 Mar 2019 16:17:12 +0100 Subject: [PATCH 1/3] Rebase code and add namespaced method --- kubernetes/e2e_test/test_utils.py | 51 +++++++++++++++++++ kubernetes/utils/__init__.py | 3 +- kubernetes/utils/create_from_yaml.py | 75 +++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 8 deletions(-) diff --git a/kubernetes/e2e_test/test_utils.py b/kubernetes/e2e_test/test_utils.py index 6c40361ff8..ddb41dad13 100644 --- a/kubernetes/e2e_test/test_utils.py +++ b/kubernetes/e2e_test/test_utils.py @@ -24,7 +24,17 @@ class TestUtils(unittest.TestCase): def setUpClass(cls): cls.config = base.get_e2e_configuration() cls.path_prefix = "kubernetes/e2e_test/test_yaml/" + cls.test_namespace = "e2e-test-utils" + k8s_client = client.api_client.ApiClient(configuration=cls.config) + core_v1 = client.CoreV1Api(api_client=k8s_client) + body = client.V1Namespace(metadata=client.V1ObjectMeta(name=cls.test_namespace)) + core_v1.create_namespace(body=body) + @classmethod + def tearDownClass(cls): + k8s_client = client.api_client.ApiClient(configuration=cls.config) + core_v1 = client.CoreV1Api(api_client=k8s_client) + core_v1.delete_namespace(name=cls.test_namespace) # Tests for creating individual API objects def test_create_apps_deployment_from_yaml(self): @@ -317,3 +327,44 @@ def test_create_from_multi_resource_yaml_with_multi_conflicts(self): ext_api.delete_namespaced_deployment( name="triple-nginx", namespace="default", body={}) + + def test_create_namespaces_apps_deployment_from_yaml(self): + """ + Should be able to create an apps/v1beta1 deployment. + """ + k8s_client = client.api_client.ApiClient(configuration=self.config) + utils.create_namespaced_from_yaml( + k8s_client, self.path_prefix + "apps-deployment.yaml", namespace=self.test_namespace) + app_api = client.AppsV1beta1Api(k8s_client) + dep = app_api.read_namespaced_deployment(name="nginx-app", + namespace=self.test_namespace) + self.assertIsNotNone(dep) + app_api.delete_namespaced_deployment( + name="nginx-app", namespace=self.test_namespace, + body={}) + + def test_create_from_list_in_multi_resource_yaml(self): + """ + Should be able to create the items in the PodList and a deployment + specified in the multi-resource file + """ + k8s_client = client.api_client.ApiClient(configuration=self.config) + utils.create_namespaced_from_yaml( + k8s_client, self.path_prefix + "multi-resource-with-list.yaml", namespace=self.test_namespace) + core_api = client.CoreV1Api(k8s_client) + app_api = client.AppsV1beta1Api(k8s_client) + pod_0 = core_api.read_namespaced_pod( + name="mock-pod-0", namespace=self.test_namespace) + self.assertIsNotNone(pod_0) + pod_1 = core_api.read_namespaced_pod( + name="mock-pod-1", namespace=self.test_namespace) + self.assertIsNotNone(pod_1) + dep = app_api.read_namespaced_deployment( + name="mock", namespace=self.test_namespace) + self.assertIsNotNone(dep) + core_api.delete_namespaced_pod( + name="mock-pod-0", namespace=self.test_namespace, body={}) + core_api.delete_namespaced_pod( + name="mock-pod-1", namespace=self.test_namespace, body={}) + app_api.delete_namespaced_deployment( + name="mock", namespace=self.test_namespace, body={}) diff --git a/kubernetes/utils/__init__.py b/kubernetes/utils/__init__.py index 2b8597c2fb..dee72861e2 100644 --- a/kubernetes/utils/__init__.py +++ b/kubernetes/utils/__init__.py @@ -14,4 +14,5 @@ from __future__ import absolute_import -from .create_from_yaml import FailToCreateError, create_from_yaml +from .create_from_yaml import (FailToCreateError, create_from_yaml, + create_namespaced_from_yaml) diff --git a/kubernetes/utils/create_from_yaml.py b/kubernetes/utils/create_from_yaml.py index 29be813b1f..fce1b939c1 100644 --- a/kubernetes/utils/create_from_yaml.py +++ b/kubernetes/utils/create_from_yaml.py @@ -55,6 +55,52 @@ def create_from_yaml( Valid values are: - All: all dry run stages will be processed """ + create_namespaced_from_yaml( + k8s_client, + yaml_file, + verbose, + namespace="default", + **kwargs + ) + + +def create_namespaced_from_yaml( + k8s_client, + yaml_file, + verbose=False, + namespace="default", + **kwargs): + """ + Perform an action from a yaml file. Pass True for verbose to + print confirmation information. + Input: + yaml_file: string. Contains the path to yaml file. + k8s_client: an ApiClient object, initialized with the client args. + verbose: If True, print confirmation from the create action. + Default is False. + namespace: string. Contains the namespace to create all + resources inside + + Returns: + An k8s api object or list of apis objects created from YAML. + When a single object is generated, return type is dependent + on output_list. + + Throws a FailToCreateError exception if creation of any object + fails with helpful messages from the server. + + Available parameters for creating : + :param async_req bool + :param bool include_uninitialized: If true, partially initialized + resources are included in the response. + :param str pretty: If 'true', then the output is pretty printed. + :param str dry_run: When present, indicates that modifications + should not be persisted. An invalid or unrecognized dryRun + directive will result in an error response and no further + processing of the request. + Valid values are: - All: all dry run stages will be processed + """ + with open(path.abspath(yaml_file)) as f: yml_document_all = yaml.safe_load_all(f) api_exceptions = [] @@ -72,15 +118,15 @@ def create_from_yaml( yml_object["apiVersion"] = yml_document["apiVersion"] yml_object["kind"] = kind try: - create_from_yaml_single_item( - k8s_client, yml_object, verbose, **kwargs) + create_namespaced_from_yaml_single_item( + k8s_client, yml_object, verbose, namespace, **kwargs) except client.rest.ApiException as api_exception: api_exceptions.append(api_exception) else: # This is a single object. Call the single item method try: - create_from_yaml_single_item( - k8s_client, yml_document, verbose, **kwargs) + create_namespaced_from_yaml_single_item( + k8s_client, yml_document, verbose, namespace, **kwargs) except client.rest.ApiException as api_exception: api_exceptions.append(api_exception) # In case we have exceptions waiting for us, raise them @@ -89,7 +135,24 @@ def create_from_yaml( def create_from_yaml_single_item( - k8s_client, yml_object, verbose=False, **kwargs): + k8s_client, + yml_object, + verbose=False, + **kwargs): + create_namespaced_from_yaml_single_item( + k8s_client, + yml_object, + verbose, + namespace="default", + **kwargs) + + +def create_namespaced_from_yaml_single_item( + k8s_client, + yml_object, + verbose=False, + namespace="default", + **kwargs): group, _, version = yml_object["apiVersion"].partition("/") if version == "": version = group @@ -108,8 +171,6 @@ def create_from_yaml_single_item( # if any if "namespace" in yml_object["metadata"]: namespace = yml_object["metadata"]["namespace"] - else: - namespace = "default" # Expect the user to create namespaced objects more often if hasattr(k8s_api, "create_namespaced_{0}".format(kind)): resp = getattr(k8s_api, "create_namespaced_{0}".format(kind))( From 15d36c968888b60d6f778062950974e5a00d8690 Mon Sep 17 00:00:00 2001 From: "Johannes M. Scheuermann" Date: Tue, 26 Mar 2019 21:45:14 +0100 Subject: [PATCH 2/3] Use optional parameter for method --- kubernetes/e2e_test/test_utils.py | 4 +- kubernetes/utils/__init__.py | 3 +- kubernetes/utils/create_from_yaml.py | 60 +--------------------------- 3 files changed, 5 insertions(+), 62 deletions(-) diff --git a/kubernetes/e2e_test/test_utils.py b/kubernetes/e2e_test/test_utils.py index ddb41dad13..f3adaf7c25 100644 --- a/kubernetes/e2e_test/test_utils.py +++ b/kubernetes/e2e_test/test_utils.py @@ -333,7 +333,7 @@ def test_create_namespaces_apps_deployment_from_yaml(self): Should be able to create an apps/v1beta1 deployment. """ k8s_client = client.api_client.ApiClient(configuration=self.config) - utils.create_namespaced_from_yaml( + utils.create_from_yaml( k8s_client, self.path_prefix + "apps-deployment.yaml", namespace=self.test_namespace) app_api = client.AppsV1beta1Api(k8s_client) dep = app_api.read_namespaced_deployment(name="nginx-app", @@ -349,7 +349,7 @@ def test_create_from_list_in_multi_resource_yaml(self): specified in the multi-resource file """ k8s_client = client.api_client.ApiClient(configuration=self.config) - utils.create_namespaced_from_yaml( + utils.create_from_yaml( k8s_client, self.path_prefix + "multi-resource-with-list.yaml", namespace=self.test_namespace) core_api = client.CoreV1Api(k8s_client) app_api = client.AppsV1beta1Api(k8s_client) diff --git a/kubernetes/utils/__init__.py b/kubernetes/utils/__init__.py index dee72861e2..2b8597c2fb 100644 --- a/kubernetes/utils/__init__.py +++ b/kubernetes/utils/__init__.py @@ -14,5 +14,4 @@ from __future__ import absolute_import -from .create_from_yaml import (FailToCreateError, create_from_yaml, - create_namespaced_from_yaml) +from .create_from_yaml import FailToCreateError, create_from_yaml diff --git a/kubernetes/utils/create_from_yaml.py b/kubernetes/utils/create_from_yaml.py index fce1b939c1..c14850d80c 100644 --- a/kubernetes/utils/create_from_yaml.py +++ b/kubernetes/utils/create_from_yaml.py @@ -22,49 +22,6 @@ def create_from_yaml( - k8s_client, - yaml_file, - verbose=False, - **kwargs): - """ - Perform an action from a yaml file. Pass True for verbose to - print confirmation information. - Input: - yaml_file: string. Contains the path to yaml file. - k8s_client: an ApiClient object, initialized with the client args. - verbose: If True, print confirmation from the create action. - Default is False. - - Returns: - An k8s api object or list of apis objects created from YAML. - When a single object is generated, return type is dependent - on output_list. - - Throws a FailToCreateError exception if creation of any object - fails with helpful messages from the server. - - Available parameters for creating : - :param async_req bool - :param bool include_uninitialized: If true, partially initialized - resources are included in the response. - :param str pretty: If 'true', then the output is pretty printed. - :param str dry_run: When present, indicates that modifications - should not be persisted. An invalid or unrecognized dryRun - directive will result in an error response and no further - processing of the request. - Valid values are: - All: all dry run stages will be processed - """ - - create_namespaced_from_yaml( - k8s_client, - yaml_file, - verbose, - namespace="default", - **kwargs - ) - - -def create_namespaced_from_yaml( k8s_client, yaml_file, verbose=False, @@ -118,14 +75,14 @@ def create_namespaced_from_yaml( yml_object["apiVersion"] = yml_document["apiVersion"] yml_object["kind"] = kind try: - create_namespaced_from_yaml_single_item( + create_from_yaml_single_item( k8s_client, yml_object, verbose, namespace, **kwargs) except client.rest.ApiException as api_exception: api_exceptions.append(api_exception) else: # This is a single object. Call the single item method try: - create_namespaced_from_yaml_single_item( + create_from_yaml_single_item( k8s_client, yml_document, verbose, namespace, **kwargs) except client.rest.ApiException as api_exception: api_exceptions.append(api_exception) @@ -135,19 +92,6 @@ def create_namespaced_from_yaml( def create_from_yaml_single_item( - k8s_client, - yml_object, - verbose=False, - **kwargs): - create_namespaced_from_yaml_single_item( - k8s_client, - yml_object, - verbose, - namespace="default", - **kwargs) - - -def create_namespaced_from_yaml_single_item( k8s_client, yml_object, verbose=False, From 80339ef3f74fa256869b49f8ea0789fc3b86b51f Mon Sep 17 00:00:00 2001 From: "Johannes M. Scheuermann" Date: Mon, 8 Apr 2019 07:52:01 +0200 Subject: [PATCH 3/3] Add more documentation to new namespace parameter --- kubernetes/utils/create_from_yaml.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kubernetes/utils/create_from_yaml.py b/kubernetes/utils/create_from_yaml.py index c14850d80c..5c116beb58 100644 --- a/kubernetes/utils/create_from_yaml.py +++ b/kubernetes/utils/create_from_yaml.py @@ -36,7 +36,10 @@ def create_from_yaml( verbose: If True, print confirmation from the create action. Default is False. namespace: string. Contains the namespace to create all - resources inside + resources inside. The namespace must preexist otherwise + the resource creation will fail. If the API object in + the yaml file already contains a namespace definition + this parameter has no effect. Returns: An k8s api object or list of apis objects created from YAML.