add liveness probe, fix readiness prob exec 91/81891/5
authorJason Luo <cl4531@att.com>
Sun, 10 Mar 2019 00:36:25 +0000 (00:36 +0000)
committerJason Luo <cl4531@att.com>
Tue, 12 Mar 2019 14:46:19 +0000 (14:46 +0000)
liveness and readiness probes may run script with
arguments, ports and volumes are optional instead
of mandatory, test_tasks.py accept ports[] and
volumes[]
fix the issue of labels which are logner than 63

Issue-ID: DCAEGEN2-1126
Change-Id: Id2f893adc300bf508c0512a51b3665872d36f674
Signed-off-by: Jason Luo <cl4531@att.com>
k8s/ChangeLog.md
k8s/k8s-node-type.yaml
k8s/k8sclient/k8sclient.py
k8s/k8splugin/tasks.py
k8s/setup.py
k8s/tests/test_tasks.py

index 3402581..a59a016 100644 (file)
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
+## [1.4.9]
+* Support for liveness probes (https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)
+* fix the readiness probe to run script such as "/opt/app/snmptrap/bin/snmptrapd.sh status"
+* change "ports" and the "mode" of volume to be optional instead of mandatory
+
 ## [1.4.8]
 * If an installation step times out because a component does not become ready within the maximum wait time,
 delete the Kubernetes artifacts associated with the component.  Previously, an installation step might time
index 13798f4..c803b81 100644 (file)
@@ -25,7 +25,7 @@ plugins:
   k8s:
     executor: 'central_deployment_agent'
     package_name: k8splugin
-    package_version: 1.4.8
+    package_version: 1.4.9
 
 data_types:
 
index 31631ad..d3417a7 100644 (file)
@@ -116,7 +116,7 @@ def _create_probe(hc, port, use_tls=False):
           period_seconds = period,
           timeout_seconds = timeout,
           _exec = client.V1ExecAction(
-              command = [hc['script']]
+              command = hc['script'].split( )
           )
         )
     return probe
@@ -131,7 +131,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):
+def _create_container_object(name, image, always_pull, use_tls=False, 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()]
@@ -139,15 +139,21 @@ def _create_container_object(name, image, always_pull, use_tls=False, env={}, co
     pod_ip = client.V1EnvVarSource(field_ref = client.V1ObjectFieldSelector(field_path="status.podIP"))
     env_vars.append(client.V1EnvVar(name="POD_IP",value_from=pod_ip))
 
-    # If a health check is specified, create a readiness probe
+    # If a health check is specified, create a readiness/liveness probe
     # (For an HTTP-based check, we assume it's at the first container port)
     probe = None
+    live_probe = None
 
     if readiness:
         hc_port = None
         if len(container_ports) > 0:
             (hc_port, proto) = container_ports[0]
         probe = _create_probe(readiness, hc_port, use_tls)
+    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)
 
     if resources:
         resources_obj = _create_resources(resources)
@@ -162,7 +168,8 @@ def _create_container_object(name, image, always_pull, use_tls=False, env={}, co
         ports=[client.V1ContainerPort(container_port=p, protocol=proto) for (p, proto) in container_ports],
         volume_mounts = volume_mounts,
         resources = resources_obj,
-        readiness_probe = probe
+        readiness_probe = probe,
+        liveness_probe = live_probe
     )
 
 def _create_deployment_object(component_name,
@@ -386,6 +393,12 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
             - timeout:  time (in seconds) to allow a probe to complete
             - endpoint: the path portion of the URL that points to the readiness endpoint for "http" and "https" types
             - path: the full path to the script to be executed in the container for "script" and "docker" types
+        - liveness: dict with health check info; if present, used to create a liveness probe for the main container.  Includes:
+            - type: check is done by making http(s) request to an endpoint ("http", "https") or by exec'ing a script in the container ("script", "docker")
+            - interval: period (in seconds) between probes
+            - timeout:  time (in seconds) to allow a probe to complete
+            - endpoint: the path portion of the URL that points to the liveness endpoint for "http" and "https" types
+            - path: the full path to the script to be executed in the container for "script" and "docker" types
 
     '''
 
@@ -460,7 +473,7 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, r
 
         # 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"]))
+        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")))
 
         # Build the k8s Deployment object
         labels = kwargs.get("labels", {})
index 727be78..399bc9f 100644 (file)
@@ -286,6 +286,7 @@ def _create_and_start_container(container_name, image, **kwargs):
             {"log_directory": "/path/to/container/log/directory", "alternate_fb_path" : "/alternate/sidecar/log/path"}"
         - 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
     '''
     env = { "CONSUL_HOST": CONSUL_INTERNAL_NAME,
             "CONFIG_BINDING_SERVICE": "config-binding-service" }
@@ -308,7 +309,8 @@ def _create_and_start_container(container_name, image, **kwargs):
                      env = env,
                      labels = kwargs.get("labels", {}),
                      log_info=kwargs.get("log_info"),
-                     readiness=kwargs.get("readiness"))
+                     readiness=kwargs.get("readiness"),
+                     liveness=kwargs.get("liveness"))
 
     # Capture the result of deployment for future use
     ctx.instance.runtime_properties[K8S_DEPLOYMENT] = dep
@@ -327,8 +329,8 @@ def _parse_cloudify_context(**kwargs):
     # Set some labels for the Kubernetes pods
     kwargs["labels"] = {
         "cfydeployment" : ctx.deployment.id,
-        "cfynode": ctx.node.name,
-        "cfynodeinstance": ctx.instance.id
+        "cfynode": ctx.node.name[:63],
+        "cfynodeinstance": ctx.instance.id[:63]
     }
 
         # Pick up the centralized logging info
@@ -349,14 +351,16 @@ def _parse_cloudify_context(**kwargs):
 
 def _enhance_docker_params(**kwargs):
     '''
-    Set up Docker environment variables and readiness check info
+    Set up Docker environment variables and readiness/liveness check info
     and inject into kwargs.
     '''
 
-    # Get info for setting up readiness probe, if present
+    # Get info for setting up readiness/liveness probe, if present
     docker_config = kwargs.get("docker_config", {})
     if "healthcheck" in docker_config:
         kwargs["readiness"] = docker_config["healthcheck"]
+    if "livehealthcheck" in docker_config:
+        kwargs["liveness"] = docker_config["livehealthcheck"]
 
     envs = kwargs.get("envs", {})
 
@@ -371,8 +375,7 @@ def _enhance_docker_params(**kwargs):
 
     def combine_params(key, docker_config, kwargs):
         v = docker_config.get(key, []) + kwargs.get(key, [])
-        if v:
-            kwargs[key] = v
+        kwargs[key] = v
         return kwargs
 
     # Add the lists of ports and volumes unintelligently - meaning just add the
@@ -398,7 +401,8 @@ def _create_and_start_component(**kwargs):
         "tls_info": kwargs.get("tls_info", {}),
         "labels": kwargs.get("labels", {}),
         "resource_config": kwargs.get("resource_config",{}),
-        "readiness": kwargs.get("readiness",{})}
+        "readiness": kwargs.get("readiness",{}),
+        "liveness": kwargs.get("liveness",{})}
     returned_args = _create_and_start_container(service_component_name, image, **sub_kwargs)
     kwargs[K8S_DEPLOYMENT] = returned_args[K8S_DEPLOYMENT]
 
@@ -518,6 +522,8 @@ def create_and_start_container_for_platforms(**kwargs):
     kwargs["resource_config"] = resource_config
     if "healthcheck" in docker_config:
         kwargs["readiness"] = docker_config["healthcheck"]
+    if "livehealthcheck" in docker_config:
+        kwargs["liveness"] = docker_config["livehealthcheck"]
     if "dns_name" in ctx.node.properties:
         service_component_name = ctx.node.properties["dns_name"]
     else:
@@ -526,8 +532,8 @@ def create_and_start_container_for_platforms(**kwargs):
     # Set some labels for the Kubernetes pods
     kwargs["labels"] = {
         "cfydeployment" : ctx.deployment.id,
-        "cfynode": ctx.node.name,
-        "cfynodeinstance": ctx.instance.id
+        "cfynode": ctx.node.name[:63],
+        "cfynodeinstance": ctx.instance.id[:63]
     }
 
     host_port = ctx.node.properties["host_port"]
index 3d94c96..a64efc8 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.8",
+    version="1.4.9",
     author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
     packages=['k8splugin','k8sclient','msb','configure'],
     zip_safe=False,
index 948489a..cf78860 100644 (file)
@@ -247,7 +247,7 @@ def test_enhance_docker_params(mockconfig):
     test_kwargs = { "docker_config": {}, "service_id": None }
     actual = tasks._enhance_docker_params(**test_kwargs)
 
-    assert actual == {'envs': {"SERVICE_TAGS": ""}, 'docker_config': {}, "service_id": None }
+    assert actual == {'envs': {"SERVICE_TAGS": ""}, 'docker_config': {}, 'ports': [], 'volumes': [], "service_id": None }
 
     # Good - Test just docker config ports and volumes
 
@@ -289,4 +289,4 @@ def test_notify_container(mockconfig):
     from k8splugin import tasks
 
     test_input = { "docker_config": { "policy": { "trigger_type": "unknown" } } }
-    assert [] == tasks._notify_container(**test_input)
\ No newline at end of file
+    assert [] == tasks._notify_container(**test_input)