Merge "Initial AppController integration"

This commit is contained in:
Jenkins 2017-03-06 15:16:10 +00:00 committed by Gerrit Code Review
commit 92b827ba0b
4 changed files with 100 additions and 7 deletions

View File

@ -10,6 +10,9 @@ DEFAULTS = {
'password': None,
'cluster_domain': 'cluster.local',
'image_pull_policy': None,
'appcontroller': {
"enabled": False
}
},
}
@ -33,6 +36,13 @@ SCHEMA = {
{'type': 'null'},
{'enum': ['Always', 'IfNotPresent', 'Never']},
]},
'appcontroller': {
'type': 'object',
'additionalProperties': False,
'properties': {
"enabled": {'type': 'boolean'},
},
},
},
},
}

View File

@ -89,7 +89,7 @@ def _process_secrets(secrets):
type, data)
def parse_role(component, topology, configmaps):
def parse_role(component, topology, configmaps, components_map):
service_dir = component["service_dir"]
role = component["service_content"]
component_name = component["component_name"]
@ -115,6 +115,8 @@ def parse_role(component, topology, configmaps):
yield _process_secrets(role.get("secrets"))
workflows = _parse_workflows(service)
if CONF.kubernetes.appcontroller['enabled']:
yield create_dependencies(workflows, components_map)
serialize_workflows(workflows)
workflow_cm = _create_workflow(workflows, service_name)
configmaps = configmaps + (files_cm, meta_cm, workflow_cm)
@ -643,6 +645,27 @@ def _create_registry_secret():
kubernetes.process_object(secret)
def _format_dependency(dep, components_map):
service_name, _, dep_name = dep.partition('/')
# FIXME in general this is not correct...
if dep_name in components_map:
kind = components_map[dep_name]['service_content']['service'].get(
'kind', "deployment")
return "%s/%s" % (kind.lower(), service_name)
return "job/%s-%s" % (service_name, dep_name)
def create_dependencies(workflows, components_map):
for name, wf in six.iteritems(workflows):
child = _format_dependency(wf['workflow']['name'], components_map)
for dep in wf['workflow']['dependencies']:
parent = _format_dependency(dep, components_map)
dep_name = "-".join((child.partition("/")[-1],
parent.partition("/")[-1]))[:63].rstrip("-")
template = templates.serialize_dependency(dep_name, parent, child)
yield template
def deploy_components(components_map, components):
topology = _make_topology(CONF.nodes, CONF.roles, CONF.replicas)
@ -679,7 +702,7 @@ def deploy_components(components_map, components):
for service_name in components:
service = components_map[service_name]
service["service_content"]['service']['exports_ctx'] = exports_ctx
objects_gen = parse_role(service, topology, configmaps)
objects_gen = parse_role(service, topology, configmaps, components_map)
objects = list(itertools.chain.from_iterable(objects_gen))
component_name = service['component_name']
do_upgrade = component_name in upgrading_components

View File

@ -2,6 +2,7 @@ import logging
import os
import pykube.exceptions
import pykube.objects
import yaml
from fuel_ccp import config
@ -95,8 +96,8 @@ def get_pykube_object(object_dict, namespace=None, client=None):
namespace = CONF.kubernetes.namespace
if client is None:
client = get_client()
obj_class = getattr(pykube, object_dict["kind"], None)
obj_class = getattr(pykube, object_dict["kind"], None) or globals().get(
object_dict["kind"], None)
if obj_class is None:
raise RuntimeError('"%s" object is not supported, skipping.'
% object_dict['kind'])
@ -128,7 +129,6 @@ def process_object(object_dict, namespace=None, client=None):
if CONF.action.dry_run:
LOG.info(yaml.dump(object_dict, default_flow_style=False))
return
obj = get_pykube_object(object_dict, namespace=namespace, client=client)
if obj.exists():
@ -227,3 +227,27 @@ def get_configmap(name):
return pykube.ConfigMap.objects(client).filter(
namespace=CONF.kubernetes.namespace,
selector="ccp=true").get_by_name(name)
class Dependency(pykube.objects.APIObject):
version = "appcontroller.k8s/v1alpha1"
endpoint = "dependencies"
kind = "Dependency"
def __init__(self, api, obj):
self.api = api
self.namespace = obj['metadata']['namespace']
self.set_obj(obj)
class Definition(pykube.objects.APIObject):
version = "appcontroller.k8s/v1alpha1"
endpoint = "definitions"
kind = "Definition"
def __init__(self, api, obj):
self.api = api
self.namespace = obj['metadata']['namespace']
self.set_obj(obj)

View File

@ -30,6 +30,18 @@ def _get_readiness_cmd(role_name):
return [PYTHON_PATH, ENTRYPOINT_PATH, "status", role_name]
def _wrap_with_definition(name, obj):
kind = obj['kind'].lower()
return {
"apiVersion": "appcontroller.k8s/v1alpha1",
"kind": "Definition",
"metadata": {
"name": "%s-%s" % (kind, name)
},
kind: obj
}
def serialize_namespace(name):
return {
"apiVersion": "v1",
@ -389,7 +401,7 @@ def serialize_volumes(service, for_job=None):
def serialize_job(name, spec, component_name, app_name):
return {
job = {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
@ -404,6 +416,9 @@ def serialize_job(name, spec, component_name, app_name):
"template": spec
}
}
if CONF.kubernetes.appcontroller["enabled"]:
job = _wrap_with_definition(name, job)
return job
def serialize_deployment(name, spec, annotations, replicas, component_name,
@ -436,12 +451,14 @@ def serialize_deployment(name, spec, annotations, replicas, component_name,
}
}
}
if CONF.kubernetes.appcontroller["enabled"]:
deployment = _wrap_with_definition(name, deployment)
return deployment
def serialize_statefulset(name, spec, annotations, replicas, component_name):
return {
obj = {
"apiVersion": "apps/v1beta1",
"kind": "StatefulSet",
"metadata": {
@ -464,6 +481,10 @@ def serialize_statefulset(name, spec, annotations, replicas, component_name):
}
}
if CONF.kubernetes.appcontroller["enabled"]:
obj = _wrap_with_definition(name, obj)
return obj
def serialize_affinity(service, topology):
policy = {
@ -545,6 +566,9 @@ def serialize_service(name, ports, headless=False, annotations=None):
else:
obj["spec"]["clusterIP"] = "None"
if CONF.kubernetes.appcontroller["enabled"]:
obj = _wrap_with_definition(name, obj)
return obj
@ -589,3 +613,15 @@ def serialize_secret(name, type="Opaque", data={}):
"type": type,
"data": data
}
def serialize_dependency(name, parent, child):
return {
"apiVersion": "appcontroller.k8s/v1alpha1",
"kind": "Dependency",
"metadata": {
"name": name
},
"parent": parent,
"child": child
}