Add resource_config to specify CPU and menory 37/79137/4
authorJason Luo <cl4531@att.com>
Mon, 25 Feb 2019 22:01:05 +0000 (22:01 +0000)
committerJason Luo <cl4531@att.com>
Wed, 27 Feb 2019 15:01:26 +0000 (15:01 +0000)
Enhance K8s plugin used by DCAE Platform to specify CPU and memory

Issue-ID: DCAEGEN2-1126

Change-Id: I2431b0b7f67f855122ed4494aa21cad0f99dcc37
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

index 70b5869..7c9a72c 100644 (file)
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
 
 and this project adheres to [Semantic Versioning](http://semver.org/).
 
 
+## [1.4.6]
+* Support for specifying CPU and memory resources in a blueprint for a containerized component
+* Changes the default time that the plugin will wait for a container to become ready from 300 seconds to 1800 seconds
+
 ## [1.4.5]
 * DCAEGEN2-1086 update onap-dcae-dcaepolicy-lib version to avoid Consul stores under old service_component_name
 
 ## [1.4.5]
 * DCAEGEN2-1086 update onap-dcae-dcaepolicy-lib version to avoid Consul stores under old service_component_name
 
index a6f1559..f63f822 100644 (file)
@@ -1,5 +1,5 @@
 # ================================================================================
 # ================================================================================
-# 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.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 tosca_definitions_version: cloudify_dsl_1_3
 
 imports:
 tosca_definitions_version: cloudify_dsl_1_3
 
 imports:
-    - http://www.getcloudify.org/spec/cloudify/3.4/types.yaml
+    - http://www.getcloudify.org/spec/cloudify/4.2/types.yaml
 
 plugins:
   k8s:
     executor: 'central_deployment_agent'
     package_name: k8splugin
 
 plugins:
   k8s:
     executor: 'central_deployment_agent'
     package_name: k8splugin
-    package_version: 1.4.5
+    package_version: 1.4.6
 
 data_types:
 
 
 data_types:
 
@@ -119,6 +119,14 @@ node_types:
                   like healthcheck definitions for the Docker component. Health checks are
                   optional.
 
                   like healthcheck definitions for the Docker component. Health checks are
                   optional.
 
+            resource_config:
+                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 
+                  for cpu and memory. (https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/)
+                   
+
             log_info:
               type: dcae.types.LoggingInfo
               description: >
             log_info:
               type: dcae.types.LoggingInfo
               description: >
index 806b41e..84ca84f 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.dcae
 # ================================================================================
 # ============LICENSE_START=======================================================
 # org.onap.dcae
 # ================================================================================
-# Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
+# 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.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -121,7 +121,17 @@ def _create_probe(hc, port, use_tls=False):
         )
     return probe
 
         )
     return probe
 
-def _create_container_object(name, image, always_pull, use_tls=False, env={}, container_ports=[], volume_mounts = [], readiness = None):
+def _create_resources(resources=None):
+    if resources is not None:
+        resources_obj = client.V1ResourceRequirements(
+          limits = resources.get("limits"),
+          requests = resources.get("requests")
+        )   
+        return resources_obj
+    else:
+        return None
+
+def _create_container_object(name, image, always_pull, use_tls=False, env={}, container_ports=[], volume_mounts = [], resources = None, readiness = 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()]
     # 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,6 +149,10 @@ def _create_container_object(name, image, always_pull, use_tls=False, env={}, co
             (hc_port, proto) = container_ports[0]
         probe = _create_probe(readiness, hc_port, use_tls)
 
             (hc_port, proto) = container_ports[0]
         probe = _create_probe(readiness, hc_port, use_tls)
 
+    if resources:
+        resources_obj = _create_resources(resources)
+    else:
+        resources_obj = None
     # Define container for pod
     return client.V1Container(
         name=name,
     # Define container for pod
     return client.V1Container(
         name=name,
@@ -147,6 +161,7 @@ def _create_container_object(name, image, always_pull, use_tls=False, env={}, co
         env=env_vars,
         ports=[client.V1ContainerPort(container_port=p, protocol=proto) for (p, proto) in container_ports],
         volume_mounts = volume_mounts,
         env=env_vars,
         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
     )
 
@@ -326,7 +341,7 @@ def _execute_command_in_pod(namespace, pod_name, command):
 
     return {"pod" : pod_name, "output" : output}
 
 
     return {"pod" : pod_name, "output" : output}
 
-def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, **kwargs):
+def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, resources, **kwargs):
     '''
     This will create a k8s Deployment and, if needed, one or two k8s Services.
     (We are being opinionated in our use of k8s... this code decides what k8s abstractions and features to use.
     '''
     This will create a k8s Deployment and, if needed, one or two k8s Services.
     (We are being opinionated in our use of k8s... this code decides what k8s abstractions and features to use.
@@ -445,7 +460,7 @@ def deploy(namespace, component_name, image, replicas, always_pull, k8sconfig, *
 
         # Create the container for the component
         # Make it the first container in the pod
 
         # 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, 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"]))
 
         # Build the k8s Deployment object
         labels = kwargs.get("labels", {})
 
         # Build the k8s Deployment object
         labels = kwargs.get("labels", {})
index ba71bd9..7f91513 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.dcae
 # ================================================================================
 # ============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.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -42,6 +42,7 @@ plugin_conf = configure.configure()
 CONSUL_HOST = plugin_conf.get("consul_host")
 CONSUL_INTERNAL_NAME = plugin_conf.get("consul_dns_name")
 DCAE_NAMESPACE = plugin_conf.get("namespace")
 CONSUL_HOST = plugin_conf.get("consul_host")
 CONSUL_INTERNAL_NAME = plugin_conf.get("consul_dns_name")
 DCAE_NAMESPACE = plugin_conf.get("namespace")
+DEFAULT_MAX_WAIT = plugin_conf.get("max_wait", 1800)
 
 # 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.
 
 # 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.
@@ -52,6 +53,7 @@ SERVICE_COMPONENT_NAME = "service_component_name"
 CONTAINER_ID = "container_id"
 APPLICATION_CONFIG = "application_config"
 K8S_DEPLOYMENT = "k8s_deployment"
 CONTAINER_ID = "container_id"
 APPLICATION_CONFIG = "application_config"
 K8S_DEPLOYMENT = "k8s_deployment"
+RESOURCE_KW = "resource_config"
 
 # Utility methods
 
 
 # Utility methods
 
@@ -97,6 +99,12 @@ def _done_for_create(**kwargs):
     ctx.logger.info("Done setting up: {0}".format(name))
     return kwargs
 
     ctx.logger.info("Done setting up: {0}".format(name))
     return kwargs
 
+def _get_resources(**kwargs):
+    if kwargs is not None:
+        ctx.logger.debug("{0}: {1}".format(RESOURCE_KW, kwargs.get(RESOURCE_KW)))
+        return kwargs.get(RESOURCE_KW)
+    ctx.logger.info("set resources to None")
+    return None
 
 @merge_inputs_for_create
 @monkeypatch_loggers
 
 @merge_inputs_for_create
 @monkeypatch_loggers
@@ -287,12 +295,14 @@ def _create_and_start_container(container_name, image, **kwargs):
     ctx.logger.info("Starting k8s deployment for {}, image: {}, env: {}, kwargs: {}".format(container_name, image, env, kwargs))
     ctx.logger.info("Passing k8sconfig: {}".format(plugin_conf))
     replicas = kwargs.get("replicas", 1)
     ctx.logger.info("Starting k8s deployment for {}, image: {}, env: {}, kwargs: {}".format(container_name, image, env, kwargs))
     ctx.logger.info("Passing k8sconfig: {}".format(plugin_conf))
     replicas = kwargs.get("replicas", 1)
+    resource_config = _get_resources(**kwargs)
     _,dep = k8sclient.deploy(DCAE_NAMESPACE,
                      container_name,
                      image,
                      replicas = replicas,
                      always_pull=kwargs.get("always_pull_image", False),
                      k8sconfig=plugin_conf,
     _,dep = k8sclient.deploy(DCAE_NAMESPACE,
                      container_name,
                      image,
                      replicas = replicas,
                      always_pull=kwargs.get("always_pull_image", False),
                      k8sconfig=plugin_conf,
+                     resources = resource_config,
                      volumes=kwargs.get("volumes",[]),
                      ports=kwargs.get("ports",[]),
                      msb_list=kwargs.get("msb_list"),
                      volumes=kwargs.get("volumes",[]),
                      ports=kwargs.get("ports",[]),
                      msb_list=kwargs.get("msb_list"),
@@ -387,6 +397,7 @@ def _create_and_start_component(**kwargs):
         "log_info": kwargs.get("log_info", {}),
         "tls_info": kwargs.get("tls_info", {}),
         "labels": kwargs.get("labels", {}),
         "log_info": kwargs.get("log_info", {}),
         "tls_info": kwargs.get("tls_info", {}),
         "labels": kwargs.get("labels", {}),
+        "resource_config": kwargs.get("resource_config",{}),
         "readiness": kwargs.get("readiness",{})}
     _create_and_start_container(service_component_name, image, **sub_kwargs)
 
         "readiness": kwargs.get("readiness",{})}
     _create_and_start_container(service_component_name, image, **sub_kwargs)
 
@@ -396,7 +407,7 @@ def _verify_component(**kwargs):
     """Verify deployment is ready"""
     service_component_name = kwargs[SERVICE_COMPONENT_NAME]
 
     """Verify deployment is ready"""
     service_component_name = kwargs[SERVICE_COMPONENT_NAME]
 
-    max_wait = kwargs.get("max_wait", 300)
+    max_wait = kwargs.get("max_wait", DEFAULT_MAX_WAIT)
     ctx.logger.info("Waiting up to {0} secs for {1} to become ready".format(max_wait, service_component_name))
 
     if _verify_k8s_deployment(service_component_name, max_wait):
     ctx.logger.info("Waiting up to {0} secs for {1} to become ready".format(max_wait, service_component_name))
 
     if _verify_k8s_deployment(service_component_name, max_wait):
@@ -492,6 +503,8 @@ def create_and_start_container_for_platforms(**kwargs):
     # Capture node properties
     image = ctx.node.properties["image"]
     docker_config = ctx.node.properties.get("docker_config", {})
     # Capture node properties
     image = ctx.node.properties["image"]
     docker_config = ctx.node.properties.get("docker_config", {})
+    resource_config = ctx.node.properties.get("resource_config", {})
+    kwargs["resource_config"] = resource_config
     if "healthcheck" in docker_config:
         kwargs["readiness"] = docker_config["healthcheck"]
     if "dns_name" in ctx.node.properties:
     if "healthcheck" in docker_config:
         kwargs["readiness"] = docker_config["healthcheck"]
     if "dns_name" in ctx.node.properties:
@@ -543,7 +556,7 @@ def create_and_start_container_for_platforms(**kwargs):
 
     # Verify that the k8s deployment is ready
 
 
     # Verify that the k8s deployment is ready
 
-    max_wait = kwargs.get("max_wait", 300)
+    max_wait = kwargs.get("max_wait", DEFAULT_MAX_WAIT)
     ctx.logger.info("Waiting up to {0} secs for {1} to become ready".format(max_wait, service_component_name))
 
     if _verify_k8s_deployment(service_component_name, max_wait):
     ctx.logger.info("Waiting up to {0} secs for {1} to become ready".format(max_wait, service_component_name))
 
     if _verify_k8s_deployment(service_component_name, max_wait):
@@ -595,7 +608,7 @@ def scale(replicas, **kwargs):
         ctx.instance.runtime_properties["replicas"] = replicas
 
         # Verify that the scaling took place as expected
         ctx.instance.runtime_properties["replicas"] = replicas
 
         # Verify that the scaling took place as expected
-        max_wait = kwargs.get("max_wait", 300)
+        max_wait = kwargs.get("max_wait", DEFAULT_MAX_WAIT)
         ctx.logger.info("Waiting up to {0} secs for {1} to scale and become ready".format(max_wait, service_component_name))
         if _verify_k8s_deployment(service_component_name, max_wait):
             ctx.logger.info("Scaling complete: {0} from {1} to {2} replica(s)".format(service_component_name, current_replicas, replicas))
         ctx.logger.info("Waiting up to {0} secs for {1} to scale and become ready".format(max_wait, service_component_name))
         if _verify_k8s_deployment(service_component_name, max_wait):
             ctx.logger.info("Scaling complete: {0} from {1} to {2} replica(s)".format(service_component_name, current_replicas, replicas))
@@ -618,7 +631,7 @@ def update_image(image, **kwargs):
         ctx.instance.runtime_properties["image"] = image
 
         # Verify that the update took place as expected
         ctx.instance.runtime_properties["image"] = image
 
         # Verify that the update took place as expected
-        max_wait = kwargs.get("max_wait", 300)
+        max_wait = kwargs.get("max_wait", DEFAULT_MAX_WAIT)
         ctx.logger.info("Waiting up to {0} secs for {1} to be updated and become ready".format(max_wait, service_component_name))
         if _verify_k8s_deployment(service_component_name, max_wait):
             ctx.logger.info("Update complete: {0} from {1} to {2}".format(service_component_name, current_image, image))
         ctx.logger.info("Waiting up to {0} secs for {1} to be updated and become ready".format(max_wait, service_component_name))
         if _verify_k8s_deployment(service_component_name, max_wait):
             ctx.logger.info("Update complete: {0} from {1} to {2}".format(service_component_name, current_image, image))
index 9b7f2bb..36fbe05 100644 (file)
@@ -1,7 +1,7 @@
 # ============LICENSE_START=======================================================
 # org.onap.dcae
 # ================================================================================
 # ============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.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ from setuptools import setup
 setup(
     name='k8splugin',
     description='Cloudify plugin for containerized components deployed using Kubernetes',
 setup(
     name='k8splugin',
     description='Cloudify plugin for containerized components deployed using Kubernetes',
-    version="1.4.5",
+    version="1.4.6",
     author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
     packages=['k8splugin','k8sclient','msb','configure'],
     zip_safe=False,
     author='J. F. Lucas, Michael Hwang, Tommy Carpenter',
     packages=['k8splugin','k8sclient','msb','configure'],
     zip_safe=False,