Bring back StatefulSet support

It's based on previous wotk on PetSets, but is adapted for
Kubernetes 1.5.

Change-Id: Ia1a18503514c2bfd6d90e6e265df33ede61e74d2
This commit is contained in:
Yuriy Taraday 2017-01-09 16:24:45 -08:00
parent dcf1cd736d
commit 968a65fbf2
6 changed files with 62 additions and 7 deletions

View File

@ -101,7 +101,7 @@ service
* - kind * - kind
- Kind of k8s object to use for containers deployment. - Kind of k8s object to use for containers deployment.
- false - false
- one of: ["Deployment", "DaemonSet"] - one of: ["Deployment", "DaemonSet", "StatefulSet"]
- Deployment - Deployment
* - containers * - containers
- List of containers under multi-container pod. - List of containers under multi-container pod.

View File

@ -1,3 +1,4 @@
import itertools
import logging import logging
import os import os
import pkg_resources import pkg_resources
@ -158,7 +159,8 @@ def get_deploy_components_info(rendering_context=None):
def get_deployed_components(): def get_deployed_components():
"""Returns set of deployed components.""" """Returns set of deployed components."""
deployed_deployments = kubernetes.list_cluster_deployments() deployed_deployments = kubernetes.list_cluster_deployments()
deployed_components = set( deployed_statefulsets = kubernetes.list_cluster_statefulsets()
kubernetes.get_object_names(deployed_deployments) deployed_components = set(kubernetes.get_object_names(
itertools.chain(deployed_deployments, deployed_statefulsets))
) )
return deployed_components return deployed_components

View File

@ -134,8 +134,15 @@ def parse_role(component, topology, configmaps, jinja_imports):
'Affinity is in conflict with annotations with key: %s' 'Affinity is in conflict with annotations with key: %s'
.format(same_keywords)) .format(same_keywords))
annotations.update(affinity) annotations.update(affinity)
obj = templates.serialize_deployment(service_name, cont_spec, annotations,
replicas, component_name, strategy) if service.get("kind") != "StatefulSet":
obj = templates.serialize_deployment(service_name, cont_spec,
annotations, replicas,
component_name, strategy)
else:
obj = templates.serialize_statefulset(service_name, cont_spec,
annotations, replicas,
component_name)
yield [obj] yield [obj]
yield _process_ports(service) yield _process_ports(service)
@ -203,6 +210,7 @@ def _process_ports(service):
service["name"], ingress_host, source_port)) service["name"], ingress_host, source_port))
service_template = templates.serialize_service( service_template = templates.serialize_service(
service["name"], ports, service["name"], ports,
headless=service.get("kind") == "StatefulSet",
annotations=service.get('annotations', {}).get('service')) annotations=service.get('annotations', {}).get('service'))
yield service_template yield service_template

View File

@ -10,7 +10,13 @@ CONF = config.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
UPDATABLE_OBJECTS = ('ConfigMap', 'Deployment', 'Service', 'Ingress') UPDATABLE_OBJECTS = (
'ConfigMap',
'Deployment',
'Service',
'Ingress',
'StatefulSet',
)
def get_client(kube_apiserver=None, key_file=None, cert_file=None, def get_client(kube_apiserver=None, key_file=None, cert_file=None,
@ -177,6 +183,13 @@ def list_cluster_ingress():
namespace=CONF.kubernetes.namespace) namespace=CONF.kubernetes.namespace)
def list_cluster_statefulsets():
client = get_client()
return pykube.StatefulSet.objects(client).filter(
namespace=CONF.kubernetes.namespace,
selector="ccp=true")
def get_object_names(items): def get_object_names(items):
names = [] names = []
for item in items: for item in items:

View File

@ -352,6 +352,31 @@ def serialize_deployment(name, spec, annotations, replicas, component_name,
return deployment return deployment
def serialize_statefulset(name, spec, annotations, replicas, component_name):
return {
"apiVersion": "apps/v1beta1",
"kind": "StatefulSet",
"metadata": {
"name": name
},
"spec": {
"serviceName": name,
"replicas": replicas,
"template": {
"metadata": {
"annotations": annotations,
"labels": {
"ccp": "true",
"app": name,
"ccp-component": component_name
}
},
"spec": spec
}
}
}
def serialize_affinity(service, topology): def serialize_affinity(service, topology):
policy = { policy = {
"nodeAffinity": { "nodeAffinity": {

View File

@ -179,6 +179,13 @@ SERVICE_SCHEMA = {
"additionalProperties": False, "additionalProperties": False,
"required": ["name", "containers"], "required": ["name", "containers"],
"not": { # strategy needs to be absent for StatefulSet's
"properties": {
"kind": {"enum": ["StatefulSet"]},
},
"required": ["kind", "strategy"],
},
"properties": { "properties": {
"name": NOT_EMPTY_STRING_SCHEMA, "name": NOT_EMPTY_STRING_SCHEMA,
"ports": { "ports": {
@ -207,7 +214,7 @@ SERVICE_SCHEMA = {
} }
}, },
"kind": { "kind": {
"enum": ["Deployment", "DaemonSet"] "enum": ["Deployment", "DaemonSet", "StatefulSet"]
}, },
"hostNetwork": { "hostNetwork": {
"type": "boolean" "type": "boolean"