fuel-ccp/fuel_ccp/templates.py

328 lines
9.1 KiB
Python

import json
from oslo_config import cfg
from fuel_ccp.common import utils
CONF = cfg.CONF
CONF.import_group('images', 'fuel_ccp.config.images')
CONF.import_group('registry', 'fuel_ccp.config.registry')
GLOBAL_CONFIG = "globals"
SCRIPT_CONFIG = "start-script"
FILES_CONFIG = "files"
META_CONFIG = "meta"
ROLE_CONFIG = "role"
def _get_image_name(image_name):
image_name = "%s/%s:%s" % (CONF.images.namespace, image_name,
CONF.images.tag)
if CONF.registry.address:
image_name = "%s/%s" % (CONF.registry.address, image_name)
return image_name
def _get_start_cmd(cmd_name):
return ["dumb-init", "python",
"/opt/mcp_start_script/bin/start_script.py", cmd_name]
def serialize_configmap(name, data):
return {
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {
"name": name,
"mcp": "true"
},
"data": data
}
def serialize_volume_mounts(container):
spec = [
{
"name": GLOBAL_CONFIG,
"mountPath": "/etc/mcp/%s" % GLOBAL_CONFIG
},
{
"name": ROLE_CONFIG,
"mountPath": "/etc/mcp/%s" % ROLE_CONFIG
},
{
"name": META_CONFIG,
"mountPath": "/etc/mcp/%s" % META_CONFIG
},
{
"name": SCRIPT_CONFIG,
"mountPath": "/opt/mcp_start_script/bin"
},
{
"name": FILES_CONFIG,
"mountPath": "/etc/mcp/%s" % FILES_CONFIG
}
]
for v in container.get("volumes", ()):
spec.append({
"name": v["name"],
"mountPath": v.get("mount-path", v["path"])
})
return spec
def serialize_daemon_container_spec(container):
cont_spec = {
"name": container["name"],
"image": _get_image_name(container["image"]),
"command": _get_start_cmd(container["name"]),
"volumeMounts": serialize_volume_mounts(container)
}
if container.get("probes", {}).get("readiness"):
cont_spec["readinessProbe"] = {
"exec": {
"command": [container["probes"]["readiness"]]
},
"timeoutSeconds": 1
}
if container.get("probes", {}).get("liveness"):
cont_spec["livenessProbe"] = {
"exec": {
"command": [container["probes"]["liveness"]]
},
"timeoutSeconds": 1
}
cont_spec["securityContext"] = {"privileged":
container.get("privileged", False)}
return cont_spec
def serialize_job_container_spec(container, job):
return {
"name": job["name"],
"image": _get_image_name(container["image"]),
"command": _get_start_cmd(job["name"]),
"volumeMounts": serialize_volume_mounts(container)
}
def serialize_job_pod_spec(service, job, cont_spec):
return {
"metadata": {
"name": job["name"]
},
"spec": {
"containers": [cont_spec],
"volumes": serialize_volumes(service),
"restartPolicy": "OnFailure"
}
}
def serialize_daemon_containers(service):
return [serialize_daemon_container_spec(c) for c in service["containers"]]
def serialize_daemon_pod_spec(service):
cont_spec = {
"containers": serialize_daemon_containers(service),
"volumes": serialize_volumes(service),
"restartPolicy": "Always"
}
if service.get("host-net"):
cont_spec["hostNetwork"] = True
return cont_spec
def serialize_volumes(service):
workflow_items = []
for cont in service["containers"]:
workflow_items.append(
{"key": cont["name"], "path": "%s.yaml" % cont["name"]})
for job_type in ("pre", "post"):
for job in cont.get(job_type, ()):
if job.get("type", "local") == "single":
workflow_items.append(
{"key": job["name"], "path": "%s.yaml" % job["name"]})
file_items = []
for c in service["containers"]:
for f_name, f_item in c["daemon"].get("files", {}).items():
file_items.append({"key": f_name, "path": f_name})
for job_type in ("pre", "post"):
for job in c.get(job_type, ()):
if job.get("type", "local") == "single" and job.get("files"):
for f_name in job["files"].keys():
file_items.append({"key": f_name, "path": f_name})
file_items.append({"key": "placeholder", "path": ".placeholder"})
vol_spec = [
{
"name": GLOBAL_CONFIG,
"configMap": {
"name": GLOBAL_CONFIG,
"items": [{"key": GLOBAL_CONFIG,
"path": "globals.yaml"}]
}
},
{
"name": SCRIPT_CONFIG,
"configMap": {
"name": SCRIPT_CONFIG,
"items": [{"key": SCRIPT_CONFIG,
"path": "start_script.py"}]
}
},
{
"name": ROLE_CONFIG,
"configMap": {
"name": "%s-%s" % (service["name"], ROLE_CONFIG),
"items": workflow_items
}
},
{
"name": META_CONFIG,
"configMap": {
"name": "%s-%s" % (service["name"], META_CONFIG),
"items": [{"key": META_CONFIG,
"path": "meta.yaml"}]
}
},
{
"name": FILES_CONFIG,
"configMap": {
"name": "%s-%s" % (service["name"], FILES_CONFIG),
"items": file_items
}
}
]
volume_names = [GLOBAL_CONFIG, META_CONFIG, ROLE_CONFIG, SCRIPT_CONFIG,
FILES_CONFIG]
for cont in service["containers"]:
for v in cont.get("volumes", ()):
if v["name"] in volume_names:
# TODO(apavlov): move to validation
continue
if v["type"] == "host":
vol_spec.append({
"name": v["name"],
"hostPath": {
"path": v["path"]
}
})
elif v["type"] == "empty-dir":
vol_spec.append({
"name": v["name"],
"emptyDir": {}
})
else:
# TODO(sreshetniak): move it to validation
raise ValueError("Volume type \"%s\" not supported" %
v["type"])
volume_names.append(v["name"])
return vol_spec
def serialize_job(name, spec):
return {
"apiVersion": "batch/v1",
"kind": "Job",
"metadata": {
"name": name,
"mcp": "true"
},
"spec": {
"template": spec
}
}
def serialize_deployment(name, spec, affinity):
return {
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
"metadata": {
"name": name
},
"spec": {
"replicas": 1,
"template": {
"metadata": {
"annotations": affinity,
"labels": {
"mcp": "true",
"app": name
}
},
"spec": spec
}
}
}
def serialize_daemonset(name, spec, affinity):
return {
"apiVersion": "extensions/v1beta1",
"kind": "DaemonSet",
"metadata": {
"name": name
},
"spec": {
"template": {
"metadata": {
"annotations": affinity,
"labels": {
"mcp": "true",
"app": name
}
},
"spec": spec
}
}
}
def serialize_affinity(service, topology):
policy = {
"nodeAffinity": {
"requiredDuringSchedulingIgnoredDuringExecution": {
"nodeSelectorTerms": [{
"matchExpressions": [{
"key": "kubernetes.io/hostname",
"operator": "In",
"values": topology[service["name"]]
}]
}]
}
}
}
return {"scheduler.alpha.kubernetes.io/affinity": json.dumps(policy)}
def serialize_service(name, ports):
ports_spec = []
for port in ports:
spec_entry = {"protocol": "TCP",
"port": port["port"],
"targetPort": port["port"],
"name": utils.k8s_name(port["name"])}
if port.get("node-port"):
spec_entry.update({"nodePort": port["node-port"]})
ports_spec.append(spec_entry)
return {
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": name,
"mcp": "true"
},
"spec": {
"type": "NodePort",
"selector": {
"app": name
},
"ports": ports_spec
}
}