Initial AppController integration
Change-Id: Ic3dc48a93f2cc1a4d3ff3e513b5cfcc545289c6b
This commit is contained in:
parent
a5083dc520
commit
ddf451199c
|
@ -10,6 +10,9 @@ DEFAULTS = {
|
||||||
'password': None,
|
'password': None,
|
||||||
'cluster_domain': 'cluster.local',
|
'cluster_domain': 'cluster.local',
|
||||||
'image_pull_policy': None,
|
'image_pull_policy': None,
|
||||||
|
'appcontroller': {
|
||||||
|
"enabled": False
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +36,13 @@ SCHEMA = {
|
||||||
{'type': 'null'},
|
{'type': 'null'},
|
||||||
{'enum': ['Always', 'IfNotPresent', 'Never']},
|
{'enum': ['Always', 'IfNotPresent', 'Never']},
|
||||||
]},
|
]},
|
||||||
|
'appcontroller': {
|
||||||
|
'type': 'object',
|
||||||
|
'additionalProperties': False,
|
||||||
|
'properties': {
|
||||||
|
"enabled": {'type': 'boolean'},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ def _process_secrets(secrets):
|
||||||
type, data)
|
type, data)
|
||||||
|
|
||||||
|
|
||||||
def parse_role(component, topology, configmaps):
|
def parse_role(component, topology, configmaps, components_map):
|
||||||
service_dir = component["service_dir"]
|
service_dir = component["service_dir"]
|
||||||
role = component["service_content"]
|
role = component["service_content"]
|
||||||
component_name = component["component_name"]
|
component_name = component["component_name"]
|
||||||
|
@ -114,6 +114,8 @@ def parse_role(component, topology, configmaps):
|
||||||
yield _process_secrets(role.get("secrets"))
|
yield _process_secrets(role.get("secrets"))
|
||||||
|
|
||||||
workflows = _parse_workflows(service)
|
workflows = _parse_workflows(service)
|
||||||
|
if CONF.kubernetes.appcontroller['enabled']:
|
||||||
|
yield create_dependencies(workflows, components_map)
|
||||||
serialize_workflows(workflows)
|
serialize_workflows(workflows)
|
||||||
workflow_cm = _create_workflow(workflows, service_name)
|
workflow_cm = _create_workflow(workflows, service_name)
|
||||||
configmaps = configmaps + (files_cm, meta_cm, workflow_cm)
|
configmaps = configmaps + (files_cm, meta_cm, workflow_cm)
|
||||||
|
@ -627,6 +629,27 @@ def _create_registry_secret():
|
||||||
kubernetes.process_object(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):
|
def deploy_components(components_map, components):
|
||||||
|
|
||||||
topology = _make_topology(CONF.nodes, CONF.roles, CONF.replicas)
|
topology = _make_topology(CONF.nodes, CONF.roles, CONF.replicas)
|
||||||
|
@ -662,7 +685,7 @@ def deploy_components(components_map, components):
|
||||||
for service_name in components:
|
for service_name in components:
|
||||||
service = components_map[service_name]
|
service = components_map[service_name]
|
||||||
service["service_content"]['service']['exports_ctx'] = exports_ctx
|
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))
|
objects = list(itertools.chain.from_iterable(objects_gen))
|
||||||
component_name = service['component_name']
|
component_name = service['component_name']
|
||||||
do_upgrade = component_name in upgrading_components
|
do_upgrade = component_name in upgrading_components
|
||||||
|
|
|
@ -2,6 +2,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pykube.exceptions
|
import pykube.exceptions
|
||||||
|
import pykube.objects
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from fuel_ccp import config
|
from fuel_ccp import config
|
||||||
|
@ -94,8 +95,8 @@ def get_pykube_object(object_dict, namespace=None, client=None):
|
||||||
namespace = CONF.kubernetes.namespace
|
namespace = CONF.kubernetes.namespace
|
||||||
if client is None:
|
if client is None:
|
||||||
client = get_client()
|
client = get_client()
|
||||||
|
obj_class = getattr(pykube, object_dict["kind"], None) or globals().get(
|
||||||
obj_class = getattr(pykube, object_dict["kind"], None)
|
object_dict["kind"], None)
|
||||||
if obj_class is None:
|
if obj_class is None:
|
||||||
raise RuntimeError('"%s" object is not supported, skipping.'
|
raise RuntimeError('"%s" object is not supported, skipping.'
|
||||||
% object_dict['kind'])
|
% object_dict['kind'])
|
||||||
|
@ -127,7 +128,6 @@ def process_object(object_dict, namespace=None, client=None):
|
||||||
if CONF.action.dry_run:
|
if CONF.action.dry_run:
|
||||||
LOG.info(yaml.dump(object_dict, default_flow_style=False))
|
LOG.info(yaml.dump(object_dict, default_flow_style=False))
|
||||||
return
|
return
|
||||||
|
|
||||||
obj = get_pykube_object(object_dict, namespace=namespace, client=client)
|
obj = get_pykube_object(object_dict, namespace=namespace, client=client)
|
||||||
|
|
||||||
if obj.exists():
|
if obj.exists():
|
||||||
|
@ -226,3 +226,27 @@ def get_configmap(name):
|
||||||
return pykube.ConfigMap.objects(client).filter(
|
return pykube.ConfigMap.objects(client).filter(
|
||||||
namespace=CONF.kubernetes.namespace,
|
namespace=CONF.kubernetes.namespace,
|
||||||
selector="ccp=true").get_by_name(name)
|
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)
|
||||||
|
|
|
@ -29,6 +29,18 @@ def _get_readiness_cmd(role_name):
|
||||||
return [PYTHON_PATH, ENTRYPOINT_PATH, "status", 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):
|
def serialize_namespace(name):
|
||||||
return {
|
return {
|
||||||
"apiVersion": "v1",
|
"apiVersion": "v1",
|
||||||
|
@ -376,7 +388,7 @@ def serialize_volumes(service, for_job=None):
|
||||||
|
|
||||||
|
|
||||||
def serialize_job(name, spec, component_name, app_name):
|
def serialize_job(name, spec, component_name, app_name):
|
||||||
return {
|
job = {
|
||||||
"apiVersion": "batch/v1",
|
"apiVersion": "batch/v1",
|
||||||
"kind": "Job",
|
"kind": "Job",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -391,6 +403,9 @@ def serialize_job(name, spec, component_name, app_name):
|
||||||
"template": spec
|
"template": spec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if CONF.kubernetes.appcontroller["enabled"]:
|
||||||
|
job = _wrap_with_definition(name, job)
|
||||||
|
return job
|
||||||
|
|
||||||
|
|
||||||
def serialize_deployment(name, spec, annotations, replicas, component_name,
|
def serialize_deployment(name, spec, annotations, replicas, component_name,
|
||||||
|
@ -423,12 +438,14 @@ def serialize_deployment(name, spec, annotations, replicas, component_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if CONF.kubernetes.appcontroller["enabled"]:
|
||||||
|
deployment = _wrap_with_definition(name, deployment)
|
||||||
|
|
||||||
return deployment
|
return deployment
|
||||||
|
|
||||||
|
|
||||||
def serialize_statefulset(name, spec, annotations, replicas, component_name):
|
def serialize_statefulset(name, spec, annotations, replicas, component_name):
|
||||||
return {
|
obj = {
|
||||||
"apiVersion": "apps/v1beta1",
|
"apiVersion": "apps/v1beta1",
|
||||||
"kind": "StatefulSet",
|
"kind": "StatefulSet",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -451,6 +468,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):
|
def serialize_affinity(service, topology):
|
||||||
policy = {
|
policy = {
|
||||||
|
@ -532,6 +553,9 @@ def serialize_service(name, ports, headless=False, annotations=None):
|
||||||
else:
|
else:
|
||||||
obj["spec"]["clusterIP"] = "None"
|
obj["spec"]["clusterIP"] = "None"
|
||||||
|
|
||||||
|
if CONF.kubernetes.appcontroller["enabled"]:
|
||||||
|
obj = _wrap_with_definition(name, obj)
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
|
@ -576,3 +600,15 @@ def serialize_secret(name, type="Opaque", data={}):
|
||||||
"type": type,
|
"type": type,
|
||||||
"data": data
|
"data": data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def serialize_dependency(name, parent, child):
|
||||||
|
return {
|
||||||
|
"apiVersion": "appcontroller.k8s/v1alpha1",
|
||||||
|
"kind": "Dependency",
|
||||||
|
"metadata": {
|
||||||
|
"name": name
|
||||||
|
},
|
||||||
|
"parent": parent,
|
||||||
|
"child": child
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue