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>
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
# ================================================================================
# ================================================================================
-# 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
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: >
# ============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.
-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()]
(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,
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
)
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.
# 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", {})
# ============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.
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.
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"
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
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"),
"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)
"""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):
# 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:
# 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):
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))
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))
# ============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.
setup(
name='k8splugin',
description='Cloudify plugin for containerized components deployed using Kubernetes',
setup(
name='k8splugin',
description='Cloudify plugin for containerized components deployed using Kubernetes',
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,