Add TLS support for client-only apps 19/90719/2
authorJack Lucas <jflucas@research.att.com>
Tue, 25 Jun 2019 22:52:55 +0000 (18:52 -0400)
committerJack Lucas <jflucas@research.att.com>
Mon, 1 Jul 2019 15:07:30 +0000 (11:07 -0400)
Also enhance unit tests to do more robust checking of results.

Issue-ID: DCAEGEN2-1550
Change-Id: Icf6e5357d828e19db73bb58b98fd60e9f111d0dc
Signed-off-by: Jack Lucas <jflucas@research.att.com>
k8s/configure/configure.py
k8s/k8s-node-type.yaml
k8s/k8sclient/k8sclient.py
k8s/k8splugin/tasks.py
k8s/pom.xml
k8s/setup.py
k8s/tests/common.py [new file with mode: 0644]
k8s/tests/conftest.py
k8s/tests/test_k8sclient.py
k8s/tests/test_k8sclient_deploy.py [new file with mode: 0644]

index e15939a..9f7929e 100644 (file)
@@ -35,6 +35,10 @@ FB_IMAGE = "docker.elastic.co/beats/filebeat:5.5.0"
 
 TLS_CERT_PATH = "/opt/tls/shared"
 TLS_IMAGE = "nexus3.onap.org:10001/onap/org.onap.dcaegen2.deployments.tls-init-container:1.0.0"
+TLS_CA_CERT_PATH = "/opt/dcae/cacert/cacert.pem"
+TLS_CA_CONFIGMAP = "dcae-cacert-configmap"
+
+CBS_BASE_URL = "https://config-binding-service:10443/service_component_all"
 
 def _set_defaults():
     """ Set default configuration parameters """
@@ -51,10 +55,16 @@ def _set_defaults():
             "config_map" : FB_CONFIG_MAP,               # ConfigMap holding the filebeat configuration
             "image": FB_IMAGE                           # Docker image to use for filebeat
         },
-        "tls": {                                        # Configuration for setting up TLS init container
+        "tls": {                                        # Configuration for setting up TLS
             "cert_path" : TLS_CERT_PATH,                # mount point for certificate volume in TLS init container
-            "image": TLS_IMAGE                          # Docker image to use for TLS init container
+            "image": TLS_IMAGE,                         # Docker image to use for TLS init container
+            "component_ca_cert_path": TLS_CA_CERT_PATH, # Mount point for CA cert for components that are clients only
+            "ca_cert_configmap": TLS_CA_CONFIGMAP       # ConfigMap holding CA cert for components that are clients only
+        },
+        "cbs": {
+            "base_url" : CBS_BASE_URL                   # URL prefix for accessing config binding service
         }
+
     }
 
 def configure(config_path=_CONFIG_PATH, key = _CONSUL_KEY):
index 273da7a..c32d834 100644 (file)
 
 tosca_definitions_version: cloudify_dsl_1_3
 
-imports:
-    - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
-
 plugins:
   k8s:
     executor: 'central_deployment_agent'
     package_name: k8splugin
-    package_version: 1.4.13
+    package_version: 1.5.0
 
 data_types:
 
index 681ea6b..273b9f3 100644 (file)
@@ -93,7 +93,7 @@ def _parse_interval(t):
         raise ValueError("Bad interval specification: {0}".format(t))
     return time
 
-def _create_probe(hc, port, use_tls=False):
+def _create_probe(hc, port):
     ''' Create a Kubernetes probe based on info in the health check dictionary hc '''
     probe_type = hc['type']
     probe = None
@@ -133,7 +133,7 @@ def _create_resources(resources=None):
     else:
         return None
 
-def _create_container_object(name, image, always_pull, use_tls=False, env={}, container_ports=[], volume_mounts = [], resources = None, readiness = None, liveness = None):
+def _create_container_object(name, image, always_pull, env={}, container_ports=[], volume_mounts = [], resources = None, readiness = None, liveness = None):
     # Set up environment variables
     # Copy any passed in environment variables
     env_vars = [client.V1EnvVar(name=k, value=env[k]) for k in env.keys()]
@@ -150,12 +150,12 @@ def _create_container_object(name, image, always_pull, use_tls=False, env={}, co
         hc_port = None
         if len(container_ports) > 0:
             (hc_port, proto) = container_ports[0]
-        probe = _create_probe(readiness, hc_port, use_tls)
+        probe = _create_probe(readiness, hc_port)
     if liveness:
         hc_port = None
         if len(container_ports) > 0:
             (hc_port, proto) = container_ports[0]
-        live_probe = _create_probe(liveness, hc_port, use_tls)
+        live_probe = _create_probe(liveness, hc_port)
 
     if resources:
         resources_obj = _create_resources(resources)
@@ -376,9 +376,11 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
             "config_subpath" :  subpath for config data in filebeat container
             "config_map" : ConfigMap holding the filebeat configuration
             "image": Docker image to use for filebeat
-        - tls: a dictionary of TLS init container parameters:
+        - tls: a dictionary of TLS-related information:
             "cert_path": mount point for certificate volume in init container
             "image": Docker image to use for TLS init container
+            "component_ca_cert_path" : mount point for CA cert for client-only containers
+            "ca_cert_configmap": the name of the ConfigMap where the CA cert is stored
     kwargs may have:
         - volumes:  array of volume objects, where a volume object is:
             {"host":{"path": "/path/on/host"}, "container":{"bind":"/path/on/container","mode":"rw_or_ro"}
@@ -453,7 +455,7 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
             sidecar_volume_mounts.append(client.V1VolumeMount(name="filebeat-data", mount_path=fb["data_path"]))
 
             # Create the container for the sidecar
-            containers.append(_create_container_object("filebeat", fb["image"], False, False, {}, [], sidecar_volume_mounts))
+            containers.append(_create_container_object("filebeat", fb["image"], False, {}, [], sidecar_volume_mounts))
 
             # Create the volume for the sidecar configuration data and the volume mount for it
             # The configuration data is in a k8s ConfigMap that should be created when DCAE is installed.
@@ -462,25 +464,44 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
             sidecar_volume_mounts.append(
                 client.V1VolumeMount(name="filebeat-conf", mount_path=fb["config_path"], sub_path=fb["config_subpath"]))
 
-        # Set up the TLS init container, if needed
-        tls_info = kwargs.get("tls_info")
-        use_tls = False
-        if tls_info and "use_tls" in tls_info and tls_info["use_tls"]:
-            if "cert_directory" in tls_info and len(tls_info["cert_directory"]) > 0:
-                use_tls = True
-                tls_config = k8sconfig["tls"]
+        # Set up TLS information
+        #   Two different ways of doing this, depending on whether the container will act as a TLS server or as a client only
+        #   If a server, then tls_info will be passed, and tls_info["use_tls"] will be set to true.  We create an InitContainer
+        #   that sets up the CA cert, the server cert, and the keys.
+        #   If a client only, only the CA cert is needed.  We mount the CA cert from a ConfigMap that has been created as part
+        #   of the installation process. If there is cert_directory information in tls_info, we use that directory in the mount path.
+        #   Otherwise, we use the configured default path in tls_config.
 
+        tls_info = kwargs.get("tls_info")
+        tls_config = k8sconfig["tls"]
+        tls_server = False
+        cert_directory = None
+
+        if tls_info and "cert_directory" in tls_info and len(tls_info["cert_directory"]) > 0:
+            cert_directory = tls_info["cert_directory"]
+            if tls_info and tls_info.get("use_tls", False):
+                tls_server = True
+                # Use an InitContainer to set up the certificate information
                 # Create the certificate volume and volume mounts
                 volumes.append(client.V1Volume(name="tls-info", empty_dir=client.V1EmptyDirVolumeSource()))
-                volume_mounts.append(client.V1VolumeMount(name="tls-info", mount_path=tls_info["cert_directory"]))
+                volume_mounts.append(client.V1VolumeMount(name="tls-info", mount_path=cert_directory))
                 init_volume_mounts = [client.V1VolumeMount(name="tls-info", mount_path=tls_config["cert_path"])]
 
                 # Create the init container
-                init_containers.append(_create_container_object("init-tls", tls_config["image"], False, False, {}, [], init_volume_mounts))
+                init_containers.append(_create_container_object("init-tls", tls_config["image"], False, {}, [], init_volume_mounts))
+
+        if not tls_server:
+            # Use a config map
+            # Create the CA cert volume
+            volumes.append(client.V1Volume(name="tls-cacert", config_map=client.V1ConfigMapVolumeSource(name=tls_config["ca_cert_configmap"])))
+
+            # Create the volume mount
+            mount_path= cert_directory if cert_directory else os.path.dirname(tls_config["component_ca_cert_path"])
+            volume_mounts.append(client.V1VolumeMount(name="tls-cacert", mount_path=mount_path))
 
         # Create the container for the component
         # Make it the first container in the pod
-        containers.insert(0, _create_container_object(component_name, image, always_pull, use_tls, kwargs.get("env", {}), container_ports, volume_mounts, resources, kwargs["readiness"], kwargs.get("liveness")))
+        containers.insert(0, _create_container_object(component_name, image, always_pull, kwargs.get("env", {}), container_ports, volume_mounts, resources, kwargs["readiness"], kwargs.get("liveness")))
 
         # Build the k8s Deployment object
         labels = kwargs.get("labels", {})
index ab72b57..ecd3ffa 100644 (file)
@@ -44,6 +44,8 @@ CONSUL_INTERNAL_NAME = plugin_conf.get("consul_dns_name")
 DCAE_NAMESPACE = plugin_conf.get("namespace")
 DEFAULT_MAX_WAIT = plugin_conf.get("max_wait", 1800)
 DEFAULT_K8S_LOCATION = plugin_conf.get("default_k8s_location")
+COMPONENT_CA_CERT_PATH = plugin_conf.get("tls").get("component_ca_cert_path")
+CBS_BASE_URL = plugin_conf.get("cbs").get("base_url")
 
 # Used to construct delivery urls for data router subscribers. Data router in FTL
 # requires https but this author believes that ONAP is to be defaulted to http.
@@ -279,13 +281,19 @@ def _create_and_start_container(container_name, image, **kwargs):
         - msb_list: array of msb objects, where an msb object is as described in msb/msb.py.
         - log_info: an object with info for setting up ELK logging, with the form:
             {"log_directory": "/path/to/container/log/directory", "alternate_fb_path" : "/alternate/sidecar/log/path"}"
+        - tls_info: an object with information for setting up the component to act as a TLS server, with the form:
+            {"use_tls" : true_or_false, "cert_directory": "/path/to/directory_where_certs_should_be_placed" }
         - replicas: number of replicas to be launched initially
         - readiness: object with information needed to create a readiness check
         - liveness: object with information needed to create a liveness check
         - k8s_location: name of the Kubernetes location (cluster) where the component is to be deployed
     '''
+    tls_info = kwargs.get("tls_info")
     env = { "CONSUL_HOST": CONSUL_INTERNAL_NAME,
-            "CONFIG_BINDING_SERVICE": "config-binding-service" }
+            "CONFIG_BINDING_SERVICE": "config-binding-service",
+            "DCAE_CA_CERTPATH" : "{0}/cacert.pem".format(tls_info["cert_directory"]) if (tls_info and tls_info["cert_directory"]) else COMPONENT_CA_CERT_PATH,
+            "CBS_CONFIG_URL" : "{0}/{1}".format(CBS_BASE_URL, container_name)
+          }
     env.update(kwargs.get("envs", {}))
     ctx.logger.info("Starting k8s deployment for {}, image: {}, env: {}, kwargs: {}".format(container_name, image, env, kwargs))
     ctx.logger.info("Passing k8sconfig: {}".format(plugin_conf))
index b99816a..d96ebe1 100644 (file)
@@ -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.13-SNAPSHOT</version>
+  <version>1.5.0-SNAPSHOT</version>
   <url>http://maven.apache.org</url>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
index 6a9dcac..5d27438 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.13",
+    version="1.5.0",
     author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
     packages=['k8splugin','k8sclient','msb','configure'],
     zip_safe=False,
diff --git a/k8s/tests/common.py b/k8s/tests/common.py
new file mode 100644 (file)
index 0000000..67f70a6
--- /dev/null
@@ -0,0 +1,135 @@
+# ============LICENSE_START=======================================================
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 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.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+
+# Common functions for unit testing
+def _set_k8s_configuration():
+    ''' Set up the basic k8s configuration '''
+    return  {
+        "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",
+            "component_ca_cert_path": "/opt/dcae/cacert/cacert.pem",
+            "ca_cert_configmap": "dcae-cacert-configmap"
+        },
+        "cbs": {
+            "base_url": "https://config-binding-service:10443/service_component_all/test-component"
+        }
+    }
+
+def _set_resources():
+    ''' Set resources '''
+    return {
+        "limits": {
+            "cpu" : 0.5,
+            "memory" : "2Gi"
+        },
+        "requests": {
+            "cpu" : 0.5,
+            "memory" : "2Gi"
+        }
+    }
+
+def _set_common_kwargs():
+    ''' Set kwargs common to all test cases '''
+    return {
+        "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"},
+        "readiness": {"type": "http", "endpoint" : "/ready"}
+    }
+
+def _get_item_by_name(list, name):
+    ''' Search a list of k8s API objects with the specified name '''
+    for item in list:
+        if item.name == name:
+            return item
+    return None
+
+def check_env_var(env_list, name, value):
+    e = _get_item_by_name(env_list, name)
+    assert e and e.value == value
+
+def verify_common(dep, deployment_description):
+    ''' Check results common to all test cases '''
+    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"
+
+    # Check environment variables
+    env = app_container.env
+    check_env_var(env, "NAME0", "value0")
+    check_env_var(env, "NAME1", "value1")
+
+    # Should have a log container with volume mounts
+    log_container = dep.spec.template.spec.containers[1]
+    assert log_container.image == "filebeat-repo/filebeat:latest"
+    assert log_container.volume_mounts[0].mount_path == "/var/log/onap/testcomponent"
+    assert log_container.volume_mounts[0].name == "component-log"
+    assert log_container.volume_mounts[1].mount_path == "/usr/share/filebeat/data"
+    assert log_container.volume_mounts[1].name == "filebeat-data"
+    assert log_container.volume_mounts[2].mount_path == "/usr/share/filebeat/filebeat.yml"
+    assert log_container.volume_mounts[2].name == "filebeat-conf"
+
+    # Needs to be correctly labeled so that the Service can find it
+    assert dep.spec.template.metadata.labels["app"] == "testcomponent"
+
+
+def do_deploy(tls_info=None):
+    ''' Common deployment operations '''
+    import k8sclient.k8sclient
+
+    k8s_test_config = _set_k8s_configuration()
+
+    resources = _set_resources()
+
+    kwargs = _set_common_kwargs()
+    if tls_info:
+        kwargs["tls_info"] = tls_info
+
+    dep, deployment_description = k8sclient.k8sclient.deploy("k8stest","testcomponent","example.com/testcomponent:1.4.3",1,False, k8s_test_config, resources, **kwargs)
+
+    # Make sure all of the basic k8s parameters are correct
+    verify_common(dep, deployment_description)
+
+    return dep, deployment_description
\ No newline at end of file
index 572a510..4716b5a 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.dcae
 # ================================================================================
-# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# Copyright (c) 2018-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.
@@ -22,13 +22,48 @@ import pytest
 
 @pytest.fixture()
 def mockconfig(monkeypatch):
+    from configure import configure
     """ Override the regular configure() routine that reads a file and calls Consul"""
     def altconfig():
-        return {
-            "consul_host": "consul",
-            "namespace":"dcae",
-            "consul_dns_name" : "consul",
-            "image_pull_secrets" : []
-        }
-    from configure import configure
-    monkeypatch.setattr(configure, 'configure', altconfig)
\ No newline at end of file
+      config = configure._set_defaults()
+      config["consul_host"] = config["consul_dns_name"]
+      return config
+    monkeypatch.setattr(configure, 'configure', altconfig)
+
+@pytest.fixture()
+def mockk8sapi(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(loc):
+        pass
+
+    monkeypatch.setattr(k8sclient.k8sclient,"_configure_api", pseudo_configure)
+    monkeypatch.setattr(client, "CoreV1Api", patched_core)
+    monkeypatch.setattr(client,"ExtensionsV1beta1Api", patched_ext)
index 70ebf05..079748c 100644 (file)
@@ -16,6 +16,8 @@
 # limitations under the License.
 # ============LICENSE_END=========================================================
 
+# Basic sanity tests for  k8sclient functions
+
 import pytest
 
 def test_parse_interval():
@@ -174,101 +176,3 @@ def test_create_probe():
     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(loc):
-        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"
diff --git a/k8s/tests/test_k8sclient_deploy.py b/k8s/tests/test_k8sclient_deploy.py
new file mode 100644 (file)
index 0000000..4e8a11d
--- /dev/null
@@ -0,0 +1,48 @@
+# ============LICENSE_START=======================================================
+# org.onap.dcae
+# ================================================================================
+# Copyright (c) 2018-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.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+
+# Test k8sclient deployment functions
+# Verify that for a given configuration and set of inputs, k8sclient generates the proper
+# Kubernetes entities
+
+import pytest
+from common import do_deploy
+
+def test_deploy_full_tls(mockk8sapi):
+    ''' Deploy component with a full TLS configuration, to act as a server '''
+
+    dep, deployment_description = do_deploy({"use_tls": True, "cert_directory": "/path/to/container/cert/directory" })
+
+    app_container = dep.spec.template.spec.containers[0]
+    assert app_container.volume_mounts[2].mount_path == "/path/to/container/cert/directory"
+
+def test_deploy_tls_off(mockk8sapi):
+    ''' TLS client only, but with cert directory configured '''
+
+    dep, deployment_description = do_deploy({"use_tls": False, "cert_directory": "/path/to/container/cert/directory" })
+
+    app_container = dep.spec.template.spec.containers[0]
+    assert app_container.volume_mounts[2].mount_path == "/path/to/container/cert/directory"
+
+def test_deploy_no_tls_info(mockk8sapi):
+    ''' TLS client only, but with cert directory configured '''
+
+    dep, deployment_description = do_deploy()
+
+    app_container = dep.spec.template.spec.containers[0]
+    assert app_container.volume_mounts[2].mount_path == "/opt/dcae/cacert"