diff --git a/kubernetes_asyncio/utils/__init__.py b/kubernetes_asyncio/utils/__init__.py index 3c1833328..b1244b9a0 100644 --- a/kubernetes_asyncio/utils/__init__.py +++ b/kubernetes_asyncio/utils/__init__.py @@ -15,5 +15,6 @@ from __future__ import absolute_import from .create_from_yaml import ( - FailToCreateError, create_from_yaml, create_from_yaml_single_item, + FailToCreateError, create_from_dict, create_from_yaml, + create_from_yaml_single_item, ) diff --git a/kubernetes_asyncio/utils/create_from_yaml.py b/kubernetes_asyncio/utils/create_from_yaml.py index a7bc4e5f9..3ef14b09e 100644 --- a/kubernetes_asyncio/utils/create_from_yaml.py +++ b/kubernetes_asyncio/utils/create_from_yaml.py @@ -61,35 +61,94 @@ async def create_from_yaml( with open(path.abspath(yaml_file)) as f: yml_document_all = yaml.safe_load_all(f) api_exceptions = [] + k8s_objects = [] # Load all documents from a single YAML file for yml_document in yml_document_all: - # If it is a list type, will need to iterate its items - if "List" in yml_document["kind"]: - # Could be "List" or "Pod/Service/...List" - # This is a list type. iterate within its items - kind = yml_document["kind"].replace("List", "") - for yml_object in yml_document["items"]: - # Mitigate cases when server returns a xxxList object - # See kubernetes-client/python#586 - if kind != "": - yml_object["apiVersion"] = yml_document["apiVersion"] - yml_object["kind"] = kind - try: - await 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: - await create_from_yaml_single_item( - k8s_client, yml_document, verbose, namespace, **kwargs) - except client.rest.ApiException as api_exception: - api_exceptions.append(api_exception) + try: + created = await create_from_dict(k8s_client, yml_document, + verbose, namespace=namespace, + **kwargs) + k8s_objects.append(created) + except FailToCreateError as failure: + api_exceptions.extend(failure) + # In case we have exceptions waiting for us, raise them if api_exceptions: raise FailToCreateError(api_exceptions) + return k8s_objects + + +async def create_from_dict( + k8s_client, + data, + 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. + data: a dictionary holding valid kubernetes objects + verbose: If True, print confirmation from the create action. + Default is False. + namespace: string. Contains the namespace to create all + 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 dict. + 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 + """ + api_exceptions = [] + k8s_objects = [] + + # If it is a list type, will need to iterate its items + if "List" in data["kind"]: + # Could be "List" or "Pod/Service/...List" + # This is a list type. iterate within its items + kind = data["kind"].replace("List", "") + for yml_object in data["items"]: + # Mitigate cases when server returns a xxxList object + # See kubernetes-client/python#586 + if kind != "": + yml_object["apiVersion"] = data["apiVersion"] + yml_object["kind"] = kind + try: + created = await create_from_yaml_single_item( + k8s_client, yml_object, verbose, namespace, **kwargs) + k8s_objects.append(created) + except client.rest.ApiException as api_exception: + api_exceptions.append(api_exception) + else: + # This is a single object. Call the single item method + try: + created = await create_from_yaml_single_item( + k8s_client, data, verbose, namespace, **kwargs) + k8s_objects.append(created) + except client.rest.ApiException as api_exception: + api_exceptions.append(api_exception) + + if api_exceptions: + raise FailToCreateError(api_exceptions) + + return k8s_objects + async def create_from_yaml_single_item( k8s_client, @@ -126,6 +185,7 @@ async def create_from_yaml_single_item( body=yml_object, **kwargs) if verbose: print("{0} created. status='{1}'".format(kind, str(resp.status))) + return resp class FailToCreateError(Exception): diff --git a/kubernetes_asyncio/utils/create_from_yaml_test.py b/kubernetes_asyncio/utils/create_from_yaml_test.py index 85588855d..671984425 100644 --- a/kubernetes_asyncio/utils/create_from_yaml_test.py +++ b/kubernetes_asyncio/utils/create_from_yaml_test.py @@ -14,7 +14,7 @@ from asynctest import CoroutineMock, TestCase -from kubernetes_asyncio.utils import create_from_yaml +from kubernetes_asyncio.utils import create_from_dict, create_from_yaml class CreateFromYamlTest(TestCase): @@ -22,13 +22,39 @@ class CreateFromYamlTest(TestCase): async def test_create_from_yaml(self): api_client = CoroutineMock() api_client.call_api = CoroutineMock() + api_client.call_api.return_value = 'mock-value' - await create_from_yaml(api_client, 'examples/nginx-deployment.yaml') + created = await create_from_yaml(api_client, 'examples/nginx-deployment.yaml') # simple check for api call self.assertEqual(api_client.call_api.call_args[0][0], '/apis/apps/v1/namespaces/{namespace}/deployments') + # returned values + self.assertEqual(created, [['mock-value']]) + + async def test_create_from_dict(self): + api_client = CoroutineMock() + api_client.call_api = CoroutineMock() + api_client.call_api.return_value = 'mock-value' + + created = await create_from_dict(api_client, { + 'apiVersion': 'apps/v1', + 'kind': 'Deployment', + 'metadata': { + 'name': 'nginx-deployment'}, + 'spec': { + 'replicas': 3, + } + }) + + # simple check for api call + self.assertEqual(api_client.call_api.call_args[0][0], + '/apis/apps/v1/namespaces/{namespace}/deployments') + + # returned values + self.assertEqual(created, ['mock-value']) + if __name__ == '__main__': import asynctest