import json
import sys
try:
import yaml
except ImportError:
sys.exit("PyYAML required: pip install pyyaml")
SRC = "backends/foundation_deployment_docker/specs/docker-engine-v1.53.yaml"
OUT = "artefacts/cloud_providers/docker/openapi.json"
STREAM_ITEMS = {
"ImageCreate": "CreateImageInfo",
"ImagePush": "PushImageInfo",
"ImageBuild": "BuildInfo",
"ImageLoad": "BuildInfo",
"ContainerStats": "ContainerStatsResponse",
}
JSON_LINES = "application/jsonl"
JSON_TYPES = ("application/json",)
TEXT_TYPES = ("text/plain",)
def media_type(declared, fallback):
types = declared or fallback or []
return types[0] if types else "application/json"
PARAM_SCHEMA_KEYS = ("type", "items", "format", "enum", "default", "collectionFormat")
def param_to_v3(pm):
out = {k: v for k, v in pm.items() if k not in PARAM_SCHEMA_KEYS}
schema = {k: v for k, v in pm.items() if k in PARAM_SCHEMA_KEYS and k != "collectionFormat"}
if schema:
out["schema"] = schema
return out
def rewrite_refs(obj):
if isinstance(obj, dict):
out = {}
for k, v in obj.items():
if k == "$ref" and isinstance(v, str) and v.startswith("#/definitions/"):
out[k] = v.replace("#/definitions/", "#/components/schemas/")
else:
out[k] = rewrite_refs(v)
return out
if isinstance(obj, list):
return [rewrite_refs(v) for v in obj]
return obj
def main():
with open(SRC) as f:
s = yaml.safe_load(f)
definitions = rewrite_refs(s.get("definitions", {}))
global_produces = s.get("produces")
global_consumes = s.get("consumes")
base_url = f"http://localhost{s.get('basePath', '')}"
new_paths = {}
for path, item in s.get("paths", {}).items():
new_item = {}
for method, op in item.items():
if method not in ("get", "post", "put", "patch", "delete", "options", "head"):
new_item[method] = rewrite_refs(op)
continue
op = rewrite_refs(op)
new_op = {k: v for k, v in op.items() if k not in ("parameters", "responses")}
produces = media_type(op.get("produces"), global_produces)
consumes = media_type(op.get("consumes"), global_consumes)
kept, body_schema, body_required = [], None, False
for pm in op.get("parameters", []) or []:
if pm.get("in") == "body":
body_schema = pm.get("schema")
body_required = bool(pm.get("required", False))
elif pm.get("in") == "formData":
body_schema = body_schema or {"type": "object"}
body_required = body_required or bool(pm.get("required", False))
else:
kept.append(param_to_v3(pm))
if kept:
new_op["parameters"] = kept
if body_schema is not None:
new_op["requestBody"] = {
"content": {consumes: {"schema": body_schema}},
"required": body_required,
}
stream_item = STREAM_ITEMS.get(op.get("operationId"))
new_resp = {}
for code, resp in (op.get("responses", {}) or {}).items():
resp = dict(resp)
sch = resp.pop("schema", None)
success = str(code).startswith("2")
if success and stream_item is not None:
resp["content"] = {
JSON_LINES: {"schema": {"$ref": f"#/components/schemas/{stream_item}"}}
}
elif sch is not None:
resp["content"] = {(produces if success else "application/json"): {"schema": sch}}
elif success and produces not in JSON_TYPES + TEXT_TYPES:
resp["content"] = {produces: {"schema": {"type": "string", "format": "binary"}}}
new_resp[str(code)] = resp
new_op["responses"] = new_resp
new_item[method] = new_op
new_paths[path] = new_item
spec3 = {
"openapi": "3.0.0",
"info": s.get("info", {"title": "Docker Engine API", "version": "1.53"}),
"servers": [{"url": base_url}],
"paths": new_paths,
"components": {"schemas": definitions},
}
with open(OUT, "w") as f:
json.dump(spec3, f)
print(f"converted -> {OUT}: {len(definitions)} schemas, {len(new_paths)} paths, base_url={base_url}")
if __name__ == "__main__":
main()