Skip to content

Instantly share code, notes, and snippets.

@mlbiam
Created November 15, 2024 22:51
Show Gist options
  • Save mlbiam/49fef182e85ca4210b5bd4dc9b8bf862 to your computer and use it in GitHub Desktop.
Save mlbiam/49fef182e85ca4210b5bd4dc9b8bf862 to your computer and use it in GitHub Desktop.
Generate Markdown Docs from Kubernetes CRD yaml
import yaml
import os
def generate_markdown(crd_file, output_file, ignore_list):
f = open(crd_file, 'r')
crds = yaml.safe_load_all(f)
markdown = "# OpenUnison Kubernetes CRD Documentation\n\n"
for crd in crds:
if not crd:
continue
kind = crd.get("spec", {}).get("names", {}).get("kind", "Unknown")
group = crd.get("spec", {}).get("group", "Unknown")
versions = crd.get("spec", {}).get("versions", [])
scope = crd.get("spec",{}).get("scope","")
singular = crd.get("spec",{}).get("names",{}).get("singular","")
plural = crd.get("spec",{}).get("names",{}).get("plural","")
if kind in ignore_list:
continue
markdown += f"## {kind}\n\n"
markdown += f"| Attribute | Value |\n"
markdown += f"| --------- | ----- |\n"
markdown += f"| **Group** | {group} |\n"
markdown += f"| **Scope** | {scope} |\n"
markdown += f"| **Singular** | {singular} |\n"
markdown += f"| **Plural** | {plural} |\n\n"
for version in versions:
if not version["storage"]:
continue
version_name = version.get("name", "Unknown")
schema = version.get("schema", {}).get("openAPIV3Schema", {}).get("properties", {})
spec = schema.get("spec", {}).get("properties", {})
markdown += f"### Version: {version_name}\n\n"
markdown += f"{version.get("schema", {}).get("openAPIV3Schema", {}).get("description", {})}\n\n"
markdown += generate_properties_table(0,"root",spec, kind)
# markdown += generate_sub_properties(spec, kind)
with open(output_file, 'w') as f:
f.write(markdown)
def generate_properties_table(depth,root,properties, parent_kind):
"""
Generate a Markdown table for properties of a CRD.
"""
if not properties:
return "No properties found.\n\n"
subTables = "";
table = "| Name | Type | Description |\n"
table += "|------|------|-------------|\n"
for prop, details in properties.items():
prop_type = details.get("type", "Unknown")
description = details.get("description", "").replace('\n','<br>')
if parent_kind == "" :
nroot = root + "-" + parent_kind.lower() + "-" + prop.lower()
else:
nroot = root + "-" + prop.lower()
if prop_type == "object" or (prop_type == "array" and details.get("items", {}).get("type") == "object"):
if not details.get("additionalProperties"):
subTables += generate_sub_props(depth,nroot,prop,details)
description += f" [Details](#{nroot})"
table += f"| {prop} | {prop_type} | {description} |\n"
return table + "\n\n" + subTables
def generate_sub_props(depth,root,name,property):
sub_markdown = "###"
for i in range(0,depth):
sub_markdown += "#"
sub_markdown += f"<a name=\"{root}\"></a> {name}\n\n"
sub_markdown += f"{property.get("description","")}\n\n"
if property.get("type") == "object":
sub_markdown += generate_properties_table(depth+1,root,property.get("properties"),"")
else:
sub_markdown += generate_properties_table(depth+1,root,property.get("items").get("properties"),"")
return sub_markdown
def generate_sub_properties(properties, parent_kind):
"""
Generate Markdown sections for sub-properties of type 'object' or arrays of objects.
"""
sub_markdown = ""
for prop, details in properties.items():
prop_type = details.get("type", "Unknown")
description = details.get("description")
if prop_type == "object":
sub_markdown += f"### {parent_kind} - {prop}\n\n"
sub_markdown += f"{description}\n\n"
sub_markdown += generate_properties_table(details.get("properties", {}), f"{parent_kind}-{prop}")
elif prop_type == "array" and details.get("items", {}).get("type") == "object":
sub_markdown += f"### {parent_kind} - {prop} (Array Items)\n\n"
sub_markdown += f"{description}\n\n"
sub_markdown += generate_properties_table(details.get("items", {}).get("properties", {}), f"{parent_kind}-{prop}")
return sub_markdown
if __name__ == "__main__":
# Replace 'crds.yaml' with the path to your CRD YAML file
# Replace 'output.md' with the desired output file path
# ignore_list = ['User','OidcSession','OpenUnison']
ignore_list = ['User','OidcSession','OpenUnison']
crd_file = "/path/to/openunison-crd.yaml"
output_file = "/path/to/openunison-crds.md"
generate_markdown(crd_file, output_file,ignore_list)
print(f"Documentation generated: {output_file}")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment