mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 12:50:05 +01:00
feat: adding terraform readme generator
This commit is contained in:
30
terraform/envs/dev/Makefile
Normal file
30
terraform/envs/dev/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
# Makefile
|
||||
# Usage:
|
||||
# make # generate Markdown from schema
|
||||
# make schema # just (re)generate schema.json
|
||||
# make clean # remove generated files
|
||||
#
|
||||
# Notes:
|
||||
# - CLI defaults to 'tofu' but can be switched to 'terraform' by doing: make CLI=terraform
|
||||
# - Your cwd must contain a minimal config that requires the provider so the schema includes it.
|
||||
|
||||
CLI ?= tofu
|
||||
SCHEMA ?= schema.json
|
||||
OUT ?= autoglue_provider_reference.md
|
||||
GEN ?= scripts/gen_md.py
|
||||
PROVIDER ?= glueops/autoglue/autoglue
|
||||
|
||||
.PHONY: all schema clean
|
||||
|
||||
all: $(OUT)
|
||||
|
||||
schema: $(SCHEMA)
|
||||
|
||||
$(SCHEMA):
|
||||
$(CLI) providers schema -json > $(SCHEMA)
|
||||
|
||||
$(OUT): $(SCHEMA) $(GEN)
|
||||
python3 $(GEN) --provider "$(PROVIDER)" --schema "$(SCHEMA)" --out "$(OUT)"
|
||||
|
||||
clean:
|
||||
rm -f $(SCHEMA) $(OUT)
|
||||
268
terraform/envs/dev/autoglue_provider_reference.md
Normal file
268
terraform/envs/dev/autoglue_provider_reference.md
Normal file
@@ -0,0 +1,268 @@
|
||||
# glueops/autoglue/autoglue – Reference (generated)
|
||||
|
||||
_Generated from providers schema JSON._
|
||||
|
||||
## Provider Configuration
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `addr` | string | optional | Base URL to the autoglue API (e.g. https://autoglue.example.com/api/v1). Defaults to http://localhost:8080/api/v1. |
|
||||
| `api_key` | string | optional, sensitive | User API key for key-only auth. |
|
||||
| `bearer` | string | optional, sensitive | Bearer token (user access token). |
|
||||
| `org_id` | string | optional | Organization ID (UUID). Required for user/bearer and user API key auth unless single-org membership. Omitted for org key/secret (derived server-side). |
|
||||
| `org_key` | string | optional, sensitive | Org-scoped key for machine auth. |
|
||||
| `org_secret` | string | optional, sensitive | Org-scoped secret for machine auth. |
|
||||
|
||||
|
||||
### Basic usage
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
autoglue = {
|
||||
source = "glueops/autoglue/autoglue"
|
||||
# version = ">= 0.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "autoglue" {
|
||||
# addr = "..."
|
||||
# api_key = "..."
|
||||
# bearer = "..."
|
||||
# org_id = "..."
|
||||
# org_key = "..."
|
||||
# org_secret = "..."
|
||||
}
|
||||
```
|
||||
## Provider Functions
|
||||
|
||||
_No provider-defined functions._
|
||||
|
||||
## Resources
|
||||
|
||||
### `autoglue_annotation`
|
||||
|
||||
Create and manage a annotation (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `created_at` | string | computed | |
|
||||
| `id` | string | computed | ID (UUID). |
|
||||
| `key` | string | required | Key. |
|
||||
| `organization_id` | string | computed | |
|
||||
| `raw` | string | computed | Full server JSON from API. |
|
||||
| `updated_at` | string | computed | |
|
||||
| `value` | string | required | Value. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
resource "autoglue_annotation" "example" {
|
||||
key = "..."
|
||||
value = "..."
|
||||
}
|
||||
```
|
||||
### `autoglue_label`
|
||||
|
||||
Create and manage a label (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `created_at` | string | computed | |
|
||||
| `id` | string | computed | Server ID (UUID). |
|
||||
| `key` | string | required | Key. |
|
||||
| `organization_id` | string | computed | |
|
||||
| `raw` | string | computed | Full server JSON from API. |
|
||||
| `updated_at` | string | computed | |
|
||||
| `value` | string | required | Value. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
resource "autoglue_label" "example" {
|
||||
key = "..."
|
||||
value = "..."
|
||||
}
|
||||
```
|
||||
### `autoglue_server`
|
||||
|
||||
Create and manage a server (org-scoped). Mirrors API validation for role/status/ssh_key_id.
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `created_at` | string | computed | |
|
||||
| `hostname` | string | required | Hostname. |
|
||||
| `id` | string | computed | Server ID (UUID). |
|
||||
| `organization_id` | string | computed | |
|
||||
| `private_ip_address` | string | required | Private IP address (required). |
|
||||
| `public_ip_address` | string | optional | Public IP address (required when role = bastion). |
|
||||
| `raw` | string | computed | Full server JSON from API. |
|
||||
| `role` | string | required | Server role (e.g., agent/manager/bastion). Lowercased by the provider. |
|
||||
| `ssh_key_id` | string | required | SSH key ID (UUID) that belongs to the org. |
|
||||
| `ssh_user` | string | required | SSH username (required). |
|
||||
| `status` | string | optional, computed | Status (pending|provisioning|ready|failed). Lowercased by the provider. |
|
||||
| `updated_at` | string | computed | |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
resource "autoglue_server" "example" {
|
||||
hostname = "..."
|
||||
private_ip_address = "..."
|
||||
role = "..."
|
||||
ssh_key_id = "..."
|
||||
ssh_user = "..."
|
||||
}
|
||||
```
|
||||
### `autoglue_ssh_key`
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `bits` | number | optional | RSA key size (2048/3072/4096). Ignored for ed25519. |
|
||||
| `comment` | string | required | Comment appended to authorized key |
|
||||
| `created_at` | string | computed | Creation time (RFC3339, UTC) |
|
||||
| `fingerprint` | string | computed | SHA256 fingerprint |
|
||||
| `id` | string | computed | SSH key ID (UUID) |
|
||||
| `name` | string | required | Display name |
|
||||
| `private_key_pem` | string | computed, sensitive | Private key PEM (resource doesn’t reveal; stays empty). |
|
||||
| `public_key` | string | computed | OpenSSH authorized key |
|
||||
| `type` | string | optional | Key type: rsa or ed25519 (default rsa) |
|
||||
| `updated_at` | string | computed | Update time (RFC3339, UTC) |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
resource "autoglue_ssh_key" "example" {
|
||||
comment = "..."
|
||||
name = "..."
|
||||
}
|
||||
```
|
||||
### `autoglue_taint`
|
||||
|
||||
Create and manage a taint (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `created_at` | string | computed | |
|
||||
| `effect` | string | required | Effect. |
|
||||
| `id` | string | computed | Server ID (UUID). |
|
||||
| `key` | string | required | Key. |
|
||||
| `organization_id` | string | computed | |
|
||||
| `raw` | string | computed | Full server JSON from API. |
|
||||
| `updated_at` | string | computed | |
|
||||
| `value` | string | required | Value. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
resource "autoglue_taint" "example" {
|
||||
effect = "..."
|
||||
key = "..."
|
||||
value = "..."
|
||||
}
|
||||
```
|
||||
## Data Sources
|
||||
|
||||
### `autoglue_annotations`
|
||||
|
||||
List annotations for the organization (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `items` | (block) | computed | Annotations returned by the API. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
data "autoglue_annotations" "all" {}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {
|
||||
# value = try(data.autoglue_annotations.all.items[0].raw, null)
|
||||
# }
|
||||
```
|
||||
### `autoglue_labels`
|
||||
|
||||
List labels for the organization (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `items` | (block) | computed | Labels returned by the API. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
data "autoglue_labels" "all" {}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {
|
||||
# value = try(data.autoglue_labels.all.items[0].raw, null)
|
||||
# }
|
||||
```
|
||||
### `autoglue_servers`
|
||||
|
||||
List servers for the organization (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `items` | (block) | computed | Servers returned by the API. |
|
||||
| `role` | string | optional | Filter by role. |
|
||||
| `status` | string | optional | Filter by status (pending|provisioning|ready|failed). |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
data "autoglue_servers" "all" {}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {
|
||||
# value = try(data.autoglue_servers.all.items[0].raw, null)
|
||||
# }
|
||||
```
|
||||
### `autoglue_ssh_keys`
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `fingerprint` | string | optional | Filter by exact fingerprint (client-side). |
|
||||
| `keys` | (block) | computed | SSH keys |
|
||||
| `name_contains` | string | optional | Filter by substring of name (client-side). |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
data "autoglue_ssh_keys" "all" {}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {
|
||||
# value = try(data.autoglue_ssh_keys.all.items[0].raw, null)
|
||||
# }
|
||||
```
|
||||
### `autoglue_taints`
|
||||
|
||||
List taints for the organization (org-scoped).
|
||||
|
||||
| Name | Type | Flags | Description |
|
||||
|---|---|---|---|
|
||||
| `items` | (block) | computed | Taints returned by the API. |
|
||||
|
||||
|
||||
**Example**
|
||||
|
||||
```hcl
|
||||
data "autoglue_taints" "all" {}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {
|
||||
# value = try(data.autoglue_taints.all.items[0].raw, null)
|
||||
# }
|
||||
```
|
||||
1
terraform/envs/dev/schema.json
Normal file
1
terraform/envs/dev/schema.json
Normal file
File diff suppressed because one or more lines are too long
180
terraform/envs/dev/scripts/gen_md.py
Normal file
180
terraform/envs/dev/scripts/gen_md.py
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse, json, sys
|
||||
from textwrap import dedent
|
||||
|
||||
def type_to_str(t):
|
||||
if isinstance(t, list):
|
||||
return "[" + ", ".join(type_to_str(x) for x in t) + "]"
|
||||
if isinstance(t, dict):
|
||||
if "attribute_types" in t:
|
||||
return "object(" + ", ".join(f"{k}:{type_to_str(v)}" for k,v in t["attribute_types"].items()) + ")"
|
||||
return json.dumps(t)
|
||||
return str(t)
|
||||
|
||||
def flags(spec):
|
||||
f = []
|
||||
if spec.get("required"): f.append("required")
|
||||
if spec.get("optional"): f.append("optional")
|
||||
if spec.get("computed"): f.append("computed")
|
||||
if spec.get("sensitive"): f.append("sensitive")
|
||||
return ", ".join(f) if f else "-"
|
||||
|
||||
def md_table_row(name, spec):
|
||||
t = spec.get("type")
|
||||
t_str = type_to_str(t) if t is not None else "(block)"
|
||||
desc = (spec.get("description") or "").replace("\n", " ")
|
||||
return f"| `{name}` | {t_str} | {flags(spec)} | {desc} |"
|
||||
|
||||
def render_block(block):
|
||||
out = []
|
||||
attrs = block.get("attributes") or {}
|
||||
if attrs:
|
||||
out += ["| Name | Type | Flags | Description |",
|
||||
"|---|---|---|---|"]
|
||||
for k, v in attrs.items():
|
||||
out.append(md_table_row(k, v))
|
||||
out.append("")
|
||||
# nested blocks
|
||||
for bname, b in (block.get("block_types") or {}).items():
|
||||
out.append(f"**Nested block `{bname}`** (mode: {b.get('nesting_mode','')})")
|
||||
nb = b.get("block", {})
|
||||
nattrs = nb.get("attributes") or {}
|
||||
if nattrs:
|
||||
out += ["| Name | Type | Flags | Description |",
|
||||
"|---|---|---|---|"]
|
||||
for k, v in nattrs.items():
|
||||
out.append(md_table_row(k, v))
|
||||
out.append("")
|
||||
return "\n".join(out)
|
||||
|
||||
def required_attrs(block):
|
||||
return [k for k, v in (block.get("attributes") or {}).items() if v.get("required")]
|
||||
|
||||
def example_provider(provider_key, pblock):
|
||||
lines = [
|
||||
'terraform {',
|
||||
' required_providers {',
|
||||
f' autoglue = {{',
|
||||
f' source = "{provider_key}"',
|
||||
' # version = ">= 0.0.0"',
|
||||
' }',
|
||||
' }',
|
||||
'}',
|
||||
'',
|
||||
'provider "autoglue" {',
|
||||
]
|
||||
for k, v in (pblock.get("attributes") or {}).items():
|
||||
if v.get("required"):
|
||||
lines.append(f' {k} = "REQUIRED_{k.upper()}"')
|
||||
for k, v in (pblock.get("attributes") or {}).items():
|
||||
if v.get("optional") and not v.get("computed"):
|
||||
lines.append(f' # {k} = "..."')
|
||||
lines.append('}')
|
||||
return "```hcl\n" + "\n".join(lines) + "\n```"
|
||||
|
||||
def example_resource(rname, rblock):
|
||||
reqs = required_attrs(rblock)
|
||||
if reqs:
|
||||
body = "\n".join(f' {k} = "..."' for k in reqs)
|
||||
else:
|
||||
body = " # no required attributes"
|
||||
return f"```hcl\nresource \"{rname}\" \"example\" {{\n{body}\n}}\n```"
|
||||
|
||||
def example_data(dname, _dblock):
|
||||
return f"""```hcl
|
||||
data "{dname}" "all" {{}}
|
||||
|
||||
# Example of reading exported fields (adjust to your needs):
|
||||
# output "first_item_raw" {{
|
||||
# value = try(data.{dname}.all.items[0].raw, null)
|
||||
# }}
|
||||
```"""
|
||||
|
||||
def example_function_call(provider_local_name, fname):
|
||||
return f"""```hcl
|
||||
# Example of calling a provider function (if available)
|
||||
# local value = {provider_local_name}::{fname}("arg")
|
||||
```"""
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--schema", required=True)
|
||||
ap.add_argument("--provider", required=True, help="provider key e.g. glueops/autoglue/autoglue")
|
||||
ap.add_argument("--out", required=True)
|
||||
args = ap.parse_args()
|
||||
|
||||
with open(args.schema, "r", encoding="utf-8") as f:
|
||||
doc = json.load(f)
|
||||
|
||||
prov = (doc.get("provider_schemas") or {}).get(args.provider)
|
||||
if not prov:
|
||||
sys.exit(f"Provider '{args.provider}' not found in schema.")
|
||||
|
||||
out = []
|
||||
out.append(f"# {args.provider} – Reference (generated)\n")
|
||||
out.append("_Generated from providers schema JSON._\n")
|
||||
|
||||
# Provider config
|
||||
pblock = (prov.get("provider") or {}).get("block", {}) or {}
|
||||
out.append("## Provider Configuration\n")
|
||||
out.append(render_block(pblock) or "_No provider configuration attributes found._")
|
||||
out.append("\n### Basic usage\n")
|
||||
out.append(example_provider(args.provider, pblock))
|
||||
|
||||
# Functions
|
||||
funcs = prov.get("functions") or {}
|
||||
out.append("## Provider Functions\n")
|
||||
if not funcs:
|
||||
out.append("_No provider-defined functions._\n")
|
||||
else:
|
||||
for fname, fdef in funcs.items():
|
||||
out.append(f"### `{fname}`\n")
|
||||
out.append((fdef.get("summary") or fdef.get("description") or "").strip() + "\n")
|
||||
out.append(f"- **Return type:** `{type_to_str(fdef.get('return_type'))}`\n")
|
||||
params = fdef.get("parameters") or []
|
||||
if params:
|
||||
out.append("\n**Parameters**\n")
|
||||
out.append("| Name | Type | Description |\n|---|---|---|\n")
|
||||
for p in params:
|
||||
pdesc = (p.get("description") or "").replace("\n", " ")
|
||||
out.append(f"| `{p.get('name')}` | {type_to_str(p.get('type'))} | {pdesc} |\n")
|
||||
out.append("\n")
|
||||
out.append(example_function_call("autoglue", fname))
|
||||
|
||||
# Resources
|
||||
resources = prov.get("resource_schemas") or {}
|
||||
out.append("## Resources\n")
|
||||
if not resources:
|
||||
out.append("_None._\n")
|
||||
else:
|
||||
for rname in sorted(resources.keys()):
|
||||
rs = resources[rname]
|
||||
rblock = rs.get("block", {}) or {}
|
||||
out.append(f"### `{rname}`\n")
|
||||
if rblock.get("description"):
|
||||
out.append(rblock["description"] + "\n")
|
||||
out.append(render_block(rblock) or "_No attributes._")
|
||||
out.append("\n**Example**\n")
|
||||
out.append(example_resource(rname, rblock))
|
||||
|
||||
# Data sources
|
||||
datas = prov.get("data_source_schemas") or {}
|
||||
out.append("## Data Sources\n")
|
||||
if not datas:
|
||||
out.append("_None._\n")
|
||||
else:
|
||||
for dname in sorted(datas.keys()):
|
||||
ds = datas[dname]
|
||||
dblock = ds.get("block", {}) or {}
|
||||
out.append(f"### `{dname}`\n")
|
||||
if dblock.get("description"):
|
||||
out.append(dblock["description"] + "\n")
|
||||
out.append(render_block(dblock) or "_No attributes._")
|
||||
out.append("\n**Example**\n")
|
||||
out.append(example_data(dname, dblock))
|
||||
|
||||
with open(args.out, "w", encoding="utf-8") as f:
|
||||
f.write("\n".join(out))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user