diff --git a/internal/models/node_pool.go b/internal/models/node_pool.go index 3f59ccc..9238d3f 100644 --- a/internal/models/node_pool.go +++ b/internal/models/node_pool.go @@ -16,8 +16,8 @@ type NodePool struct { Labels []Label `gorm:"many2many:node_labels;constraint:OnDelete:CASCADE" json:"labels,omitempty"` Taints []Taint `gorm:"many2many:node_taints;constraint:OnDelete:CASCADE" json:"taints,omitempty"` //Clusters []Cluster `gorm:"many2many:cluster_node_pools;constraint:OnDelete:CASCADE" json:"clusters,omitempty"` - Topology string `gorm:"not null" json:"topology,omitempty"` // stacked or external - Role string `gorm:"not null" json:"role,omitempty"` // master, worker, or etcd (etcd only if topology = external + //Topology string `gorm:"not null,default:'stacked'" json:"topology,omitempty"` // stacked or external + Role string `gorm:"not null,default:'worker'" json:"role,omitempty"` // master, worker, or etcd (etcd only if topology = external CreatedAt time.Time `gorm:"not null;default:now()" json:"created_at" format:"date-time"` UpdatedAt time.Time `gorm:"not null;default:now()" json:"updated_at" format:"date-time"` } diff --git a/internal/models/taint.go b/internal/models/taint.go index 38a0869..1540a51 100644 --- a/internal/models/taint.go +++ b/internal/models/taint.go @@ -13,6 +13,7 @@ type Taint struct { Key string `gorm:"not null" json:"key"` Value string `gorm:"not null" json:"value"` Effect string `gorm:"not null" json:"effect"` + NodePools []NodePool `gorm:"many2many:node_taints;constraint:OnDelete:CASCADE" json:"servers,omitempty"` CreatedAt time.Time `gorm:"column:created_at;not null;default:now()" json:"created_at" format:"date-time"` UpdatedAt time.Time `gorm:"autoUpdateTime;column:updated_at;not null;default:now()" json:"updated_at" format:"date-time"` } diff --git a/terraform-provider-autoglue/internal/provider/config.go b/terraform-provider-autoglue/internal/provider/config.go index 506ed78..256b967 100644 --- a/terraform-provider-autoglue/internal/provider/config.go +++ b/terraform-provider-autoglue/internal/provider/config.go @@ -25,7 +25,7 @@ func providerConfigSchema() map[string]pschema.Attribute { return map[string]pschema.Attribute{ "addr": pschema.StringAttribute{ Optional: true, - Description: "Base URL to the autoglue API (e.g. https://gsot.example.com/api/v1). Defaults to http://localhost:8080/api/v1.", + Description: "Base URL to the autoglue API (e.g. https://autoglue.example.com/api/v1). Defaults to http://localhost:8080/api/v1.", }, "bearer": pschema.StringAttribute{ Optional: true, diff --git a/terraform/envs/dev/Makefile b/terraform/envs/dev/Makefile new file mode 100644 index 0000000..685b9be --- /dev/null +++ b/terraform/envs/dev/Makefile @@ -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) diff --git a/terraform/envs/dev/autoglue_provider_reference.md b/terraform/envs/dev/autoglue_provider_reference.md new file mode 100644 index 0000000..cd9d57c --- /dev/null +++ b/terraform/envs/dev/autoglue_provider_reference.md @@ -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) +# } +``` \ No newline at end of file diff --git a/terraform/envs/dev/schema.json b/terraform/envs/dev/schema.json new file mode 100644 index 0000000..91099a5 --- /dev/null +++ b/terraform/envs/dev/schema.json @@ -0,0 +1 @@ +{"format_version":"1.0","provider_schemas":{"glueops/autoglue/autoglue":{"provider":{"version":0,"block":{"attributes":{"addr":{"type":"string","description":"Base URL to the autoglue API (e.g. https://autoglue.example.com/api/v1). Defaults to http://localhost:8080/api/v1.","description_kind":"plain","optional":true},"api_key":{"type":"string","description":"User API key for key-only auth.","description_kind":"plain","optional":true,"sensitive":true},"bearer":{"type":"string","description":"Bearer token (user access token).","description_kind":"plain","optional":true,"sensitive":true},"org_id":{"type":"string","description":"Organization ID (UUID). Required for user/bearer and user API key auth unless single-org membership. Omitted for org key/secret (derived server-side).","description_kind":"plain","optional":true},"org_key":{"type":"string","description":"Org-scoped key for machine auth.","description_kind":"plain","optional":true,"sensitive":true},"org_secret":{"type":"string","description":"Org-scoped secret for machine auth.","description_kind":"plain","optional":true,"sensitive":true}},"description_kind":"plain"}},"resource_schemas":{"autoglue_annotation":{"version":0,"block":{"attributes":{"created_at":{"type":"string","description_kind":"plain","computed":true},"id":{"type":"string","description":"ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description":"Key.","description_kind":"plain","required":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full server JSON from API.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description_kind":"plain","computed":true},"value":{"type":"string","description":"Value.","description_kind":"plain","required":true}},"description":"Create and manage a annotation (org-scoped).","description_kind":"plain"}},"autoglue_label":{"version":0,"block":{"attributes":{"created_at":{"type":"string","description_kind":"plain","computed":true},"id":{"type":"string","description":"Server ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description":"Key.","description_kind":"plain","required":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full server JSON from API.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description_kind":"plain","computed":true},"value":{"type":"string","description":"Value.","description_kind":"plain","required":true}},"description":"Create and manage a label (org-scoped).","description_kind":"plain"}},"autoglue_server":{"version":0,"block":{"attributes":{"created_at":{"type":"string","description_kind":"plain","computed":true},"hostname":{"type":"string","description":"Hostname.","description_kind":"plain","required":true},"id":{"type":"string","description":"Server ID (UUID).","description_kind":"plain","computed":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"private_ip_address":{"type":"string","description":"Private IP address (required).","description_kind":"plain","required":true},"public_ip_address":{"type":"string","description":"Public IP address (required when role = bastion).","description_kind":"plain","optional":true},"raw":{"type":"string","description":"Full server JSON from API.","description_kind":"plain","computed":true},"role":{"type":"string","description":"Server role (e.g., agent/manager/bastion). Lowercased by the provider.","description_kind":"plain","required":true},"ssh_key_id":{"type":"string","description":"SSH key ID (UUID) that belongs to the org.","description_kind":"plain","required":true},"ssh_user":{"type":"string","description":"SSH username (required).","description_kind":"plain","required":true},"status":{"type":"string","description":"Status (pending|provisioning|ready|failed). Lowercased by the provider.","description_kind":"plain","optional":true,"computed":true},"updated_at":{"type":"string","description_kind":"plain","computed":true}},"description":"Create and manage a server (org-scoped). Mirrors API validation for role/status/ssh_key_id.","description_kind":"plain"}},"autoglue_ssh_key":{"version":0,"block":{"attributes":{"bits":{"type":"number","description":"RSA key size (2048/3072/4096). Ignored for ed25519.","description_kind":"plain","optional":true},"comment":{"type":"string","description":"Comment appended to authorized key","description_kind":"plain","required":true},"created_at":{"type":"string","description":"Creation time (RFC3339, UTC)","description_kind":"plain","computed":true},"fingerprint":{"type":"string","description":"SHA256 fingerprint","description_kind":"plain","computed":true},"id":{"type":"string","description":"SSH key ID (UUID)","description_kind":"plain","computed":true},"name":{"type":"string","description":"Display name","description_kind":"plain","required":true},"private_key_pem":{"type":"string","description":"Private key PEM (resource doesn’t reveal; stays empty).","description_kind":"plain","computed":true,"sensitive":true},"public_key":{"type":"string","description":"OpenSSH authorized key","description_kind":"plain","computed":true},"type":{"type":"string","description":"Key type: rsa or ed25519 (default rsa)","description_kind":"plain","optional":true},"updated_at":{"type":"string","description":"Update time (RFC3339, UTC)","description_kind":"plain","computed":true}},"description_kind":"plain"}},"autoglue_taint":{"version":0,"block":{"attributes":{"created_at":{"type":"string","description_kind":"plain","computed":true},"effect":{"type":"string","description":"Effect.","description_kind":"plain","required":true},"id":{"type":"string","description":"Server ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description":"Key.","description_kind":"plain","required":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full server JSON from API.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description_kind":"plain","computed":true},"value":{"type":"string","description":"Value.","description_kind":"plain","required":true}},"description":"Create and manage a taint (org-scoped).","description_kind":"plain"}}},"data_source_schemas":{"autoglue_annotations":{"version":0,"block":{"attributes":{"items":{"nested_type":{"attributes":{"created_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"id":{"type":"string","description":"Taint ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description_kind":"plain","computed":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full JSON for the item.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"value":{"type":"string","description_kind":"plain","computed":true}},"nesting_mode":"list"},"description":"Annotations returned by the API.","description_kind":"plain","computed":true}},"description":"List annotations for the organization (org-scoped).","description_kind":"plain"}},"autoglue_labels":{"version":0,"block":{"attributes":{"items":{"nested_type":{"attributes":{"created_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"id":{"type":"string","description":"Taint ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description_kind":"plain","computed":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full JSON for the item.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"value":{"type":"string","description_kind":"plain","computed":true}},"nesting_mode":"list"},"description":"Labels returned by the API.","description_kind":"plain","computed":true}},"description":"List labels for the organization (org-scoped).","description_kind":"plain"}},"autoglue_servers":{"version":0,"block":{"attributes":{"items":{"nested_type":{"attributes":{"created_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"hostname":{"type":"string","description_kind":"plain","computed":true},"id":{"type":"string","description":"Server ID (UUID).","description_kind":"plain","computed":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"private_ip_address":{"type":"string","description_kind":"plain","computed":true},"public_ip_address":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full JSON for the item.","description_kind":"plain","computed":true},"role":{"type":"string","description_kind":"plain","computed":true},"ssh_key_id":{"type":"string","description_kind":"plain","computed":true},"ssh_user":{"type":"string","description_kind":"plain","computed":true},"status":{"type":"string","description_kind":"plain","computed":true},"updated_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true}},"nesting_mode":"list"},"description":"Servers returned by the API.","description_kind":"plain","computed":true},"role":{"type":"string","description":"Filter by role.","description_kind":"plain","optional":true},"status":{"type":"string","description":"Filter by status (pending|provisioning|ready|failed).","description_kind":"plain","optional":true}},"description":"List servers for the organization (org-scoped).","description_kind":"plain"}},"autoglue_ssh_keys":{"version":0,"block":{"attributes":{"fingerprint":{"type":"string","description":"Filter by exact fingerprint (client-side).","description_kind":"plain","optional":true},"keys":{"nested_type":{"attributes":{"created_at":{"type":"string","description_kind":"plain","computed":true},"fingerprint":{"type":"string","description_kind":"plain","computed":true},"id":{"type":"string","description_kind":"plain","computed":true},"name":{"type":"string","description_kind":"plain","computed":true},"public_key":{"type":"string","description_kind":"plain","computed":true},"updated_at":{"type":"string","description_kind":"plain","computed":true}},"nesting_mode":"list"},"description":"SSH keys","description_kind":"plain","computed":true},"name_contains":{"type":"string","description":"Filter by substring of name (client-side).","description_kind":"plain","optional":true}},"description_kind":"plain"}},"autoglue_taints":{"version":0,"block":{"attributes":{"items":{"nested_type":{"attributes":{"created_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"effect":{"type":"string","description_kind":"plain","computed":true},"id":{"type":"string","description":"Taint ID (UUID).","description_kind":"plain","computed":true},"key":{"type":"string","description_kind":"plain","computed":true},"organization_id":{"type":"string","description_kind":"plain","computed":true},"raw":{"type":"string","description":"Full JSON for the item.","description_kind":"plain","computed":true},"updated_at":{"type":"string","description":"RFC3339, UTC.","description_kind":"plain","computed":true},"value":{"type":"string","description_kind":"plain","computed":true}},"nesting_mode":"list"},"description":"Taints returned by the API.","description_kind":"plain","computed":true}},"description":"List taints for the organization (org-scoped).","description_kind":"plain"}}}},"registry.opentofu.org/hashicorp/http":{"provider":{"version":0,"block":{"description_kind":"plain"}},"data_source_schemas":{"http":{"version":0,"block":{"attributes":{"body":{"type":"string","description":"The response body returned as a string. **NOTE**: This is deprecated, use `response_body` instead.","description_kind":"plain","deprecated":true,"computed":true},"ca_cert_pem":{"type":"string","description":"Certificate Authority (CA) in [PEM (RFC 1421)](https://datatracker.ietf.org/doc/html/rfc1421) format.","description_kind":"plain","optional":true},"client_cert_pem":{"type":"string","description":"Client certificate in [PEM (RFC 1421)](https://datatracker.ietf.org/doc/html/rfc1421) format.","description_kind":"plain","optional":true},"client_key_pem":{"type":"string","description":"Client key in [PEM (RFC 1421)](https://datatracker.ietf.org/doc/html/rfc1421) format.","description_kind":"plain","optional":true},"id":{"type":"string","description":"The URL used for the request.","description_kind":"plain","computed":true},"insecure":{"type":"bool","description":"Disables verification of the server's certificate chain and hostname. Defaults to `false`","description_kind":"plain","optional":true},"method":{"type":"string","description":"The HTTP Method for the request. Allowed methods are a subset of methods defined in [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231#section-4.3) namely, `GET`, `HEAD`, and `POST`. `POST` support is only intended for read-only URLs, such as submitting a search.","description_kind":"plain","optional":true},"request_body":{"type":"string","description":"The request body as a string.","description_kind":"plain","optional":true},"request_headers":{"type":["map","string"],"description":"A map of request header field names and values.","description_kind":"plain","optional":true},"request_timeout_ms":{"type":"number","description":"The request timeout in milliseconds.","description_kind":"plain","optional":true},"response_body":{"type":"string","description":"The response body returned as a string.","description_kind":"plain","computed":true},"response_body_base64":{"type":"string","description":"The response body encoded as base64 (standard) as defined in [RFC 4648](https://datatracker.ietf.org/doc/html/rfc4648#section-4).","description_kind":"plain","computed":true},"response_headers":{"type":["map","string"],"description":"A map of response header field names and values. Duplicate headers are concatenated according to [RFC2616](https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2).","description_kind":"plain","computed":true},"status_code":{"type":"number","description":"The HTTP response status code.","description_kind":"plain","computed":true},"url":{"type":"string","description":"The URL for the request. Supported schemes are `http` and `https`.","description_kind":"plain","required":true}},"block_types":{"retry":{"nesting_mode":"single","block":{"attributes":{"attempts":{"type":"number","description":"The number of times the request is to be retried. For example, if 2 is specified, the request will be tried a maximum of 3 times.","description_kind":"plain","optional":true},"max_delay_ms":{"type":"number","description":"The maximum delay between retry requests in milliseconds.","description_kind":"plain","optional":true},"min_delay_ms":{"type":"number","description":"The minimum delay between retry requests in milliseconds.","description_kind":"plain","optional":true}},"description":"Retry request configuration. By default there are no retries. Configuring this block will result in retries if an error is returned by the client (e.g., connection errors) or if a 5xx-range (except 501) status code is received. For further details see [go-retryablehttp](https://pkg.go.dev/github.com/hashicorp/go-retryablehttp).","description_kind":"plain"}}},"description":"\nThe `http` data source makes an HTTP GET request to the given URL and exports\ninformation about the response.\n\nThe given URL may be either an `http` or `https` URL. This resource\nwill issue a warning if the result is not UTF-8 encoded.\n\n~\u003e **Important** Although `https` URLs can be used, there is currently no\nmechanism to authenticate the remote server except for general verification of\nthe server certificate's chain of trust. Data retrieved from servers not under\nyour control should be treated as untrustworthy.\n\nBy default, there are no retries. Configuring the retry block will result in\nretries if an error is returned by the client (e.g., connection errors) or if \na 5xx-range (except 501) status code is received. For further details see \n[go-retryablehttp](https://pkg.go.dev/github.com/hashicorp/go-retryablehttp).\n","description_kind":"plain"}}}},"registry.opentofu.org/hashicorp/local":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"local_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Content to store in the file, expected to be a UTF-8 encoded string.\n Conflicts with `sensitive_content`, `content_base64` and `source`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true},"content_base64":{"type":"string","description":"Content to store in the file, expected to be binary encoded as base64 string.\n Conflicts with `content`, `sensitive_content` and `source`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"directory_permission":{"type":"string","description":"Permissions to set for directories created (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0777\"`.","description_kind":"plain","optional":true,"computed":true},"file_permission":{"type":"string","description":"Permissions to set for the output file (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0777\"`.","description_kind":"plain","optional":true,"computed":true},"filename":{"type":"string","description":"The path to the file that will be created.\n Missing parent directories will be created.\n If the file already exists, it will be overridden with the given content.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true},"sensitive_content":{"type":"string","description":"Sensitive content to store in the file, expected to be an UTF-8 encoded string.\n Will not be displayed in diffs.\n Conflicts with `content`, `content_base64` and `source`.\n Exactly one of these four arguments must be specified.\n If in need to use _sensitive_ content, please use the [`local_sensitive_file`](./sensitive_file.html)\n resource instead.","description_kind":"plain","deprecated":true,"optional":true,"sensitive":true},"source":{"type":"string","description":"Path to file to use as source for the one we are creating.\n Conflicts with `content`, `sensitive_content` and `content_base64`.\n Exactly one of these four arguments must be specified.","description_kind":"plain","optional":true}},"description":"Generates a local file with the given content.","description_kind":"plain"}},"local_sensitive_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Sensitive Content to store in the file, expected to be a UTF-8 encoded string.\n Conflicts with `content_base64` and `source`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true,"sensitive":true},"content_base64":{"type":"string","description":"Sensitive Content to store in the file, expected to be binary encoded as base64 string.\n Conflicts with `content` and `source`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true,"sensitive":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"directory_permission":{"type":"string","description":"Permissions to set for directories created (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0700\"`.","description_kind":"plain","optional":true,"computed":true},"file_permission":{"type":"string","description":"Permissions to set for the output file (before umask), expressed as string in\n [numeric notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation).\n Default value is `\"0700\"`.","description_kind":"plain","optional":true,"computed":true},"filename":{"type":"string","description":"The path to the file that will be created.\n Missing parent directories will be created.\n If the file already exists, it will be overridden with the given content.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true},"source":{"type":"string","description":"Path to file to use as source for the one we are creating.\n Conflicts with `content` and `content_base64`.\n Exactly one of these three arguments must be specified.","description_kind":"plain","optional":true}},"description":"Generates a local file with the given sensitive content.","description_kind":"plain"}}},"data_source_schemas":{"local_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Raw content of the file that was read, as UTF-8 encoded string. Files that do not contain UTF-8 text will have invalid UTF-8 sequences in `content`\n replaced with the Unicode replacement character. ","description_kind":"plain","computed":true},"content_base64":{"type":"string","description":"Base64 encoded version of the file content (use this when dealing with binary data).","description_kind":"plain","computed":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"filename":{"type":"string","description":"Path to the file that will be read. The data source will return an error if the file does not exist.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true}},"description":"Reads a file from the local filesystem.","description_kind":"plain"}},"local_sensitive_file":{"version":0,"block":{"attributes":{"content":{"type":"string","description":"Raw content of the file that was read, as UTF-8 encoded string. Files that do not contain UTF-8 text will have invalid UTF-8 sequences in `content`\n replaced with the Unicode replacement character.","description_kind":"plain","computed":true,"sensitive":true},"content_base64":{"type":"string","description":"Base64 encoded version of the file content (use this when dealing with binary data).","description_kind":"plain","computed":true,"sensitive":true},"content_base64sha256":{"type":"string","description":"Base64 encoded SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_base64sha512":{"type":"string","description":"Base64 encoded SHA512 checksum of file content.","description_kind":"plain","computed":true},"content_md5":{"type":"string","description":"MD5 checksum of file content.","description_kind":"plain","computed":true},"content_sha1":{"type":"string","description":"SHA1 checksum of file content.","description_kind":"plain","computed":true},"content_sha256":{"type":"string","description":"SHA256 checksum of file content.","description_kind":"plain","computed":true},"content_sha512":{"type":"string","description":"SHA512 checksum of file content.","description_kind":"plain","computed":true},"filename":{"type":"string","description":"Path to the file that will be read. The data source will return an error if the file does not exist.","description_kind":"plain","required":true},"id":{"type":"string","description":"The hexadecimal encoding of the SHA1 checksum of the file content.","description_kind":"plain","computed":true}},"description":"Reads a file that contains sensitive data, from the local filesystem.","description_kind":"plain"}}},"functions":{"direxists":{"description":"Given a path string, will return true if the directory exists. This function works only with directories. If used with a file, the function will return an error.\n\nThis function behaves similar to the built-in [`fileexists`](https://developer.hashicorp.com/terraform/language/functions/fileexists) function, however, `direxists` will not replace filesystem paths including `~` with the current user's home directory path. This functionality can be achieved by using the built-in [`pathexpand`](https://developer.hashicorp.com/terraform/language/functions/pathexpand) function with `direxists`, see example below.","summary":"Determines whether a directory exists at a given path.","return_type":"bool","parameters":[{"name":"path","description":"Relative or absolute path to check for the existence of a directory","type":"string"}]}}},"registry.opentofu.org/hashicorp/null":{"provider":{"version":0,"block":{"description_kind":"plain"}},"resource_schemas":{"null_resource":{"version":0,"block":{"attributes":{"id":{"type":"string","description":"This is set to a random value at create time.","description_kind":"plain","computed":true},"triggers":{"type":["map","string"],"description":"A map of arbitrary strings that, when changed, will force the null resource to be replaced, re-running any associated provisioners.","description_kind":"plain","optional":true}},"description":"The `null_resource` resource implements the standard resource lifecycle but takes no further action. On Terraform 1.4 and later, use the [`terraform_data` resource type](https://developer.hashicorp.com/terraform/language/resources/terraform-data) instead. Terraform 1.9 and later support the `moved` configuration block from `null_resource` to `terraform_data`.\n\nThe `triggers` argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.","description_kind":"plain"}}},"data_source_schemas":{"null_data_source":{"version":0,"block":{"attributes":{"has_computed_default":{"type":"string","description":"If set, its literal value will be stored and returned. If not, its value defaults to `\"default\"`. This argument exists primarily for testing and has little practical use.","description_kind":"plain","optional":true,"computed":true},"id":{"type":"string","description":"This attribute is only present for some legacy compatibility issues and should not be used. It will be removed in a future version.","description_kind":"plain","deprecated":true,"computed":true},"inputs":{"type":["map","string"],"description":"A map of arbitrary strings that is copied into the `outputs` attribute, and accessible directly for interpolation.","description_kind":"plain","optional":true},"outputs":{"type":["map","string"],"description":"After the data source is \"read\", a copy of the `inputs` map.","description_kind":"plain","computed":true},"random":{"type":"string","description":"A random value. This is primarily for testing and has little practical use; prefer the [hashicorp/random provider](https://registry.terraform.io/providers/hashicorp/random) for more practical random number use-cases.","description_kind":"plain","computed":true}},"description":"The `null_data_source` data source implements the standard data source lifecycle but does not\ninteract with any external APIs.\n\nHistorically, the `null_data_source` was typically used to construct intermediate values to re-use elsewhere in configuration. The\nsame can now be achieved using [locals](https://developer.hashicorp.com/terraform/language/values/locals) or the [terraform_data resource type](https://developer.hashicorp.com/terraform/language/resources/terraform-data) in Terraform 1.4 and later.","description_kind":"plain","deprecated":true}}}}}} diff --git a/terraform/envs/dev/scripts/gen_md.py b/terraform/envs/dev/scripts/gen_md.py new file mode 100644 index 0000000..b5bc9a7 --- /dev/null +++ b/terraform/envs/dev/scripts/gen_md.py @@ -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()