diff --git a/docs/data-sources/blueprint.md b/docs/data-sources/blueprint.md index d91ee12..5183581 100644 --- a/docs/data-sources/blueprint.md +++ b/docs/data-sources/blueprint.md @@ -1,16 +1,27 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_blueprint Data Source - terraform-provider-resourcely" subcategory: "" -description: |- - A resourcely blueprint --- # resourcely_blueprint (Data Source) -A resourcely blueprint +A blueprint is a configuration template used to provision cloud infrastructure resources. Blueprints allow you to: +- Define which options are available for properties of your resource(s). +- Apply gaurdrails to your resource(s) to prevent misconfiguration. +- Define what information to collect from your developers before provisioning the resource. +Once a blueprint is configured and published, it becomes available for use in your Resourcely service catalog. + +The template is specified using Resourcely's TFT templating language. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details about TFT. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the template. + +## Example Usage + +```terraform +data "resourcely_blueprint" "example" { + series_id = "00000000-00000000-00000000-00000000" +} +``` ## Schema @@ -19,20 +30,17 @@ A resourcely blueprint - `series_id` (String) UUID for the blueprint -### Optional - -- `is_published` (Boolean) A published blueprint is available for use by developers to create resources through the Resourcely portal. - ### Read-Only -- `categories` (Set of String) -- `cloud_provider` (String) -- `content` (String) -- `description` (String) -- `excluded_context_question_series` (Set of String) series_id for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories -- `guidance` (String) -- `id` (String) UUID for this version. -- `labels` (Set of String) -- `name` (String) +- `categories` (Set of String) The category to assign to this blueprint. +- `cloud_provider` (String) The cloud provider that this blueprint targets. +- `content` (String) The templated Terraform configuration specified using Resourcely's TFT format. +- `description` (String) A description of the blueprints's purpose or functionality. +- `excluded_context_question_series` (Set of String) The series_ids for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories +- `guidance` (String) Guidance to help your users know when and how to use this blueprint. +- `id` (String) UUID for the current version of the blueprint. +- `is_published` (Boolean) A published blueprint is available for use by developers to create resources through the Resourcely portal. +- `labels` (Set of String) Additional keywords to help your users discover this blueprint. +- `name` (String) The name of the blueprint. - `scope` (String) -- `version` (Number) Specific version of the blueprint +- `version` (Number) Increment version number for the current version of the blueprint. diff --git a/docs/data-sources/context_question.md b/docs/data-sources/context_question.md index 729d7bb..8c158c9 100644 --- a/docs/data-sources/context_question.md +++ b/docs/data-sources/context_question.md @@ -1,42 +1,57 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_context_question Data Source - terraform-provider-resourcely" subcategory: "" -description: |- - A resourcely ContextQuestion --- # resourcely_context_question (Data Source) -A resourcely ContextQuestion +A [context question](https://docs.resourcely.io/concepts/other-features-and-settings/global-context-and-values) is used to gather data from developers before provisioning a resource. They are designed to gather and store insightful data related to the resource. +Some examples include: +- What type of data will be stored in this infrastructure? +- What application is this infrastructure associated with? +- What is the email address the person/team responsible for this infrastructure? + +Three types of context questions are supported: + +- Text +- Single Choice +- Multiple Choice + +## Example Usage + +```terraform +data "resourcely_context_question" "example" { + series_id = "00000000-00000000-00000000-00000000" +} +``` ## Schema ### Required -- `series_id` (String) UUID for the global context +- `series_id` (String) UUID for the context question. ### Read-Only -- `answer_choices` (Attributes Set) (see [below for nested schema](#nestedatt--answer_choices)) -- `answer_format` (String) -- `blueprint_categories` (Set of String) Resource categories the context question applies to -- `excluded_blueprint_series` (Set of String) series_id for Blueprints exempt from this context question even though those blueprints belong to the context question's blueprint_categories -- `id` (String) UUID for this version. -- `label` (String) -- `priority` (Number) Priority of this question, relative to others. 0=high, 1=medium, 2=low -- `prompt` (String) -- `qtype` (String) -- `regex_pattern` (String) Regex validation for the acceptable answers to the context question +- `answer_choices` (Attributes Set) The answer choices from which the developer can select. Applicable only when `qtype` is `QTYPE_SINGLE_SELECT` or `QTYPE_MULTI_SELECT`. (see [below for nested schema](#nestedatt--answer_choices)) +- `answer_format` (String) A format validation for acceptable answers to the context question. Applicable only when `qtype` is `QTYPE_TEXT` . Will be one of `ANSWER_TEXT`, `ANSWER_NUMBER`, `ANSWER_EMAIL`, or `ANSWER_REGEX`. If `ANSWER_REGEX`, the `regex_pattern` property will also be set. +- `blueprint_categories` (Set of String) The blueprint categories to which this context question applies. This question will be asked whenever a developer uses a blueprint in these categories. +- `excluded_blueprint_series` (Set of String) The series_ids of blueprints for which this question should not be asked, even if those blueprints belong to the context question's blueprint_categories. +- `id` (String) UUID for the current version of this context question. +- `label` (String) A key used to reference the context question in blueprints and guardrails. Is unique within your Resourcley tenant. +- `priority` (Number) The priority of this question, relative to others. 0=high, 1=medium, 2=low +- `prompt` (String) The question that Resourcely will ask your developers. +- `qtype` (String) The type of the question. Will be one of `QYTPE_TEXT`, `QYTPE_SINGLE_SELECT`, or `QTYPE_MULTI_SELECT`. +- `regex_pattern` (String) A regex validation for the acceptable answers to the context question. Applicable only when both `qtype` is `QTYPE_TEXT` and `answer_format` is `ANSWER_REGEX`. - `scope` (String) -- `version` (Number) Specific version of the global context +- `version` (Number) Incrementing version number of the context question. ### Nested Schema for `answer_choices` Read-Only: -- `label` (String) +- `label` (String) The value for the answer choice. diff --git a/docs/data-sources/global_value.md b/docs/data-sources/global_value.md index 5742aba..c0a75d6 100644 --- a/docs/data-sources/global_value.md +++ b/docs/data-sources/global_value.md @@ -1,49 +1,46 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_global_value Data Source - terraform-provider-resourcely" subcategory: "" -description: |- - A Resourcely global value --- # resourcely_global_value (Data Source) -A Resourcely global value +A [global value](https://docs.resourcely.io/concepts/other-features-and-settings/global-values) allows admins to define custom drop-downs for customizing Terraform infrastructure resource properties before they are provisioned. They are useful for providing access to lists of relatively static values like VPC IDs, allowed regions, department or team names, etc. +## Example Usage +```terraform +data "resourcely_global_value" "example" { + series_id = "00000000-00000000-00000000-00000000" +} +``` ## Schema ### Required -- `series_id` (String) UUID for the global value +- `series_id` (String) UUID for the global value. ### Read-Only -- `description` (String) A longer description -- `id` (String) UUID for this version. -- `is_deprecated` (Boolean) True if the global value should not be used in new blueprints or guardrails +- `description` (String) A description of the purpose of the global value. +- `id` (String) UUID for the current version of the global value. +- `is_deprecated` (Boolean) Set to true if the global value should not be used in new blueprints or guardrails - `key` (String) An immutable identifier used to reference this global value in blueprints or guardrails. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. -- `name` (String) A short display name -- `options` (Attributes List) The list of value options for this global value (see [below for nested schema](#nestedatt--options)) -- `type` (String) The type of options in the global value. Can be one of `PRESET_VALUE_TEXT`, `PRESET_VALUE_NUMBER`, `PRESET_VALUE_LIST`, `PRESET_VALUE_OBJECT` -- `version` (Number) Specific version of the global value +- `name` (String) The name of the global value. +- `options` (Attributes List) The list of value options for this global value. (see [below for nested schema](#nestedatt--options)) +- `type` (String) The type of options in the global value. Will be one of `PRESET_VALUE_TEXT`, `PRESET_VALUE_NUMBER`, `PRESET_VALUE_LIST`, `PRESET_VALUE_OBJECT` +- `version` (Number) Incrementing version number for the current version of the global value. ### Nested Schema for `options` Read-Only: -- `description` (String) A longer description -- `key` (String) An immutable identifier for ths option. - -Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. -- `label` (String) A unique short display name -- `value` (String) A JSON encoding of the option's value. This value must match the declared type of the global value. - -Example: `value = jsonencode("a")` - -Example: `value = jsonencode(["a", "b"])` +- `description` (String) A description of this option's meaning. +- `key` (String) An immutable identifier for ths option. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. +- `label` (String) A unique display name +- `value` (String) A JSON encoding of the option's value.` diff --git a/docs/data-sources/guardrail.md b/docs/data-sources/guardrail.md index 96d9e95..1119139 100644 --- a/docs/data-sources/guardrail.md +++ b/docs/data-sources/guardrail.md @@ -1,36 +1,42 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_guardrail Data Source - terraform-provider-resourcely" subcategory: "" -description: |- - A resourcely guardrail --- # resourcely_guardrail (Data Source) -A resourcely guardrail +A guardrail governs how cloud resources can be created and altered, preventing infrastructure misconfiguration. Before infrastructure is provisioned, Resourcely examines the changes being made and prevents a merge if any guardrail requirements are violated. Some examples of guardrails include: +- Require approval for making a public S3 bucket +- Restrict the allowed compute instance types or images +Guardrails are specified using the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). + +## Example Usage + +```terraform +data "resourcely_guardrail" "example" { + series_id = "00000000-00000000-00000000-00000000" +} +``` ## Schema ### Required -- `series_id` (String) UUID for the guardrail +- `series_id` (String) UUID for the guardrail. ### Read-Only -- `category` (String) -- `cloud_provider` (String) -- `content` (String) -- `description` (String) -- `guardrail_template_inputs` (String) A JSON encoding of values for the guardrail template inputs. - -Example: `guardrail_template_inputs = jsonencode({inputOne = "value one"})` -- `guardrail_template_series_id` (String) The series id of the guardrail template used to render the policies -- `id` (String) UUID for this version. -- `name` (String) +- `category` (String) The category of this guardrail. +- `cloud_provider` (String) The cloud provider that this guardrail targets. +- `content` (String) The guardrail policy written in the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). +- `description` (String) A description of the guardrail's purpose or policy. +- `guardrail_template_inputs` (String) A JSON encoding of values for the guardrail template inputs.` +- `guardrail_template_series_id` (String) The series id of the guardrail template used to render the policy. +- `id` (String) UUID for the current version of this guar. +- `name` (String) The name of the guardrail. - `scope` (String) -- `state` (String) -- `version` (Number) Specific version of the guardrail +- `state` (String) The [state](https://docs.resourcely.io/build/setting-up-guardrails/releasing-guardrails#guardrail-status) of the guardrail. +- `version` (Number) Incrementing version number for this current version of the guardrail. diff --git a/docs/index.md b/docs/index.md index 80d2434..c45b9af 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,25 +1,124 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs -page_title: "resourcely Provider" -subcategory: "" -description: |- - Configure Resourcely resources +page_title: "Provider: resourcely" --- -# resourcely Provider +# RESOURCELY Provider -Configure Resourcely resources +The Resourcely provider is used to manage Resourcely blueprint, +guardrails, global values, and more through Terraform. The provider +needs to be configured with the proper credentials before it can be +used. ## Example Usage +Configure the Resourcely provider. + ```terraform +# Pin the source and version of the provider terraform { required_providers { resourcely = { - source = "Resourcely-Inc/resourcely" + source = "Resourcely-Inc/resourcely" + version = "~> 1.0" } } } + +# No provider configuration is required. See `Authentication and +# Configuration` below to learn how to provide your Resourcley API +# credentials. +provider "resourcely" { +} +``` + +Create a guardrail. + +```terraform +resource "resourcely_guardrail" "s3_bucket_naming_convention" { + name = "S3 Bucket Naming Convention" + description = "Ensures that all S3 Buckets comply with our standardized naming convention, promoting consistency and ease of identification across our AWS environments." + + cloud_provider = "PROVIDER_AMAZON" + category = "GUARDRAIL_BEST_PRACTICES" + + content = <<-EOT + GUARDRAIL "S3 Bucket Naming Convention" + WHEN aws_s3_bucket + REQUIRE bucket STARTS WITH "mycompany-" + EOT +} +``` + +Create a blueprint. + +```terraform +resource "resourcely_blueprint" "private_s3_bucket" { + name = "Private S3 Bucket" + description = "Creates a private, S3 bucket with configuration versioning." + + cloud_provider = "PROVIDER_AMAZON" + categories = ["BLUEPRINT_BLOB_STORAGE"] + + is_published = true + + content = <<-EOT + --- + constants: + __name: "{{ bucket }}_{{ __guid }}" + --- + resource "aws_s3_" "{{ __name }}" { + bucket = {{ bucket }} + } + + resource "aws_s3_bucket_public_access_block" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true + } + + resource "aws_s3_bucket_ownership_controls" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + rule { + object_ownership = "BucketOwnerEnforced" + } + } + EOT +} +``` + +## Authentication and Configuration + +The provider requires a Resourcely API token to authenticate. It +expects the token to be provided through the `RESOURCELY_AUTH_TOKEN` +environment variable. Configure your Terraform runner to supply this +variable. + +You can generate the token from the [Resourcely Settings +page](https://portal.resourcely.io/settings/generate-api-token). Choose +the "Terraform Provider" role. + +You can also supply the token directly in the provider block. Ensure +that token is securely stored in a secret management system. Do not +hardcode it in the provider block. + +```terraform +provider "resourcely" { + auth_token = var.resourcely_auth_token +} +``` + +If your organization uses multiple tenants within Resourcely, you can +configure the `allowed_tenants` in the provider block to prevent +accidently mixing API keys between tenants. + +```terraform +provider "resourcely" { + allowed_tenants = ["MyCompany"] +} ``` @@ -29,4 +128,4 @@ terraform { - `allowed_tenants` (List of String) List of allowed tenant names (case-insensitive) to prevent accidently applying a configuration to the wrong one. - `auth_token` (String, Sensitive) Authorization token for Resourcely API. -- `host` (String) URI for Resourcely API. +- `host` (String) URI for Resourcely API. Defaults to 'https://api.resourcely.io'. diff --git a/docs/resources/blueprint.md b/docs/resources/blueprint.md index be3e2e6..09abe22 100644 --- a/docs/resources/blueprint.md +++ b/docs/resources/blueprint.md @@ -1,16 +1,60 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_blueprint Resource - terraform-provider-resourcely" subcategory: "" -description: |- - A Resourcely Blueprint --- # resourcely_blueprint (Resource) -A Resourcely Blueprint +A blueprint is a configuration template used to provision cloud infrastructure resources. Blueprints allow you to: +- Define which options are available for properties of your resource(s). +- Apply gaurdrails to your resource(s) to prevent misconfiguration. +- Define what information to collect from your developers before provisioning the resource. +Once a blueprint is configured and published, it becomes available for use in your Resourcely service catalog. + +The template is specified using Resourcely's TFT templating language. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details about TFT. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the template. + +## Example Usage + +```terraform +resource "resourcely_blueprint" "private_s3_bucket" { + name = "Private S3 Bucket" + description = "Creates a private, S3 bucket with configuration versioning." + + cloud_provider = "PROVIDER_AMAZON" + categories = ["BLUEPRINT_BLOB_STORAGE"] + + is_published = true + + content = <<-EOT + --- + constants: + __name: "{{ bucket }}_{{ __guid }}" + --- + resource "aws_s3_" "{{ __name }}" { + bucket = {{ bucket }} + } + + resource "aws_s3_bucket_public_access_block" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true + } + + resource "aws_s3_bucket_ownership_controls" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + rule { + object_ownership = "BucketOwnerEnforced" + } + } + EOT +} +``` ## Schema @@ -18,23 +62,29 @@ A Resourcely Blueprint ### Required - `cloud_provider` (String) The cloud provider that this blueprint targets. Can be one of `PROVIDER_AMAZON`, `PROVIDER_AZURE`, `PROVIDER_CONDUCTORONE`, `PROVIDER_DATABRICKS`, `PROVIDER_DATADOG`, `PROVIDER_GITHUB`, `PROVIDER_GITLAB`, `PROVIDER_GOOGLE`, `PROVIDER_HYPERV`, `PROVIDER_IBM`, `PROVIDER_JUMPCLOUD`, `PROVIDER_KUBERNETES`, `PROVIDER_OKTA`, `PROVIDER_ORACLE`, `PROVIDER_RESOURCELY`, `PROVIDER_SNOWFLAKE`, `PROVIDER_SPACELIFT`, `PROVIDER_VMWARE`, `PROVIDER_OTHER` -- `content` (String) -- `name` (String) +- `content` (String) The templated Terraform configuration specified using Resourcely's TFT format. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the content. +- `name` (String) The name of the blueprint. ### Optional - `categories` (Set of String) The category to assign to this blueprint. Can be one of `BLUEPRINT_ASYNC_PROCESSING`, `BLUEPRINT_BLOB_STORAGE`, `BLUEPRINT_COMPUTE`, `BLUEPRINT_CONTAINERIZATION`, `BLUEPRINT_DATABASE`, `BLUEPRINT_GITHUB_REPO`, `BLUEPRINT_GITHUB_REPO_TEAM`, `BLUEPRINT_IAM`, `BLUEPRINT_LOGS_AND_METRICS`, `BLUEPRINT_NETWORKING`, `BLUEPRINT_SERVERLESS_COMPUTE` -- `description` (String) -- `excluded_context_question_series` (Set of String) series_id for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories -- `guidance` (String) -- `is_published` (Boolean) A published blueprint is available for use by developers to create resources through the Resourcely portal. - -If left unset, the blueprint will start as unpublished, and you may safely change this property in the Resourcely portal. -- `labels` (Set of String) +- `description` (String) A description of the blueprint's purpose or functionality. +- `excluded_context_question_series` (Set of String) The series_ids for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories +- `guidance` (String) Guidance to help your users know when and how to use this blueprint. +- `is_published` (Boolean) A published blueprint is available for use by developers to create resources through the Resourcely portal. If left unset, the blueprint will start as unpublished, and you may safely change this property in the Resourcely portal. +- `labels` (Set of String) Additional keywords to help your users discover this blueprint. - `scope` (String) ### Read-Only -- `id` (String) UUID for this version. -- `series_id` (String) UUID for the blueprint -- `version` (Number) Specific version of the blueprint +- `id` (String) UUID for the current version of the blueprint. +- `series_id` (String) UUID for the blueprint. +- `version` (Number) Incrementing version number for the current version of the blueprint. + +## Import + +A blueprint can be imported using its series_id. + +```shell +terraform import resourcely_blueprint.example 00000000-00000000-00000000-00000000 +``` diff --git a/docs/resources/context_question.md b/docs/resources/context_question.md index c9c7fc3..f9298b6 100644 --- a/docs/resources/context_question.md +++ b/docs/resources/context_question.md @@ -1,45 +1,127 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_context_question Resource - terraform-provider-resourcely" subcategory: "" -description: |- - A Resourcely Context Question --- # resourcely_context_question (Resource) -A Resourcely Context Question +A [context question](https://docs.resourcely.io/concepts/other-features-and-settings/global-context-and-values) is used to gather data from developers before provisioning a resource. They are designed to gather and store insightful data related to the resource. +Some examples include: +- What type of data will be stored in this infrastructure? +- What application is this infrastructure associated with? +- What is the email address the person/team responsible for this infrastructure? + +Three types of context questions are supported: + +- Text +- Single Choice +- Multiple Choice + +## Example Usage + +Create a simple, multi-select context question. + +```terraform +resource "resourcely_context_question" "data_classification" { + label = "classification" + prompt = "What kind of data is stored by this infrastructure?" + + qtype = "QTYPE_MULTI_SELECT" + answer_choices = [ + { label = "financial" }, + { label = "pii" }, + { label = "proprietary" }, + { label = "public" }, + ] + + blueprint_categories = ["BLUEPRINT_BLOB_STORAGE", "BLUEPRINT_DATABASE"] + + priority = 1 +} +``` + + +Context questions with "text" type can restrict the allowed answer formats. For example, create a context question that asks for an email address. + +```terraform +resource "resourcely_context_question" "owner" { + label = "owner" + prompt = "What is the email address of the team or person responsible for this infrastructure?" + + qtype = "QTYPE_TEXT" + answer_format = "ANSWER_EMAIL" + + blueprint_categories = [ + "BLUEPRINT_COMPUTE", + "BLUEPRINT_DATABASE", + "BLUEPRINT_NETWORKING", + "BLUEPRINT_SERVERLESS_COMPUTE" + ] + + priority = 0 +} +``` + +Or, create a context question that asks for a project code comprising 6 hex digits. + +```terraform +resource "resourcely_context_question" "project_code" { + label = "project_code" + prompt = "What is the project code that this infrastructure should be associated with?" + + qtype = "QTYPE_TEXT" + answer_format = "ANSWER_REGEX" + regex_pattern = "^[A-Z0-9]{6}$" + + blueprint_categories = [ + "BLUEPRINT_COMPUTE", + "BLUEPRINT_DATABASE", + "BLUEPRINT_NETWORKING", + "BLUEPRINT_SERVERLESS_COMPUTE" + ] + + priority = 2 +} +``` ## Schema ### Required -- `label` (String) -- `prompt` (String) -- `qtype` (String) +- `label` (String) A key used to reference the context question in blueprints and guardrails. Must be unique within your Resourcley tenant. +- `prompt` (String) The question that Resourcely with ask your developers. +- `qtype` (String) The type of the question. Must be one of `QTYPE_TEXT`, `QTYPE_SINGLE_SELECT`, or `QTYPE_MULTI_SELECT` - `scope` (String) ### Optional -- `answer_choices` (Attributes Set) (see [below for nested schema](#nestedatt--answer_choices)) -- `answer_format` (String) -- `blueprint_categories` (Set of String) -- `excluded_blueprint_series` (Set of String) series_id for Blueprints exempt from this context question even though those blueprints belong to the context question's blueprint_categories -- `priority` (Number) Priority of this question, relative to others. 0=high, 1=medium, 2=low -- `regex_pattern` (String) Regex validation for the acceptable answers to the context question +- `answer_choices` (Attributes Set) The answer choices from which the developer can select. Applicable only when `qtype` is `QTYPE_SINGLE_SELECT` or `QTYPE_MULTI_SELECT`. (see [below for nested schema](#nestedatt--answer_choices)) +- `answer_format` (String) A format validation for acceptable answers to the context question. Applicable only when `qtype` is `QTYPE_TEXT` . Must be one of `ANSWER_TEXT`, `ANSWER_NUMBER`, `ANSWER_EMAIL`, or `ANSWER_REGEX`. If `ANSWER_REGEX`, must also specify the `regex_pattern` property. +- `blueprint_categories` (Set of String) The blueprint categories to which this context question applies. This question will be asked whenever a developer uses a blueprint in these categories. +- `excluded_blueprint_series` (Set of String) The series_ids of blueprints for which this question should not be asked, even if those blueprints belong to the context question's blueprint_categories. +- `priority` (Number) The priority of this question, relative to others. 0=high, 1=medium, 2=low +- `regex_pattern` (String) A regex validation for the acceptable answers to the context question. Applicable only when both `qtype` is `QTYPE_TEXT` and `answer_format` is `ANSWER_REGEX`. ### Read-Only -- `id` (String) UUID for this version. -- `series_id` (String) UUID for the Context Question -- `version` (Number) Specific version of the Global Context +- `id` (String) UUID for the current version of the context question. +- `series_id` (String) UUID for the context question. +- `version` (Number) Incrementing version number for the current version of this context question. ### Nested Schema for `answer_choices` Required: -- `label` (String) +- `label` (String) The value for the answer choice. + +## Import + +A blueprint can be imported using its series_id. + +```shell +terraform import resourcely_context_question.example 00000000-00000000-00000000-00000000 +``` diff --git a/docs/resources/global_value.md b/docs/resources/global_value.md index e59e365..3b2d2c2 100644 --- a/docs/resources/global_value.md +++ b/docs/resources/global_value.md @@ -1,55 +1,177 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_global_value Resource - terraform-provider-resourcely" subcategory: "" -description: |- - A Resourcely GlobalValue --- # resourcely_global_value (Resource) -A Resourcely GlobalValue - - +A [global value](https://docs.resourcely.io/concepts/other-features-and-settings/global-values) allows admins to define custom drop-downs for customizing Terraform infrastructure resource properties before they are provisioned. They are useful for providing access to lists of relatively static values like VPC IDs, allowed regions, department or team names, etc. + +This global value API does not support deletion. Deleting the Terraform resource will remove the resource from the Terraform state file, but will not actually delete the global value entity. Set `is_deprecated = true` to tell Resourcely that this global value should no longer be used by new blueprints or guardrails. + +## Example Usage + +Create a global value containing all the departments within the company. + +```terraform +resource "resourcely_global_value" "departments" { + name = "Departments" + key = "departments" + description = "All departments within MyCompany" + + type = "PRESET_VALUE_TEXT" + options = [ + { + key = "product", + label = "Product", + value = "product", + }, + { + key = "it", + label = "IT", + value = "IT", + }, + { + key = "marketing", + label = "Marketing", + value = "market", + }, + { + key = "engingeering", + label = "Engineering", + value = "eng", + }, + ] +} +``` + +Create a global value listing the AMI attributes for three Linux +distributions. Then create a blueprint that creates an instance, +querying for the AMI using the attributes of the selected +distribution. + +```terraform +resource "resourcely_global_value" "amis" { + name = "EC2 AMI" + key = "amis" + description = "AMI selectors." + + type = "PRESET_VALUE_OBJECT" + options = [ + { + key = "ubuntu", + label = "Ubuntu", + value = { + name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*", + virt_type = "hvm", + owner = "099720109477", + } + }, + { + key = "centos", + label = "CentOS", + value = { + name = "CentOS Stream 9 x84_64 *", + virt_type = "hvm", + owner = "125523088429", + }, + }, + { + key = "debian", + label = "Debian", + value = { + name = "debian-12-amd64-*", + virt_type = "hvm", + owner = "136693071363", + }, + }, + ] +} + +resource "resourcely_blueprint" "simple_instance" { + name = "A simple EC2 Instance" + description = "Creates a simple EC2 instance using one of three preselected AMIs." + + cloud_provider = "PROVIDER_AMAZON" + categories = ["BLUEPRINT_COMPUTE"] + + is_published = true + + content = <<-EOT + --- + constants: + __name: "{{ bucket }}_{{ __guid }}" + variables: + ami: + description: The Linux distribution to run on this instance. + global_value: amis + --- + data "aws_ami" "{{ __name }}" { + most_recent = true + + filter { + name = "name" + values = [{{ ami.name }}] + } + + filter { + name = "virtualization-type" + values = [{{ ami.virt_type }}] + } + + owners = [{{ ami.owner }}] + } + + resource "aws_instance" "{{ __name }}" { + ami = data.aws_ami.{{ __name }}.id + instance_type = "t3.micro" + + tags = { + Name = "HelloWorld" + } + } + EOT +} +``` ## Schema ### Required -- `key` (String) An immutable identifier used to reference this global value in blueprints or guardrails. - -Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. -- `name` (String) A short display name -- `options` (Attributes List) The list of value options for this global value (see [below for nested schema](#nestedatt--options)) +- `key` (String) An immutable identifier used to reference this global value in blueprints or guardrails. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. +- `name` (String) The name of the global value. +- `options` (Attributes List) The list of value options for this global value. (see [below for nested schema](#nestedatt--options)) - `type` (String) The type of options in the global value. Can be one of `PRESET_VALUE_TEXT`, `PRESET_VALUE_NUMBER`, `PRESET_VALUE_LIST`, `PRESET_VALUE_OBJECT` ### Optional -- `description` (String) A longer description -- `is_deprecated` (Boolean) True if the global value should not be used in new blueprints or guardrails +- `description` (String) A description of the purpose of the global value. +- `is_deprecated` (Boolean) Set to true if the global value should not be used in new blueprints or guardrails. ### Read-Only -- `id` (String) UUID for this version of the global value -- `series_id` (String) UUID for the global value -- `version` (Number) Version of the global value +- `id` (String) UUID for the current version of the global value. +- `series_id` (String) UUID for the global value. +- `version` (Number) Incrementing version number for the current version of the global value. ### Nested Schema for `options` Required: -- `key` (String) An immutable identifier for ths option. +- `key` (String) An immutable identifier for ths option. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. +- `label` (String) A unique display name. +- `value` (String) A JSON encoding of the option's value. This value must match the declared type of the global value. Example: `value = jsonencode("a")` Example: `value = jsonencode(["a", "b"])` -Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`. -- `label` (String) A unique short display name -- `value` (String) A JSON encoding of the option's value. This value must match the declared type of the global value. +Optional: -Example: `value = jsonencode("a")` +- `description` (String) A description of this option's meaning. -Example: `value = jsonencode(["a", "b"])` +## Import -Optional: +A global value can be imported using its series_id. -- `description` (String) A longer description +```shell +terraform import resourcely_global_value.example 00000000-00000000-00000000-00000000 +``` diff --git a/docs/resources/guardrail.md b/docs/resources/guardrail.md index c93db1e..0385396 100644 --- a/docs/resources/guardrail.md +++ b/docs/resources/guardrail.md @@ -1,39 +1,88 @@ --- -# generated by https://github.com/hashicorp/terraform-plugin-docs page_title: "resourcely_guardrail Resource - terraform-provider-resourcely" subcategory: "" -description: |- - A resourcely guardrail --- # resourcely_guardrail (Resource) -A resourcely guardrail +A guardrail governs how cloud resources can be created and altered, preventing infrastructure misconfiguration. Before infrastructure is provisioned, Resourcely examines the changes being made and prevents a merge if any guardrail requirements are violated. +Some examples of guardrails include: +- Require approval for making a public S3 bucket +- Restrict the allowed compute instance types or images + +Guardrails are specified using the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). + +## Example Usage + +Create a guardrail using the [Really policy langauge](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). + +```terraform +resource "resourcely_guardrail" "s3_bucket_naming_convention" { + name = "S3 Bucket Naming Convention" + description = "Ensures that all S3 Buckets comply with our standardized naming convention, promoting consistency and ease of identification across our AWS environments." + + cloud_provider = "PROVIDER_AMAZON" + category = "GUARDRAIL_BEST_PRACTICES" + + content = <<-EOT + GUARDRAIL "S3 Bucket Naming Convention" + WHEN aws_s3_bucket + REQUIRE bucket STARTS WITH "mycompany-" + EOT +} +``` + +This resource also supports creating a guardrail from a Resourcely +Guardrail Template. Instead of specifying the `content`, specify the +`guardrail_template_series_id` and `guardrail_template_inputs` +instead. + +```terraform +resource "resourcely_guardrail" "s3_bucket_naming_convention_from_template" { + name = "S3 Bucket Naming Convention" + description = "Ensures that all S3 Buckets comply with our standardized naming convention, promoting consistency and ease of identification across our AWS environments." + + cloud_provider = "PROVIDER_AMAZON" + category = "GUARDRAIL_BEST_PRACTICES" + + guardrail_template_series_id = "4909a93c-b248-4e5a-bff5-7cc101702351" + guardrail_template_inputs = jsonencode({ + prefix = "mycompany-" + approver = "default" + }) +} +``` ## Schema ### Required -- `category` (String) The category to assign to the guardrail. Can be one of `GUARDRAIL_ACCESS_CONTROL`, `GUARDRAIL_BEST_PRACTICES`, `GUARDRAIL_CHANGE_MANAGEMENT`, `GUARDRAIL_COST_EFFICIENCY`, `GUARDRAIL_ENCRYPTION`, `GUARDRAIL_GLOBALIZATION`, `GUARDRAIL_IAM`, `GUARDRAIL_LOGGING`, `GUARDRAIL_MODULE_INPUTS`, `GUARDRAIL_PRIVACY_COMPLIANCE`, `GUARDRAIL_RELIABILITY`, `GUARDRAIL_STORAGE_AND_SCALE` -- `cloud_provider` (String) The cloud provider that this guardrail targets. Can be one of `PROVIDER_AMAZON`, `PROVIDER_AZURE`, `PROVIDER_CONDUCTORONE`, `PROVIDER_DATABRICKS`, `PROVIDER_DATADOG`, `PROVIDER_GITHUB`, `PROVIDER_GITLAB`, `PROVIDER_GOOGLE`, `PROVIDER_HYPERV`, `PROVIDER_IBM`,`PROVIDER_JUMPCLOUD`, `PROVIDER_KUBERNETES`, `PROVIDER_OKTA`, `PROVIDER_ORACLE`, `PROVIDER_RESOURCELY`, `PROVIDER_SNOWFLAKE`, `PROVIDER_SPACELIFT`, `PROVIDER_VMWARE`, `PROVIDER_OTHER` -- `name` (String) Name to associate with the guardrail +- `category` (String) The category to assign to this guardrail. Can be one of `GUARDRAIL_ACCESS_CONTROL`, `GUARDRAIL_BEST_PRACTICES`, `GUARDRAIL_CHANGE_MANAGEMENT`, `GUARDRAIL_COST_EFFICIENCY`, `GUARDRAIL_ENCRYPTION`, `GUARDRAIL_GLOBALIZATION`, `GUARDRAIL_IAM`, `GUARDRAIL_LOGGING`, `GUARDRAIL_MODULE_INPUTS`, `GUARDRAIL_PRIVACY_COMPLIANCE`, `GUARDRAIL_RELIABILITY`, `GUARDRAIL_STORAGE_AND_SCALE`. +- `cloud_provider` (String) The cloud provider that this guardrail targets. Can be one of `PROVIDER_AMAZON`, `PROVIDER_AZURE`, `PROVIDER_CONDUCTORONE`, `PROVIDER_DATABRICKS`, `PROVIDER_DATADOG`, `PROVIDER_GITHUB`, `PROVIDER_GITLAB`, `PROVIDER_GOOGLE`, `PROVIDER_HYPERV`, `PROVIDER_IBM`,`PROVIDER_JUMPCLOUD`, `PROVIDER_KUBERNETES`, `PROVIDER_OKTA`, `PROVIDER_ORACLE`, `PROVIDER_RESOURCELY`, `PROVIDER_SNOWFLAKE`, `PROVIDER_SPACELIFT`, `PROVIDER_VMWARE`, `PROVIDER_OTHER`. +- `name` (String) The name of the guardrail. ### Optional -- `content` (String) The content of the guardrail, written in Resourcely's Really language -- `description` (String) Description of what the guardrail applies to -- `guardrail_template_inputs` (String) A JSON encoding of values for the guardrail template inputs. - -Example: `guardrail_template_inputs = jsonencode({inputOne = "value one"})` -- `guardrail_template_series_id` (String) The series id of the guardrail template used to render the policies +- `content` (String) The guardrail policy written in the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). Must specify exactly one of `content` or `guardrail_template_series_id`. +- `description` (String) A description of the guardrail's purpose or policy. +- `guardrail_template_inputs` (String) A JSON encoding of values for the guardrail template inputs. Required if `guardrail_template_series_id` is used. Example: `guardrail_template_inputs = jsonencode({inputOne = "value one"})` +- `guardrail_template_series_id` (String) The series id of the guardrail template used to render the policy. Must specify exactly one of `guardrail_template_series_id` or `content`. - `scope` (String) -- `state` (String) The state to set the guardrail to. Can be one of `GUARDRAIL_STATE_INACTIVE`, `GUARDRAIL_STATE_EVALUATE_ONLY`, `GUARDRAIL_STATE_ACTIVE`. If not provided state is set to `GUARDRAIL_STATE_ACTIVE` +- `state` (String) The [state](https://docs.resourcely.io/build/setting-up-guardrails/releasing-guardrails#guardrail-status) of the guardrail. Can be one of `GUARDRAIL_STATE_INACTIVE`, `GUARDRAIL_STATE_EVALUATE_ONLY`, `GUARDRAIL_STATE_ACTIVE`. If not provided state is set to `GUARDRAIL_STATE_ACTIVE`. ### Read-Only -- `id` (String) UUID for this version. -- `series_id` (String) UUID for the guardrail -- `version` (Number) Specific version of the guardrail +- `id` (String) UUID for the current version of the guardrail. +- `series_id` (String) UUID for the guardrail. +- `version` (Number) Incrementing version number for the current version of the guardrail. + +## Import + +A guardrail can be imported using its series_id. + +```shell +terraform import resourcely_guardrail.example 00000000-00000000-00000000-00000000 +``` diff --git a/examples/data-sources/resourcely_blueprint/data-source.tf b/examples/data-sources/resourcely_blueprint/data-source.tf new file mode 100644 index 0000000..8b88693 --- /dev/null +++ b/examples/data-sources/resourcely_blueprint/data-source.tf @@ -0,0 +1,3 @@ +data "resourcely_blueprint" "example" { + series_id = "00000000-00000000-00000000-00000000" +} diff --git a/examples/data-sources/resourcely_context_question/data-source.tf b/examples/data-sources/resourcely_context_question/data-source.tf new file mode 100644 index 0000000..8210473 --- /dev/null +++ b/examples/data-sources/resourcely_context_question/data-source.tf @@ -0,0 +1,3 @@ +data "resourcely_context_question" "example" { + series_id = "00000000-00000000-00000000-00000000" +} diff --git a/examples/data-sources/resourcely_global_value/data-source.tf b/examples/data-sources/resourcely_global_value/data-source.tf new file mode 100644 index 0000000..7119bac --- /dev/null +++ b/examples/data-sources/resourcely_global_value/data-source.tf @@ -0,0 +1,3 @@ +data "resourcely_global_value" "example" { + series_id = "00000000-00000000-00000000-00000000" +} diff --git a/examples/data-sources/resourcely_guardrail/data-source.tf b/examples/data-sources/resourcely_guardrail/data-source.tf new file mode 100644 index 0000000..68f165c --- /dev/null +++ b/examples/data-sources/resourcely_guardrail/data-source.tf @@ -0,0 +1,3 @@ +data "resourcely_guardrail" "example" { + series_id = "00000000-00000000-00000000-00000000" +} diff --git a/examples/data-sources/scaffolding_example/data-source.tf b/examples/data-sources/scaffolding_example/data-source.tf deleted file mode 100644 index f4f73ef..0000000 --- a/examples/data-sources/scaffolding_example/data-source.tf +++ /dev/null @@ -1,3 +0,0 @@ -data "github_team" "example" { - configurable_attribute = "some-value" -} \ No newline at end of file diff --git a/examples/provider/provider.tf b/examples/provider/provider.tf index 38daf75..d1f088f 100644 --- a/examples/provider/provider.tf +++ b/examples/provider/provider.tf @@ -1,7 +1,15 @@ +# Pin the source and version of the provider terraform { required_providers { resourcely = { - source = "Resourcely-Inc/resourcely" + source = "Resourcely-Inc/resourcely" + version = "~> 1.0" } } -} \ No newline at end of file +} + +# No provider configuration is required. See `Authentication and +# Configuration` below to learn how to provide your Resourcley API +# credentials. +provider "resourcely" { +} diff --git a/examples/provider/provider_with_allowed_tenants.tf b/examples/provider/provider_with_allowed_tenants.tf new file mode 100644 index 0000000..51d9534 --- /dev/null +++ b/examples/provider/provider_with_allowed_tenants.tf @@ -0,0 +1,3 @@ +provider "resourcely" { + allowed_tenants = ["MyCompany"] +} diff --git a/examples/provider/provider_with_auth_token.tf b/examples/provider/provider_with_auth_token.tf new file mode 100644 index 0000000..1961861 --- /dev/null +++ b/examples/provider/provider_with_auth_token.tf @@ -0,0 +1,3 @@ +provider "resourcely" { + auth_token = var.resourcely_auth_token +} diff --git a/examples/resources/resourcely_blueprint/import.sh b/examples/resources/resourcely_blueprint/import.sh new file mode 100644 index 0000000..5d3a4af --- /dev/null +++ b/examples/resources/resourcely_blueprint/import.sh @@ -0,0 +1 @@ +terraform import resourcely_blueprint.example 00000000-00000000-00000000-00000000 diff --git a/examples/resources/resourcely_blueprint/resource.tf b/examples/resources/resourcely_blueprint/resource.tf new file mode 100644 index 0000000..55869b2 --- /dev/null +++ b/examples/resources/resourcely_blueprint/resource.tf @@ -0,0 +1,36 @@ +resource "resourcely_blueprint" "private_s3_bucket" { + name = "Private S3 Bucket" + description = "Creates a private, S3 bucket with configuration versioning." + + cloud_provider = "PROVIDER_AMAZON" + categories = ["BLUEPRINT_BLOB_STORAGE"] + + is_published = true + + content = <<-EOT + --- + constants: + __name: "{{ bucket }}_{{ __guid }}" + --- + resource "aws_s3_" "{{ __name }}" { + bucket = {{ bucket }} + } + + resource "aws_s3_bucket_public_access_block" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true + } + + resource "aws_s3_bucket_ownership_controls" "{{ __name }}" { + bucket = aws_s3_bucket.{{ __name }}.id + + rule { + object_ownership = "BucketOwnerEnforced" + } + } + EOT +} diff --git a/examples/resources/resourcely_context_question/import.sh b/examples/resources/resourcely_context_question/import.sh new file mode 100644 index 0000000..79ab84e --- /dev/null +++ b/examples/resources/resourcely_context_question/import.sh @@ -0,0 +1 @@ +terraform import resourcely_context_question.example 00000000-00000000-00000000-00000000 diff --git a/examples/resources/resourcely_context_question/resource.tf b/examples/resources/resourcely_context_question/resource.tf new file mode 100644 index 0000000..df56a29 --- /dev/null +++ b/examples/resources/resourcely_context_question/resource.tf @@ -0,0 +1,16 @@ +resource "resourcely_context_question" "data_classification" { + label = "classification" + prompt = "What kind of data is stored by this infrastructure?" + + qtype = "QTYPE_MULTI_SELECT" + answer_choices = [ + { label = "financial" }, + { label = "pii" }, + { label = "proprietary" }, + { label = "public" }, + ] + + blueprint_categories = ["BLUEPRINT_BLOB_STORAGE", "BLUEPRINT_DATABASE"] + + priority = 1 +} diff --git a/examples/resources/resourcely_context_question/resource_with_email_format.tf b/examples/resources/resourcely_context_question/resource_with_email_format.tf new file mode 100644 index 0000000..a77bafc --- /dev/null +++ b/examples/resources/resourcely_context_question/resource_with_email_format.tf @@ -0,0 +1,16 @@ +resource "resourcely_context_question" "owner" { + label = "owner" + prompt = "What is the email address of the team or person responsible for this infrastructure?" + + qtype = "QTYPE_TEXT" + answer_format = "ANSWER_EMAIL" + + blueprint_categories = [ + "BLUEPRINT_COMPUTE", + "BLUEPRINT_DATABASE", + "BLUEPRINT_NETWORKING", + "BLUEPRINT_SERVERLESS_COMPUTE" + ] + + priority = 0 +} diff --git a/examples/resources/resourcely_context_question/resource_with_regex_format.tf b/examples/resources/resourcely_context_question/resource_with_regex_format.tf new file mode 100644 index 0000000..defd2b9 --- /dev/null +++ b/examples/resources/resourcely_context_question/resource_with_regex_format.tf @@ -0,0 +1,17 @@ +resource "resourcely_context_question" "project_code" { + label = "project_code" + prompt = "What is the project code that this infrastructure should be associated with?" + + qtype = "QTYPE_TEXT" + answer_format = "ANSWER_REGEX" + regex_pattern = "^[A-Z0-9]{6}$" + + blueprint_categories = [ + "BLUEPRINT_COMPUTE", + "BLUEPRINT_DATABASE", + "BLUEPRINT_NETWORKING", + "BLUEPRINT_SERVERLESS_COMPUTE" + ] + + priority = 2 +} diff --git a/examples/resources/resourcely_global_value/import.sh b/examples/resources/resourcely_global_value/import.sh new file mode 100644 index 0000000..cdd0fc9 --- /dev/null +++ b/examples/resources/resourcely_global_value/import.sh @@ -0,0 +1 @@ +terraform import resourcely_global_value.example 00000000-00000000-00000000-00000000 diff --git a/examples/resources/resourcely_global_value/resource.tf b/examples/resources/resourcely_global_value/resource.tf new file mode 100644 index 0000000..f2e722f --- /dev/null +++ b/examples/resources/resourcely_global_value/resource.tf @@ -0,0 +1,29 @@ +resource "resourcely_global_value" "departments" { + name = "Departments" + key = "departments" + description = "All departments within MyCompany" + + type = "PRESET_VALUE_TEXT" + options = [ + { + key = "product", + label = "Product", + value = "product", + }, + { + key = "it", + label = "IT", + value = "IT", + }, + { + key = "marketing", + label = "Marketing", + value = "market", + }, + { + key = "engingeering", + label = "Engineering", + value = "eng", + }, + ] +} diff --git a/examples/resources/resourcely_global_value/resource_with_object_values.tf b/examples/resources/resourcely_global_value/resource_with_object_values.tf new file mode 100644 index 0000000..fcff589 --- /dev/null +++ b/examples/resources/resourcely_global_value/resource_with_object_values.tf @@ -0,0 +1,81 @@ +resource "resourcely_global_value" "amis" { + name = "EC2 AMI" + key = "amis" + description = "AMI selectors." + + type = "PRESET_VALUE_OBJECT" + options = [ + { + key = "ubuntu", + label = "Ubuntu", + value = { + name = "ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*", + virt_type = "hvm", + owner = "099720109477", + } + }, + { + key = "centos", + label = "CentOS", + value = { + name = "CentOS Stream 9 x84_64 *", + virt_type = "hvm", + owner = "125523088429", + }, + }, + { + key = "debian", + label = "Debian", + value = { + name = "debian-12-amd64-*", + virt_type = "hvm", + owner = "136693071363", + }, + }, + ] +} + +resource "resourcely_blueprint" "simple_instance" { + name = "A simple EC2 Instance" + description = "Creates a simple EC2 instance using one of three preselected AMIs." + + cloud_provider = "PROVIDER_AMAZON" + categories = ["BLUEPRINT_COMPUTE"] + + is_published = true + + content = <<-EOT + --- + constants: + __name: "{{ bucket }}_{{ __guid }}" + variables: + ami: + description: The Linux distribution to run on this instance. + global_value: amis + --- + data "aws_ami" "{{ __name }}" { + most_recent = true + + filter { + name = "name" + values = [{{ ami.name }}] + } + + filter { + name = "virtualization-type" + values = [{{ ami.virt_type }}] + } + + owners = [{{ ami.owner }}] + } + + resource "aws_instance" "{{ __name }}" { + ami = data.aws_ami.{{ __name }}.id + instance_type = "t3.micro" + + tags = { + Name = "HelloWorld" + } + } + EOT +} diff --git a/examples/resources/resourcely_guardrail/import.sh b/examples/resources/resourcely_guardrail/import.sh new file mode 100644 index 0000000..332cb1b --- /dev/null +++ b/examples/resources/resourcely_guardrail/import.sh @@ -0,0 +1 @@ +terraform import resourcely_guardrail.example 00000000-00000000-00000000-00000000 diff --git a/examples/resources/resourcely_guardrail/resource.tf b/examples/resources/resourcely_guardrail/resource.tf new file mode 100644 index 0000000..a5c8f35 --- /dev/null +++ b/examples/resources/resourcely_guardrail/resource.tf @@ -0,0 +1,13 @@ +resource "resourcely_guardrail" "s3_bucket_naming_convention" { + name = "S3 Bucket Naming Convention" + description = "Ensures that all S3 Buckets comply with our standardized naming convention, promoting consistency and ease of identification across our AWS environments." + + cloud_provider = "PROVIDER_AMAZON" + category = "GUARDRAIL_BEST_PRACTICES" + + content = <<-EOT + GUARDRAIL "S3 Bucket Naming Convention" + WHEN aws_s3_bucket + REQUIRE bucket STARTS WITH "mycompany-" + EOT +} diff --git a/examples/resources/resourcely_guardrail/resource_with_template.tf b/examples/resources/resourcely_guardrail/resource_with_template.tf new file mode 100644 index 0000000..fbc09b1 --- /dev/null +++ b/examples/resources/resourcely_guardrail/resource_with_template.tf @@ -0,0 +1,13 @@ +resource "resourcely_guardrail" "s3_bucket_naming_convention_from_template" { + name = "S3 Bucket Naming Convention" + description = "Ensures that all S3 Buckets comply with our standardized naming convention, promoting consistency and ease of identification across our AWS environments." + + cloud_provider = "PROVIDER_AMAZON" + category = "GUARDRAIL_BEST_PRACTICES" + + guardrail_template_series_id = "4909a93c-b248-4e5a-bff5-7cc101702351" + guardrail_template_inputs = jsonencode({ + prefix = "mycompany-" + approver = "default" + }) +} diff --git a/examples/resources/scaffolding_example/resource.tf b/examples/resources/scaffolding_example/resource.tf deleted file mode 100644 index 39193b6..0000000 --- a/examples/resources/scaffolding_example/resource.tf +++ /dev/null @@ -1,4 +0,0 @@ -# for more information on Authoring Your Own Blueprints https://docs.resourcely.com/getting-started/using-resourcely/setting-up-blueprints/authoring-your-own-blueprints -resource "resourcely_blueprint" "example" { - configurable_attribute = "some-value" -} diff --git a/internal/provider/blueprint_data_source.go b/internal/provider/blueprint_data_source.go index e551330..92417bd 100644 --- a/internal/provider/blueprint_data_source.go +++ b/internal/provider/blueprint_data_source.go @@ -29,12 +29,11 @@ func (d *BlueprintDataSource) Metadata(_ context.Context, req datasource.Metadat func (d *BlueprintDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A resourcely blueprint", + MarkdownDescription: "A blueprint is a configuration template used to provision cloud infrastructure resources. Blueprints allow you to:\n\n- Define which options are available for properties of your resource(s).\n- Apply gaurdrails to your resource(s) to prevent misconfiguration.\n- Define what information to collect from your developers before provisioning the resource.\n\nOnce a blueprint is configured and published, it becomes available for use in your Resourcely service catalog.\n\nThe template is specified using Resourcely's TFT templating language. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details about TFT. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the template.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of the blueprint.", Computed: true, }, "series_id": schema.StringAttribute{ @@ -42,51 +41,50 @@ func (d *BlueprintDataSource) Schema(_ context.Context, _ datasource.SchemaReque Required: true, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the blueprint", + MarkdownDescription: "Increment version number for the current version of the blueprint.", Computed: true, }, "scope": schema.StringAttribute{ Computed: true, }, "name": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The name of the blueprint.", Computed: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A description of the blueprints's purpose or functionality.", Computed: true, }, "cloud_provider": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The cloud provider that this blueprint targets.", Computed: true, }, "content": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The templated Terraform configuration specified using Resourcely's TFT format.", Computed: true, }, "guidance": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Guidance to help your users know when and how to use this blueprint.", Computed: true, }, "categories": schema.SetAttribute{ ElementType: basetypes.StringType{}, Computed: true, - MarkdownDescription: "", + MarkdownDescription: "The category to assign to this blueprint.", }, "labels": schema.SetAttribute{ ElementType: basetypes.StringType{}, Computed: true, - MarkdownDescription: "", + MarkdownDescription: "Additional keywords to help your users discover this blueprint.", }, "is_published": schema.BoolAttribute{ Computed: true, - Optional: true, MarkdownDescription: "A published blueprint is available for use by developers to create resources through the Resourcely portal.", }, "excluded_context_question_series": schema.SetAttribute{ ElementType: basetypes.StringType{}, Computed: true, - MarkdownDescription: "series_id for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories", + MarkdownDescription: "The series_ids for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories", }, }, } diff --git a/internal/provider/blueprint_resource.go b/internal/provider/blueprint_resource.go index c5fc67f..f643f5c 100644 --- a/internal/provider/blueprint_resource.go +++ b/internal/provider/blueprint_resource.go @@ -51,23 +51,21 @@ func (r *BlueprintResource) Schema( resp *resource.SchemaResponse, ) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A Resourcely Blueprint", - + MarkdownDescription: "A blueprint is a configuration template used to provision cloud infrastructure resources. Blueprints allow you to:\n\n- Define which options are available for properties of your resource(s).\n- Apply gaurdrails to your resource(s) to prevent misconfiguration.\n- Define what information to collect from your developers before provisioning the resource.\n\nOnce a blueprint is configured and published, it becomes available for use in your Resourcely service catalog.\n\nThe template is specified using Resourcely's TFT templating language. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details about TFT. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the template.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of the blueprint.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the blueprint", + MarkdownDescription: "UUID for the blueprint.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the blueprint", + MarkdownDescription: "Incrementing version number for the current version of the blueprint.", Computed: true, }, "scope": schema.StringAttribute{ @@ -78,11 +76,11 @@ func (r *BlueprintResource) Schema( }, }, "name": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The name of the blueprint.", Required: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A description of the blueprint's purpose or functionality.", Default: stringdefault.StaticString(""), Computed: true, Optional: true, @@ -116,18 +114,18 @@ func (r *BlueprintResource) Schema( }, }, "content": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The templated Terraform configuration specified using Resourcely's TFT format. See the [Authoring Your Own Blueprints](https://docs.resourcely.io/build/setting-up-blueprints/authoring-your-own-blueprints) docs for details. The [Resourcely Foundry](https://portal.resourcely.io/foundry?mode=blueprint) provides an IDE to assist with authoring the content.", Required: true, }, "guidance": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "Guidance to help your users know when and how to use this blueprint.", Default: stringdefault.StaticString(""), Computed: true, Optional: true, }, "labels": schema.SetAttribute{ ElementType: basetypes.StringType{}, - MarkdownDescription: "", + MarkdownDescription: "Additional keywords to help your users discover this blueprint.", Default: setdefault.StaticValue(types.SetValueMust(types.StringType, nil)), Computed: true, Optional: true, @@ -159,7 +157,7 @@ func (r *BlueprintResource) Schema( "is_published": schema.BoolAttribute{ Computed: true, Optional: true, - MarkdownDescription: "A published blueprint is available for use by developers to create resources through the Resourcely portal.\n\nIf left unset, the blueprint will start as unpublished, and you may safely change this property in the Resourcely portal.", + MarkdownDescription: "A published blueprint is available for use by developers to create resources through the Resourcely portal. If left unset, the blueprint will start as unpublished, and you may safely change this property in the Resourcely portal.", PlanModifiers: []planmodifier.Bool{ boolplanmodifier.UseStateForUnknown(), }, @@ -169,7 +167,7 @@ func (r *BlueprintResource) Schema( ElementType: basetypes.StringType{}, Computed: true, Optional: true, - MarkdownDescription: "series_id for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories", + MarkdownDescription: "The series_ids for context questions that won't be used with this blueprint, even if this blueprint matches the context questions' blueprint_categories", }, }, } diff --git a/internal/provider/context_question_data_source.go b/internal/provider/context_question_data_source.go index a2dd2e6..46289e5 100644 --- a/internal/provider/context_question_data_source.go +++ b/internal/provider/context_question_data_source.go @@ -30,20 +30,18 @@ func (d *ContextQuestionDataSource) Metadata(_ context.Context, req datasource.M func (d *ContextQuestionDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A resourcely ContextQuestion", - + MarkdownDescription: "A [context question](https://docs.resourcely.io/concepts/other-features-and-settings/global-context-and-values) is used to gather data from developers before provisioning a resource. They are designed to gather and store insightful data related to the resource.\n\nSome examples include:\n\n- What type of data will be stored in this infrastructure?\n- What application is this infrastructure associated with?\n- What is the email address the person/team responsible for this infrastructure?\n\nThree types of context questions are supported:\n\n- Text\n- Single Choice\n- Multiple Choice\n", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of this context question.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the global context", + MarkdownDescription: "UUID for the context question.", Required: true, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the global context", + MarkdownDescription: "Incrementing version number of the context question.", Computed: true, }, "scope": schema.StringAttribute{ @@ -51,49 +49,50 @@ func (d *ContextQuestionDataSource) Schema(_ context.Context, _ datasource.Schem Computed: true, }, "label": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A key used to reference the context question in blueprints and guardrails. Is unique within your Resourcley tenant.", Computed: true, }, "prompt": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The question that Resourcely will ask your developers.", Computed: true, }, "qtype": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The type of the question. Will be one of `QYTPE_TEXT`, `QYTPE_SINGLE_SELECT`, or `QTYPE_MULTI_SELECT`.", Computed: true, }, "answer_format": schema.StringAttribute{ - MarkdownDescription: "", - Computed: true, + MarkdownDescription: "A format validation for acceptable answers to the context question. Applicable only when `qtype` is `QTYPE_TEXT` . Will be one of `ANSWER_TEXT`, `ANSWER_NUMBER`, `ANSWER_EMAIL`, or `ANSWER_REGEX`. If `ANSWER_REGEX`, the `regex_pattern` property will also be set.", + + Computed: true, }, "answer_choices": schema.SetNestedAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The answer choices from which the developer can select. Applicable only when `qtype` is `QTYPE_SINGLE_SELECT` or `QTYPE_MULTI_SELECT`.", Computed: true, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "label": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The value for the answer choice.", Computed: true, }, }, }, }, "blueprint_categories": schema.SetAttribute{ + MarkdownDescription: "The blueprint categories to which this context question applies. This question will be asked whenever a developer uses a blueprint in these categories.", ElementType: basetypes.StringType{}, Computed: true, - MarkdownDescription: "Resource categories the context question applies to", }, "regex_pattern": schema.StringAttribute{ - MarkdownDescription: "Regex validation for the acceptable answers to the context question", + MarkdownDescription: "A regex validation for the acceptable answers to the context question. Applicable only when both `qtype` is `QTYPE_TEXT` and `answer_format` is `ANSWER_REGEX`.", Computed: true, }, "excluded_blueprint_series": schema.SetAttribute{ + MarkdownDescription: "The series_ids of blueprints for which this question should not be asked, even if those blueprints belong to the context question's blueprint_categories.", ElementType: basetypes.StringType{}, Computed: true, - MarkdownDescription: "series_id for Blueprints exempt from this context question even though those blueprints belong to the context question's blueprint_categories", }, "priority": schema.Int64Attribute{ - MarkdownDescription: "Priority of this question, relative to others. 0=high, 1=medium, 2=low", + MarkdownDescription: "The priority of this question, relative to others. 0=high, 1=medium, 2=low", Computed: true, }, }, diff --git a/internal/provider/context_question_resource.go b/internal/provider/context_question_resource.go index 64ed0a4..04342c4 100644 --- a/internal/provider/context_question_resource.go +++ b/internal/provider/context_question_resource.go @@ -46,23 +46,21 @@ func (r *ContextQuestionResource) Metadata(_ context.Context, req resource.Metad func (r *ContextQuestionResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A Resourcely Context Question", - + MarkdownDescription: "A [context question](https://docs.resourcely.io/concepts/other-features-and-settings/global-context-and-values) is used to gather data from developers before provisioning a resource. They are designed to gather and store insightful data related to the resource.\n\nSome examples include:\n\n- What type of data will be stored in this infrastructure?\n- What application is this infrastructure associated with?\n- What is the email address the person/team responsible for this infrastructure?\n\nThree types of context questions are supported:\n\n- Text\n- Single Choice\n- Multiple Choice\n", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of the context question.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the Context Question", + MarkdownDescription: "UUID for the context question.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the Global Context", + MarkdownDescription: "Incrementing version number for the current version of this context question.", Computed: true, }, "scope": schema.StringAttribute{ @@ -73,15 +71,15 @@ func (r *ContextQuestionResource) Schema(_ context.Context, _ resource.SchemaReq }, }, "label": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A key used to reference the context question in blueprints and guardrails. Must be unique within your Resourcley tenant.", Required: true, }, "prompt": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The question that Resourcely with ask your developers.", Required: true, }, "qtype": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The type of the question. Must be one of `QTYPE_TEXT`, `QTYPE_SINGLE_SELECT`, or `QTYPE_MULTI_SELECT`", Required: true, Validators: []validator.String{ stringvalidator.OneOf( @@ -91,7 +89,7 @@ func (r *ContextQuestionResource) Schema(_ context.Context, _ resource.SchemaReq }, }, "answer_format": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A format validation for acceptable answers to the context question. Applicable only when `qtype` is `QTYPE_TEXT` . Must be one of `ANSWER_TEXT`, `ANSWER_NUMBER`, `ANSWER_EMAIL`, or `ANSWER_REGEX`. If `ANSWER_REGEX`, must also specify the `regex_pattern` property.", Default: stringdefault.StaticString("ANSWER_TEXT"), Optional: true, Computed: true, @@ -105,14 +103,14 @@ func (r *ContextQuestionResource) Schema(_ context.Context, _ resource.SchemaReq }, }, "answer_choices": schema.SetNestedAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The answer choices from which the developer can select. Applicable only when `qtype` is `QTYPE_SINGLE_SELECT` or `QTYPE_MULTI_SELECT`.", Default: setdefault.StaticValue(types.SetValueMust(types.ObjectType{AttrTypes: map[string]attr.Type{"label": types.StringType}}, nil)), Optional: true, Computed: true, NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "label": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The value for the answer choice.", Required: true, }, }, @@ -120,41 +118,44 @@ func (r *ContextQuestionResource) Schema(_ context.Context, _ resource.SchemaReq }, "blueprint_categories": schema.SetAttribute{ ElementType: basetypes.StringType{}, - MarkdownDescription: "", + MarkdownDescription: "The blueprint categories to which this context question applies. This question will be asked whenever a developer uses a blueprint in these categories.", Default: setdefault.StaticValue(types.SetValueMust(types.StringType, nil)), Computed: true, Optional: true, Validators: []validator.Set{ // All list items must pass the nested validators setvalidator.ValueStringsAre(stringvalidator.OneOf( + "BLUEPRINT_ASYNC_PROCESSING", "BLUEPRINT_BLOB_STORAGE", - "BLUEPRINT_NETWORKING", - "BLUEPRINT_DATABASE", "BLUEPRINT_COMPUTE", - "BLUEPRINT_SERVERLESS_COMPUTE", - "BLUEPRINT_ASYNC_PROCESSING", "BLUEPRINT_CONTAINERIZATION", + "BLUEPRINT_DATABASE", + "BLUEPRINT_GITHUB_REPO", + "BLUEPRINT_GITHUB_REPO_TEAM", + "BLUEPRINT_IAM", "BLUEPRINT_LOGS_AND_METRICS", + "BLUEPRINT_NETWORKING", + "BLUEPRINT_SERVERLESS_COMPUTE", ), ), }, }, "regex_pattern": schema.StringAttribute{ + MarkdownDescription: "A regex validation for the acceptable answers to the context question. Applicable only when both `qtype` is `QTYPE_TEXT` and `answer_format` is `ANSWER_REGEX`.", Default: stringdefault.StaticString(""), - MarkdownDescription: "Regex validation for the acceptable answers to the context question", Optional: true, Computed: true, }, "excluded_blueprint_series": schema.SetAttribute{ + MarkdownDescription: "The series_ids of blueprints for which this question should not be asked, even if those blueprints belong to the context question's blueprint_categories.", Default: setdefault.StaticValue(types.SetValueMust(types.StringType, nil)), ElementType: basetypes.StringType{}, - MarkdownDescription: "series_id for Blueprints exempt from this context question even though those blueprints belong to the context question's blueprint_categories", Optional: true, Computed: true, }, "priority": schema.Int64Attribute{ + MarkdownDescription: "The priority of this question, relative to others. 0=high, 1=medium, 2=low", Default: int64default.StaticInt64(0), - MarkdownDescription: "Priority of this question, relative to others. 0=high, 1=medium, 2=low", Optional: true, Computed: true, Validators: []validator.Int64{ diff --git a/internal/provider/global_value_data_source.go b/internal/provider/global_value_data_source.go index c45d9d6..07ffbed 100644 --- a/internal/provider/global_value_data_source.go +++ b/internal/provider/global_value_data_source.go @@ -29,24 +29,22 @@ func (d *GlobalValueDataSource) Metadata(_ context.Context, req datasource.Metad func (d *GlobalValueDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A Resourcely global value", - + MarkdownDescription: "A [global value](https://docs.resourcely.io/concepts/other-features-and-settings/global-values) allows admins to define custom drop-downs for customizing Terraform infrastructure resource properties before they are provisioned. They are useful for providing access to lists of relatively static values like VPC IDs, allowed regions, department or team names, etc.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of the global value.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the global value", + MarkdownDescription: "UUID for the global value.", Required: true, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the global value", + MarkdownDescription: "Incrementing version number for the current version of the global value.", Computed: true, }, "is_deprecated": schema.BoolAttribute{ - MarkdownDescription: "True if the global value should not be used in new blueprints or guardrails", + MarkdownDescription: "Set to true if the global value should not be used in new blueprints or guardrails", Computed: true, }, "key": schema.StringAttribute{ @@ -54,40 +52,40 @@ func (d *GlobalValueDataSource) Schema(_ context.Context, _ datasource.SchemaReq Computed: true, }, "name": schema.StringAttribute{ - MarkdownDescription: "A short display name", + MarkdownDescription: "The name of the global value.", Computed: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "A longer description", + MarkdownDescription: "A description of the purpose of the global value.", Computed: true, }, "type": schema.StringAttribute{ - MarkdownDescription: "The type of options in the global value. Can be one of `PRESET_VALUE_TEXT`, `PRESET_VALUE_NUMBER`, `PRESET_VALUE_LIST`, `PRESET_VALUE_OBJECT`", + MarkdownDescription: "The type of options in the global value. Will be one of `PRESET_VALUE_TEXT`, `PRESET_VALUE_NUMBER`, `PRESET_VALUE_LIST`, `PRESET_VALUE_OBJECT`", Computed: true, }, "options": schema.ListNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "key": schema.StringAttribute{ - MarkdownDescription: "An immutable identifier for ths option.\n\nMust start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", + MarkdownDescription: "An immutable identifier for ths option. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", Computed: true, }, "label": schema.StringAttribute{ - MarkdownDescription: "A unique short display name", + MarkdownDescription: "A unique display name", Computed: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "A longer description", + MarkdownDescription: "A description of this option's meaning.", Computed: true, }, "value": schema.StringAttribute{ CustomType: jsontypes.NormalizedType{}, - MarkdownDescription: "A JSON encoding of the option's value. This value must match the declared type of the global value.\n\nExample: `value = jsonencode(\"a\")`\n\nExample: `value = jsonencode([\"a\", \"b\"])`", + MarkdownDescription: "A JSON encoding of the option's value.`", Computed: true, }, }, }, - MarkdownDescription: "The list of value options for this global value", + MarkdownDescription: "The list of value options for this global value.", Computed: true, }, }, diff --git a/internal/provider/global_value_resource.go b/internal/provider/global_value_resource.go index 69f80f5..9821f2a 100644 --- a/internal/provider/global_value_resource.go +++ b/internal/provider/global_value_resource.go @@ -51,44 +51,42 @@ func (r *GlobalValueResource) Schema( resp *resource.SchemaResponse, ) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A Resourcely GlobalValue", - + MarkdownDescription: "A [global value](https://docs.resourcely.io/concepts/other-features-and-settings/global-values) allows admins to define custom drop-downs for customizing Terraform infrastructure resource properties before they are provisioned. They are useful for providing access to lists of relatively static values like VPC IDs, allowed regions, department or team names, etc.\n\nThis global value API does not support deletion. Deleting the Terraform resource will remove the resource from the Terraform state file, but will not actually delete the global value entity. Set `is_deprecated = true` to tell Resourcely that this global value should no longer be used by new blueprints or guardrails.", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version of the global value", + MarkdownDescription: "UUID for the current version of the global value.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the global value", + MarkdownDescription: "UUID for the global value.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Version of the global value", + MarkdownDescription: "Incrementing version number for the current version of the global value.", Computed: true, }, "is_deprecated": schema.BoolAttribute{ - MarkdownDescription: "True if the global value should not be used in new blueprints or guardrails", + MarkdownDescription: "Set to true if the global value should not be used in new blueprints or guardrails.", Default: booldefault.StaticBool(false), Computed: true, Optional: true, }, "key": schema.StringAttribute{ - MarkdownDescription: "An immutable identifier used to reference this global value in blueprints or guardrails.\n\nMust start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", + MarkdownDescription: "An immutable identifier used to reference this global value in blueprints or guardrails. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", Required: true, Validators: []validator.String{ stringvalidator.RegexMatches(regexp.MustCompile("^[a-z][a-z0-9_]*$"), "Key must start with a lowercase letter in`a-z` and include only characters in `a-z0-9_`."), }, }, "name": schema.StringAttribute{ - MarkdownDescription: "A short display name", + MarkdownDescription: "The name of the global value.", Required: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "A longer description", + MarkdownDescription: "A description of the purpose of the global value.", Default: stringdefault.StaticString(""), Computed: true, Optional: true, @@ -109,29 +107,29 @@ func (r *GlobalValueResource) Schema( NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "key": schema.StringAttribute{ - MarkdownDescription: "An immutable identifier for ths option.\n\nMust start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", + MarkdownDescription: "An immutable identifier for ths option. Must start with a lowercase letter in `a-z` and include only characters in `a-z0-9_`.", Required: true, Validators: []validator.String{ stringvalidator.RegexMatches(regexp.MustCompile("^[a-z][a-z0-9_]*$"), "Key must start with a lowercase letter in`a-z` and include only characters in `a-z0-9_`."), }}, "label": schema.StringAttribute{ - MarkdownDescription: "A unique short display name", + MarkdownDescription: "A unique display name.", Required: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "A longer description", + MarkdownDescription: "A description of this option's meaning.", Default: stringdefault.StaticString(""), Computed: true, Optional: true, }, "value": schema.StringAttribute{ CustomType: jsontypes.NormalizedType{}, - MarkdownDescription: "A JSON encoding of the option's value. This value must match the declared type of the global value.\n\nExample: `value = jsonencode(\"a\")`\n\nExample: `value = jsonencode([\"a\", \"b\"])`", + MarkdownDescription: "A JSON encoding of the option's value. This value must match the declared type of the global value. Example: `value = jsonencode(\"a\")` Example: `value = jsonencode([\"a\", \"b\"])`", Required: true, }, }, }, - MarkdownDescription: "The list of value options for this global value", + MarkdownDescription: "The list of value options for this global value.", Required: true, Validators: []validator.List{ listvalidator.SizeAtLeast(1), diff --git a/internal/provider/guardrail_data_source.go b/internal/provider/guardrail_data_source.go index ec70d3f..4b2096e 100644 --- a/internal/provider/guardrail_data_source.go +++ b/internal/provider/guardrail_data_source.go @@ -29,20 +29,18 @@ func (d *GuardrailDataSource) Metadata(ctx context.Context, req datasource.Metad func (d *GuardrailDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A resourcely guardrail", - + MarkdownDescription: "A guardrail governs how cloud resources can be created and altered, preventing infrastructure misconfiguration. Before infrastructure is provisioned, Resourcely examines the changes being made and prevents a merge if any guardrail requirements are violated. Some examples of guardrails include:\n\n- Require approval for making a public S3 bucket\n- Restrict the allowed compute instance types or images\n\nGuardrails are specified using the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails).", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of this guar.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the guardrail", + MarkdownDescription: "UUID for the guardrail.", Required: true, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the guardrail", + MarkdownDescription: "Incrementing version number for this current version of the guardrail.", Computed: true, }, "scope": schema.StringAttribute{ @@ -50,36 +48,36 @@ func (d *GuardrailDataSource) Schema(ctx context.Context, req datasource.SchemaR Computed: true, }, "name": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The name of the guardrail.", Computed: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "A description of the guardrail's purpose or policy.", Computed: true, }, "cloud_provider": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The cloud provider that this guardrail targets.", Computed: true, }, "category": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The category of this guardrail.", Computed: true, }, "state": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The [state](https://docs.resourcely.io/build/setting-up-guardrails/releasing-guardrails#guardrail-status) of the guardrail.", Computed: true, }, "content": schema.StringAttribute{ - MarkdownDescription: "", + MarkdownDescription: "The guardrail policy written in the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails).", Computed: true, }, "guardrail_template_series_id": schema.StringAttribute{ - MarkdownDescription: "The series id of the guardrail template used to render the policies", + MarkdownDescription: "The series id of the guardrail template used to render the policy.", Computed: true, }, "guardrail_template_inputs": schema.StringAttribute{ CustomType: jsontypes.NormalizedType{}, - MarkdownDescription: "A JSON encoding of values for the guardrail template inputs.\n\nExample: `guardrail_template_inputs = jsonencode({inputOne = \"value one\"})`", + MarkdownDescription: "A JSON encoding of values for the guardrail template inputs.`", Computed: true, }, }, diff --git a/internal/provider/guardrail_resource.go b/internal/provider/guardrail_resource.go index bf0cbd8..1210b9c 100644 --- a/internal/provider/guardrail_resource.go +++ b/internal/provider/guardrail_resource.go @@ -48,23 +48,21 @@ func (r *GuardrailResource) Schema( resp *resource.SchemaResponse, ) { resp.Schema = schema.Schema{ - // This description is used by the documentation generator and the language server. - MarkdownDescription: "A resourcely guardrail", - + MarkdownDescription: "A guardrail governs how cloud resources can be created and altered, preventing infrastructure misconfiguration. Before infrastructure is provisioned, Resourcely examines the changes being made and prevents a merge if any guardrail requirements are violated.\n\nSome examples of guardrails include:\n\n- Require approval for making a public S3 bucket\n- Restrict the allowed compute instance types or images\n\nGuardrails are specified using the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails).", Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ - MarkdownDescription: "UUID for this version.", + MarkdownDescription: "UUID for the current version of the guardrail.", Computed: true, }, "series_id": schema.StringAttribute{ - MarkdownDescription: "UUID for the guardrail", + MarkdownDescription: "UUID for the guardrail.", Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, }, "version": schema.Int64Attribute{ - MarkdownDescription: "Specific version of the guardrail", + MarkdownDescription: "Incrementing version number for the current version of the guardrail.", Computed: true, }, "scope": schema.StringAttribute{ @@ -75,17 +73,17 @@ func (r *GuardrailResource) Schema( }, }, "name": schema.StringAttribute{ - MarkdownDescription: "Name to associate with the guardrail", + MarkdownDescription: "The name of the guardrail.", Required: true, }, "description": schema.StringAttribute{ - MarkdownDescription: "Description of what the guardrail applies to", + MarkdownDescription: "A description of the guardrail's purpose or policy.", Default: stringdefault.StaticString(""), Computed: true, Optional: true, }, "cloud_provider": schema.StringAttribute{ - MarkdownDescription: "The cloud provider that this guardrail targets. Can be one of `PROVIDER_AMAZON`, `PROVIDER_AZURE`, `PROVIDER_CONDUCTORONE`, `PROVIDER_DATABRICKS`, `PROVIDER_DATADOG`, `PROVIDER_GITHUB`, `PROVIDER_GITLAB`, `PROVIDER_GOOGLE`, `PROVIDER_HYPERV`, `PROVIDER_IBM`,`PROVIDER_JUMPCLOUD`, `PROVIDER_KUBERNETES`, `PROVIDER_OKTA`, `PROVIDER_ORACLE`, `PROVIDER_RESOURCELY`, `PROVIDER_SNOWFLAKE`, `PROVIDER_SPACELIFT`, `PROVIDER_VMWARE`, `PROVIDER_OTHER`", + MarkdownDescription: "The cloud provider that this guardrail targets. Can be one of `PROVIDER_AMAZON`, `PROVIDER_AZURE`, `PROVIDER_CONDUCTORONE`, `PROVIDER_DATABRICKS`, `PROVIDER_DATADOG`, `PROVIDER_GITHUB`, `PROVIDER_GITLAB`, `PROVIDER_GOOGLE`, `PROVIDER_HYPERV`, `PROVIDER_IBM`,`PROVIDER_JUMPCLOUD`, `PROVIDER_KUBERNETES`, `PROVIDER_OKTA`, `PROVIDER_ORACLE`, `PROVIDER_RESOURCELY`, `PROVIDER_SNOWFLAKE`, `PROVIDER_SPACELIFT`, `PROVIDER_VMWARE`, `PROVIDER_OTHER`.", Required: true, Validators: []validator.String{ stringvalidator.OneOf( @@ -112,7 +110,7 @@ func (r *GuardrailResource) Schema( }, }, "category": schema.StringAttribute{ - MarkdownDescription: "The category to assign to the guardrail. Can be one of `GUARDRAIL_ACCESS_CONTROL`, `GUARDRAIL_BEST_PRACTICES`, `GUARDRAIL_CHANGE_MANAGEMENT`, `GUARDRAIL_COST_EFFICIENCY`, `GUARDRAIL_ENCRYPTION`, `GUARDRAIL_GLOBALIZATION`, `GUARDRAIL_IAM`, `GUARDRAIL_LOGGING`, `GUARDRAIL_MODULE_INPUTS`, `GUARDRAIL_PRIVACY_COMPLIANCE`, `GUARDRAIL_RELIABILITY`, `GUARDRAIL_STORAGE_AND_SCALE`", + MarkdownDescription: "The category to assign to this guardrail. Can be one of `GUARDRAIL_ACCESS_CONTROL`, `GUARDRAIL_BEST_PRACTICES`, `GUARDRAIL_CHANGE_MANAGEMENT`, `GUARDRAIL_COST_EFFICIENCY`, `GUARDRAIL_ENCRYPTION`, `GUARDRAIL_GLOBALIZATION`, `GUARDRAIL_IAM`, `GUARDRAIL_LOGGING`, `GUARDRAIL_MODULE_INPUTS`, `GUARDRAIL_PRIVACY_COMPLIANCE`, `GUARDRAIL_RELIABILITY`, `GUARDRAIL_STORAGE_AND_SCALE`.", Required: true, Validators: []validator.String{ stringvalidator.OneOf( @@ -132,7 +130,7 @@ func (r *GuardrailResource) Schema( }, }, "state": schema.StringAttribute{ - MarkdownDescription: "The state to set the guardrail to. Can be one of `GUARDRAIL_STATE_INACTIVE`, `GUARDRAIL_STATE_EVALUATE_ONLY`, `GUARDRAIL_STATE_ACTIVE`. If not provided state is set to `GUARDRAIL_STATE_ACTIVE`", + MarkdownDescription: "The [state](https://docs.resourcely.io/build/setting-up-guardrails/releasing-guardrails#guardrail-status) of the guardrail. Can be one of `GUARDRAIL_STATE_INACTIVE`, `GUARDRAIL_STATE_EVALUATE_ONLY`, `GUARDRAIL_STATE_ACTIVE`. If not provided state is set to `GUARDRAIL_STATE_ACTIVE`.", Optional: true, Computed: true, Default: stringdefault.StaticString("GUARDRAIL_STATE_ACTIVE"), @@ -145,19 +143,19 @@ func (r *GuardrailResource) Schema( }, }, "content": schema.StringAttribute{ - MarkdownDescription: "The content of the guardrail, written in Resourcely's Really language", + MarkdownDescription: "The guardrail policy written in the [Really policy language](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). Must specify exactly one of `content` or `guardrail_template_series_id`.", Optional: true, Computed: true, }, "guardrail_template_series_id": schema.StringAttribute{ - MarkdownDescription: "The series id of the guardrail template used to render the policies", + MarkdownDescription: "The series id of the guardrail template used to render the policy. Must specify exactly one of `guardrail_template_series_id` or `content`.", Optional: true, Computed: true, Default: stringdefault.StaticString(""), }, "guardrail_template_inputs": schema.StringAttribute{ CustomType: jsontypes.NormalizedType{}, - MarkdownDescription: "A JSON encoding of values for the guardrail template inputs.\n\nExample: `guardrail_template_inputs = jsonencode({inputOne = \"value one\"})`", + MarkdownDescription: "A JSON encoding of values for the guardrail template inputs. Required if `guardrail_template_series_id` is used. Example: `guardrail_template_inputs = jsonencode({inputOne = \"value one\"})`", Optional: true, }, }, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 48bcdf7..ac5f22e 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -51,7 +51,7 @@ func (p *ResourcelyProvider) Schema(ctx context.Context, req provider.SchemaRequ Description: "Configure Resourcely resources", Attributes: map[string]schema.Attribute{ "host": schema.StringAttribute{ - MarkdownDescription: "URI for Resourcely API.", + MarkdownDescription: "URI for Resourcely API. Defaults to 'https://api.resourcely.io'.", Optional: true, }, "auth_token": schema.StringAttribute{ diff --git a/templates/data-sources/blueprint.md.tmpl b/templates/data-sources/blueprint.md.tmpl new file mode 100644 index 0000000..c0da8da --- /dev/null +++ b/templates/data-sources/blueprint.md.tmpl @@ -0,0 +1,14 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +{{ tffile .ExampleFile }} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/data-sources/context_question.md.tmpl b/templates/data-sources/context_question.md.tmpl new file mode 100644 index 0000000..c0da8da --- /dev/null +++ b/templates/data-sources/context_question.md.tmpl @@ -0,0 +1,14 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +{{ tffile .ExampleFile }} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/data-sources/global_value.md.tmpl b/templates/data-sources/global_value.md.tmpl new file mode 100644 index 0000000..c0da8da --- /dev/null +++ b/templates/data-sources/global_value.md.tmpl @@ -0,0 +1,14 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +{{ tffile .ExampleFile }} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/data-sources/guardrail.md.tmpl b/templates/data-sources/guardrail.md.tmpl new file mode 100644 index 0000000..c0da8da --- /dev/null +++ b/templates/data-sources/guardrail.md.tmpl @@ -0,0 +1,14 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +{{ tffile .ExampleFile }} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl new file mode 100644 index 0000000..9dbd78f --- /dev/null +++ b/templates/index.md.tmpl @@ -0,0 +1,49 @@ +--- +page_title: "Provider: resourcely" +--- + +# {{ .ProviderShortName | upper }} Provider + +The Resourcely provider is used to manage Resourcely blueprint, +guardrails, global values, and more through Terraform. The provider +needs to be configured with the proper credentials before it can be +used. + +## Example Usage + +Configure the Resourcely provider. + +{{tffile "examples/provider/provider.tf"}} + +Create a guardrail. + +{{tffile "examples/resources/resourcely_guardrail/resource.tf"}} + +Create a blueprint. + +{{tffile "examples/resources/resourcely_blueprint/resource.tf"}} + +## Authentication and Configuration + +The provider requires a Resourcely API token to authenticate. It +expects the token to be provided through the `RESOURCELY_AUTH_TOKEN` +environment variable. Configure your Terraform runner to supply this +variable. + +You can generate the token from the [Resourcely Settings +page](https://portal.resourcely.io/settings/generate-api-token). Choose +the "Terraform Provider" role. + +You can also supply the token directly in the provider block. Ensure +that token is securely stored in a secret management system. Do not +hardcode it in the provider block. + +{{tffile "examples/provider/provider_with_auth_token.tf"}} + +If your organization uses multiple tenants within Resourcely, you can +configure the `allowed_tenants` in the provider block to prevent +accidently mixing API keys between tenants. + +{{tffile "examples/provider/provider_with_allowed_tenants.tf"}} + +{{ .SchemaMarkdown | trimspace }} diff --git a/templates/resources/blueprint.md.tmpl b/templates/resources/blueprint.md.tmpl new file mode 100644 index 0000000..7f22faa --- /dev/null +++ b/templates/resources/blueprint.md.tmpl @@ -0,0 +1,20 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +{{ tffile .ExampleFile }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +A blueprint can be imported using its series_id. + +{{codefile "shell" .ImportFile }} diff --git a/templates/resources/context_question.md.tmpl b/templates/resources/context_question.md.tmpl new file mode 100644 index 0000000..eb869ca --- /dev/null +++ b/templates/resources/context_question.md.tmpl @@ -0,0 +1,31 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +Create a simple, multi-select context question. + +{{ tffile .ExampleFile }} + + +Context questions with "text" type can restrict the allowed answer formats. For example, create a context question that asks for an email address. + +{{ tffile "examples/resources/resourcely_context_question/resource_with_email_format.tf" }} + +Or, create a context question that asks for a project code comprising 6 hex digits. + +{{ tffile "examples/resources/resourcely_context_question/resource_with_regex_format.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +A blueprint can be imported using its series_id. + +{{codefile "shell" .ImportFile }} diff --git a/templates/resources/global_value.md.tmpl b/templates/resources/global_value.md.tmpl new file mode 100644 index 0000000..7754ea5 --- /dev/null +++ b/templates/resources/global_value.md.tmpl @@ -0,0 +1,29 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +Create a global value containing all the departments within the company. + +{{ tffile .ExampleFile }} + +Create a global value listing the AMI attributes for three Linux +distributions. Then create a blueprint that creates an instance, +querying for the AMI using the attributes of the selected +distribution. + +{{ tffile "examples/resources/resourcely_global_value/resource_with_object_values.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +A global value can be imported using its series_id. + +{{codefile "shell" .ImportFile }} diff --git a/templates/resources/guardrail.md.tmpl b/templates/resources/guardrail.md.tmpl new file mode 100644 index 0000000..f260ec0 --- /dev/null +++ b/templates/resources/guardrail.md.tmpl @@ -0,0 +1,29 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +--- + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +## Example Usage + +Create a guardrail using the [Really policy langauge](https://docs.resourcely.io/build/setting-up-guardrails/authoring-your-own-guardrails). + +{{ tffile .ExampleFile }} + +This resource also supports creating a guardrail from a Resourcely +Guardrail Template. Instead of specifying the `content`, specify the +`guardrail_template_series_id` and `guardrail_template_inputs` +instead. + +{{ tffile "examples/resources/resourcely_guardrail/resource_with_template.tf" }} + +{{ .SchemaMarkdown | trimspace }} + +## Import + +A guardrail can be imported using its series_id. + +{{codefile "shell" .ImportFile }}