Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add create from directory support #1683

Merged
merged 2 commits into from Feb 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
22 changes: 22 additions & 0 deletions kubernetes/e2e_test/test_utils.py
Expand Up @@ -288,6 +288,28 @@ def test_create_implicit_service_list_from_yaml_with_conflict(self):
core_api.delete_namespaced_service(name="mock-4",
namespace="default", body={})

# Tests for creating multi-resource from directory

def test_create_multi_resource_from_directory(self):
"""
Should be able to create a service and a replication controller
from a directory
"""
k8s_client = client.api_client.ApiClient(configuration=self.config)
utils.create_from_directory(
k8s_client, self.path_prefix + "multi-resource/")
core_api = client.CoreV1Api(k8s_client)
svc = core_api.read_namespaced_service(name="mock",
namespace="default")
self.assertIsNotNone(svc)
ctr = core_api.read_namespaced_replication_controller(
name="mock", namespace="default")
self.assertIsNotNone(ctr)
core_api.delete_namespaced_replication_controller(
name="mock", namespace="default", propagation_policy="Background")
core_api.delete_namespaced_service(name="mock",
namespace="default", body={})

# Tests for multi-resource yaml objects

def test_create_from_multi_resource_yaml(self):
Expand Down
@@ -0,0 +1,19 @@
apiVersion: v1
kind: ReplicationController
metadata:
name: mock
spec:
replicas: 1
selector:
app: mock
template:
metadata:
labels:
app: mock
spec:
containers:
- name: mock-container
image: k8s.gcr.io/pause:2.0
ports:
- containerPort: 9949
protocol: TCP
@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: mock
labels:
app: mock
spec:
ports:
- port: 99
protocol: TCP
targetPort: 9949
selector:
app: mock
2 changes: 1 addition & 1 deletion kubernetes/utils/__init__.py
Expand Up @@ -15,5 +15,5 @@
from __future__ import absolute_import

from .create_from_yaml import (FailToCreateError, create_from_dict,
create_from_yaml)
create_from_yaml, create_from_directory)
from .quantity import parse_quantity
74 changes: 72 additions & 2 deletions kubernetes/utils/create_from_yaml.py
Expand Up @@ -14,7 +14,7 @@


import re
from os import path
import os

import yaml

Expand All @@ -24,6 +24,76 @@
LOWER_OR_NUM_FOLLOWED_BY_UPPER_RE = re.compile('([a-z0-9])([A-Z])')


def create_from_directory(
k8s_client,
yaml_dir=None,
verbose=False,
namespace="default",
**kwargs):
"""
Perform an action from files from a directory. Pass True for verbose to
print confirmation information.

Input:
k8s_client: an ApiClient object, initialized with the client args.
yaml_dir: string. Contains the path to directory.
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.

Available parameters for creating <kind>:
: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

Returns:
The list containing the created kubernetes API objects.

Raises:
FailToCreateError which holds list of `client.rest.ApiException`
instances for each object that failed to create.
"""

if not yaml_dir:
raise ValueError(
'`yaml_dir` argument must be provided')
elif not os.path.isdir(yaml_dir):
raise ValueError(
'`yaml_dir` argument must be a path to directory')

files = [os.path.join(yaml_dir, i) for i in os.listdir(yaml_dir)
if os.path.isfile(os.path.join(yaml_dir, i))]
if not files:
raise ValueError(
'`yaml_dir` contains no files')

failures = []
k8s_objects_all = []

for file in files:
try:
k8s_objects = create_from_yaml(k8s_client, file,
verbose=verbose,
namespace=namespace,
**kwargs)
k8s_objects_all.append(k8s_objects)
except FailToCreateError as failure:
failures.extend(failure.api_exceptions)
if failures:
raise FailToCreateError(failures)
return k8s_objects_all


def create_from_yaml(
k8s_client,
yaml_file=None,
Expand Down Expand Up @@ -87,7 +157,7 @@ def create_with(objects):
yml_document_all = yaml_objects
return create_with(yml_document_all)
elif yaml_file:
with open(path.abspath(yaml_file)) as f:
with open(os.path.abspath(yaml_file)) as f:
yml_document_all = yaml.safe_load_all(f)
return create_with(yml_document_all)
else:
Expand Down