Add k8sclient unit tests 00/79400/1
authorJack Lucas <jflucas@research.att.com>
Wed, 27 Feb 2019 16:38:13 +0000 (11:38 -0500)
committerJack Lucas <jflucas@research.att.com>
Thu, 28 Feb 2019 21:06:09 +0000 (16:06 -0500)
Change-Id: I4b664865618bf87822af325e2c2dd43e71c0bdac
Issue-ID: DCAEGEN2-1261
Signed-off-by: Jack Lucas <jflucas@research.att.com>
k8s/.coveragerc [new file with mode: 0644]
k8s/LICENSE.txt
k8s/k8s-node-type.yaml
k8s/k8sclient/k8sclient.py
k8s/pom.xml
k8s/setup.py
k8s/tests/test_k8sclient.py

diff --git a/k8s/.coveragerc b/k8s/.coveragerc
new file mode 100644 (file)
index 0000000..088c2da
--- /dev/null
@@ -0,0 +1,21 @@
+# .coveragerc to control coverage.py
+[run]
+branch = True
+
+[report]
+# Regexes for lines to exclude from consideration
+exclude_lines =
+    # Have to re-enable the standard pragma
+    pragma: no cover
+
+    # Don't complain about missing debug-only code:
+    def __repr__
+    if self\.debug
+
+    # Don't complain if tests don't hit defensive assertion code:
+    raise AssertionError
+    raise NotImplementedError
+
+    # Don't complain if non-runnable code isn't run:
+    if 0:
+    if __name__ == .__main__.:
index e266d0a..43098d1 100644 (file)
@@ -1,7 +1,7 @@
 ============LICENSE_START=======================================================
 org.onap.dcae
 ================================================================================
-Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
+Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
 ================================================================================
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
index f63f822..166e430 100644 (file)
 tosca_definitions_version: cloudify_dsl_1_3
 
 imports:
-    - http://www.getcloudify.org/spec/cloudify/4.2/types.yaml
+    - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
 
 plugins:
   k8s:
     executor: 'central_deployment_agent'
     package_name: k8splugin
-    package_version: 1.4.6
+    package_version: 1.4.7
 
 data_types:
 
@@ -123,9 +123,9 @@ node_types:
                 default: {}
                 description: >
                   This is used to specify the cpu and memory request and limit for container.
-                  Please specify "requests" property and/or a "limits" property, with subproproperties 
+                  Please specify "requests" property and/or a "limits" property, with subproproperties
                   for cpu and memory. (https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/)
-                   
+
 
             log_info:
               type: dcae.types.LoggingInfo
index 84ca84f..31631ad 100644 (file)
@@ -38,7 +38,7 @@ FACTORS = {None: 1, "s": 1, "m": 60, "h": 3600}
 # group 3: protocol
 # group 4: host port
 PORTS = re.compile("^([0-9]+)(/(udp|UDP|tcp|TCP))?:([0-9]+)$")
-   
+
 def _create_deployment_name(component_name):
     return "dep-{0}".format(component_name)
 
@@ -126,7 +126,7 @@ def _create_resources(resources=None):
         resources_obj = client.V1ResourceRequirements(
           limits = resources.get("limits"),
           requests = resources.get("requests")
-        )   
+        )
         return resources_obj
     else:
         return None
@@ -398,9 +398,9 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
     }
 
     try:
-        _configure_api()
 
         # Get API handles
+        _configure_api()
         core = client.CoreV1Api()
         ext = client.ExtensionsV1beta1Api()
 
index 844f214..45c5a39 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0"?>
 <!--
 ================================================================================
-Copyright (c) 2017-2018 AT&T Intellectual Property. All rights reserved.
+Copyright (c) 2017-2019 AT&T Intellectual Property. All rights reserved.
 ================================================================================
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@ ECOMP is a trademark and service mark of AT&T Intellectual Property.
   <groupId>org.onap.dcaegen2.platform.plugins</groupId>
   <artifactId>k8s</artifactId>
   <name>k8s-plugin</name>
-  <version>1.4.5-SNAPSHOT</version>
+  <version>1.4.7-SNAPSHOT</version>
   <url>http://maven.apache.org</url>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
index 36fbe05..9ad35bf 100644 (file)
@@ -23,7 +23,7 @@ from setuptools import setup
 setup(
     name='k8splugin',
     description='Cloudify plugin for containerized components deployed using Kubernetes',
-    version="1.4.6",
+    version="1.4.7",
     author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
     packages=['k8splugin','k8sclient','msb','configure'],
     zip_safe=False,
index e985def..2511239 100644 (file)
@@ -102,7 +102,7 @@ def test_parse_ports():
             ("9101/udp:31043", (9101, 31043, "UDP"))
         ]
     ]
-    
+
     bad_ports = [
         "9101",
         "9101:",
@@ -130,10 +130,10 @@ def test_parse_ports():
         (9661,"TCP") : 19661,
         (9661,"UDP") : 19661,
         (8080,"TCP") : 8080
-    }  
+    }
 
     for test_case in good_ports:
-        container_ports, port_map = _parse_ports([test_case["in"]])  
+        container_ports, port_map = _parse_ports([test_case["in"]])
         (cport, hport, proto) = test_case["ex"]
         assert container_ports == [(cport, proto)]
         assert port_map == {(cport, proto) : hport}
@@ -153,3 +153,122 @@ def test_create_container():
 
     assert container.ports[0].container_port == 80 and container.ports[0].protocol == "TCP"
     assert container.ports[1].container_port == 53 and container.ports[1].protocol == "UDP"
+
+def test_create_probe():
+    from k8sclient.k8sclient import _create_probe
+    from kubernetes import client
+
+    http_checks = [
+        {"type" : "http", "endpoint" : "/example/health"}
+    ]
+
+    script_checks = [
+        {"type" : "docker", "script": "/opt/app/health_check.sh"}
+    ]
+
+    for hc in http_checks:
+        probe = _create_probe(hc, 13131)
+        assert probe.http_get.path == hc["endpoint"]
+        assert probe.http_get.scheme == hc["type"].upper()
+
+    for hc in script_checks:
+        probe = _create_probe(hc, 13131)
+        assert probe._exec.command[0] == hc["script"]
+
+def test_deploy(monkeypatch):
+    import k8sclient.k8sclient
+    from kubernetes import client
+
+    # We need to patch the kubernetes 'client' module
+    # Awkward because of the way it requires a function call
+    # to get an API object
+    core = client.CoreV1Api()
+    ext = client.ExtensionsV1beta1Api()
+
+    def pseudo_deploy(namespace, dep):
+        return dep
+
+    def pseudo_service(namespace, svc):
+        return svc
+
+    # patched_core returns a CoreV1Api object with the
+    # create_namespaced_service method stubbed out so that there
+    # is no attempt to call the k8s API server
+    def patched_core():
+        monkeypatch.setattr(core, "create_namespaced_service", pseudo_service)
+        return core
+
+    # patched_ext returns an ExtensionsV1beta1Api object with the
+    # create_namespaced_deployment method stubbed out so that there
+    # is no attempt to call the k8s API server
+    def patched_ext():
+        monkeypatch.setattr(ext,"create_namespaced_deployment", pseudo_deploy)
+        return ext
+
+    def pseudo_configure():
+        pass
+
+    monkeypatch.setattr(k8sclient.k8sclient,"_configure_api", pseudo_configure)
+    monkeypatch.setattr(client, "CoreV1Api", patched_core)
+    monkeypatch.setattr(client,"ExtensionsV1beta1Api", patched_ext)
+
+    k8s_test_config = {
+        "image_pull_secrets" : ["secret0", "secret1"],
+        "filebeat" : {
+            "log_path": "/var/log/onap",
+            "data_path": "/usr/share/filebeat/data",
+            "config_path": "/usr/share/filebeat/filebeat.yml",
+            "config_subpath": "filebeat.yml",
+            "image" : "filebeat-repo/filebeat:latest",
+            "config_map" : "dcae-filebeat-configmap"
+        },
+        "tls" : {
+            "cert_path": "/opt/certs",
+            "image": "tlsrepo/tls-init-container:1.2.3"
+        }
+    }
+
+    resources = {
+        "limits": {
+            "cpu" : 0.5,
+            "memory" : "2Gi"
+        },
+        "requests": {
+            "cpu" : 0.5,
+            "memory" : "2Gi"
+        }
+    }
+
+    kwargs = {
+        "volumes": [
+            {"host":{"path": "/path/on/host"}, "container":{"bind":"/path/on/container","mode":"rw"}}
+        ],
+        "ports": ["80:0", "443:0"],
+        "env": {"name0": "value0", "name1": "value1"},
+        "log_info": {"log_directory": "/path/to/container/log/directory"},
+        "tls_info": {"use_tls": True, "cert_directory": "/path/to/container/cert/directory" },
+        "readiness": {"type": "http", "endpoint" : "/ready"}
+    }
+    dep, deployment_description = k8sclient.k8sclient.deploy("k8stest","testcomponent","example.com/testcomponent:1.4.3",1,False, k8s_test_config, resources, **kwargs)
+
+    assert deployment_description["deployment"] == "dep-testcomponent"
+    assert deployment_description["namespace"] == "k8stest"
+    assert deployment_description["services"][0] == "testcomponent"
+
+    # For unit test purposes, we want to make sure that the deployment object
+    # we're passing to the k8s API is correct
+    app_container = dep.spec.template.spec.containers[0]
+    assert app_container.image == "example.com/testcomponent:1.4.3"
+    assert app_container.image_pull_policy == "IfNotPresent"
+    assert len(app_container.ports) == 2
+    assert app_container.ports[0].container_port == 80
+    assert app_container.ports[1].container_port == 443
+    assert app_container.readiness_probe.http_get.path == "/ready"
+    assert app_container.readiness_probe.http_get.scheme == "HTTP"
+    assert len(app_container.volume_mounts) == 3
+    assert app_container.volume_mounts[0].mount_path == "/path/on/container"
+    assert app_container.volume_mounts[1].mount_path == "/path/to/container/log/directory"
+    assert app_container.volume_mounts[2].mount_path == "/path/to/container/cert/directory"
+
+    # Needs to be correctly labeled so that the Service can find it
+    assert dep.spec.template.metadata.labels["app"] == "testcomponent"