Skip to content

Commit

Permalink
feat: initial release
Browse files Browse the repository at this point in the history
This initial release provides a basic working module for Terraform Cloud/Enterprise Workspace.

What provides:
- Workspace
- Workspace variables
- Workspace run triggers

Not yet implemented:
- Workspace Notifications
  • Loading branch information
davcen authored Apr 28, 2022
1 parent 7efa2c6 commit d62082f
Show file tree
Hide file tree
Showing 11 changed files with 597 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,6 @@ override.tf.json

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Terraform Provider lock file
.terraform.lock.hcl
29 changes: 29 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.68.1 # Get the latest from: https://github.com/antonbabenko/pre-commit-terraform/releases
hooks:
- id: terraform_fmt
- id: terraform_docs
args:
- '--args=--lockfile=false'
- id: terraform_validate
- id: terraform_tflint
args:
- '--args=--only=terraform_deprecated_interpolation'
- '--args=--only=terraform_deprecated_index'
- '--args=--only=terraform_unused_declarations'
- '--args=--only=terraform_comment_syntax'
- '--args=--only=terraform_documented_outputs'
- '--args=--only=terraform_documented_variables'
- '--args=--only=terraform_typed_variables'
- '--args=--only=terraform_module_pinned_source'
- '--args=--only=terraform_naming_convention'
- '--args=--only=terraform_required_version'
- '--args=--only=terraform_required_providers'
- '--args=--only=terraform_standard_module_structure'
- '--args=--only=terraform_workspace_remote'
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.2.0
hooks:
- id: check-merge-conflict
- id: end-of-file-fixer
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,69 @@
# terraform-tfe-workspace
Terraform module to provision and manage Terraform Cloud workspaces

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 0.14.0 |
| <a name="requirement_tfe"></a> [tfe](#requirement\_tfe) | ~> 0.31.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_tfe"></a> [tfe](#provider\_tfe) | ~> 0.31.0 |

## Modules

No modules.

## Resources

| Name | Type |
|------|------|
| [tfe_run_trigger.this](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs/resources/run_trigger) | resource |
| [tfe_variable.this](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs/resources/variable) | resource |
| [tfe_workspace.this](https://registry.terraform.io/providers/hashicorp/tfe/latest/docs/resources/workspace) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_allow_destroy_plan"></a> [allow\_destroy\_plan](#input\_allow\_destroy\_plan) | (Optional) Whether destroy plans can be queued on the workspace | `bool` | `false` | no |
| <a name="input_auto_apply"></a> [auto\_apply](#input\_auto\_apply) | (Optional) Whether to automatically apply changes when a Terraform plan is successful | `bool` | `false` | no |
| <a name="input_description"></a> [description](#input\_description) | (Optional) A description for the workspace | `string` | `""` | no |
| <a name="input_environment_sensitive_variables"></a> [environment\_sensitive\_variables](#input\_environment\_sensitive\_variables) | (Optional) Map of sensitive variables of 'environment' category used in the workspace<br><br> Item syntax:<br> {<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br> } | `map(any)` | `{}` | no |
| <a name="input_environment_variables"></a> [environment\_variables](#input\_environment\_variables) | (Optional) Map of variables of 'environment' category used in the workspace<br><br> Item syntax:<br> {<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br> } | `map(any)` | `{}` | no |
| <a name="input_execution_mode"></a> [execution\_mode](#input\_execution\_mode) | (Optional) Which execution mode to use | `string` | `"remote"` | no |
| <a name="input_file_triggers_enabled"></a> [file\_triggers\_enabled](#input\_file\_triggers\_enabled) | (Optional) Whether to filter runs based on the changed files in a VCS push | `bool` | `true` | no |
| <a name="input_global_remote_state"></a> [global\_remote\_state](#input\_global\_remote\_state) | (Optional) Whether the workspace allows all workspaces in the organization to access its state data during runs | `bool` | `false` | no |
| <a name="input_name"></a> [name](#input\_name) | (Required) Name of the workspace | `string` | n/a | yes |
| <a name="input_oauth_token_id"></a> [oauth\_token\_id](#input\_oauth\_token\_id) | (Optional) The token ID of the VCS connection to use | `string` | `""` | no |
| <a name="input_organization"></a> [organization](#input\_organization) | (Required) Name of the organization | `string` | n/a | yes |
| <a name="input_queue_all_runs"></a> [queue\_all\_runs](#input\_queue\_all\_runs) | (Optional) Whether the workspace should start automatically performing runs immediately after its creation | `bool` | `true` | no |
| <a name="input_remote_state_consumer_ids"></a> [remote\_state\_consumer\_ids](#input\_remote\_state\_consumer\_ids) | (Optional) The set of workspace IDs set as explicit remote state consumers for the given workspace | `list(string)` | `[]` | no |
| <a name="input_run_triggers"></a> [run\_triggers](#input\_run\_triggers) | List of source workspaces IDs that trigger runs in this workspace | `list(string)` | `[]` | no |
| <a name="input_speculative_enabled"></a> [speculative\_enabled](#input\_speculative\_enabled) | (Optional) Whether this workspace allows speculative plans | `bool` | `true` | no |
| <a name="input_ssh_key_id"></a> [ssh\_key\_id](#input\_ssh\_key\_id) | (Optional) The ID of an SSH key to assign to the workspace | `string` | `null` | no |
| <a name="input_structured_run_output_enabled"></a> [structured\_run\_output\_enabled](#input\_structured\_run\_output\_enabled) | (Optional) Whether this workspace should show output from Terraform runs using the enhanced UI when available | `bool` | `true` | no |
| <a name="input_tag_names"></a> [tag\_names](#input\_tag\_names) | (Optional) A list of tag names for this workspace | `list(string)` | `[]` | no |
| <a name="input_terraform_hcl_sensitive_variables"></a> [terraform\_hcl\_sensitive\_variables](#input\_terraform\_hcl\_sensitive\_variables) | (Optional) Map of sensitive variables in HCL format of 'Terraform' category used in the workspace<br><br> Item syntax:<br> {<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br> }<br><br>NOTE: you can specifies values in HCL format directly, like this:<br><br> {<br> variable\_list = ["item1","item2"]<br><br> variable\_map = {<br> key1 = value1<br> key2 = value2<br> }<br> } | `any` | `{}` | no |
| <a name="input_terraform_hcl_variables"></a> [terraform\_hcl\_variables](#input\_terraform\_hcl\_variables) | (Optional) Map of variables in HCL format of 'Terraform' category used in the workspace<br><br> Item syntax:<br> {<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br> }<br><br>NOTE: you can specifies values in HCL format directly, like this:<br><br> {<br> variable\_list = ["item1","item2"]<br><br> variable\_map = {<br> key1 = value1<br> key2 = value2<br> }<br> }<br>} | `any` | `{}` | no |
| <a name="input_terraform_sensitive_variables"></a> [terraform\_sensitive\_variables](#input\_terraform\_sensitive\_variables) | (Optional) Map of sensitive variables of 'Terraform' category used in the workspace<br><br>Item syntax:<br>{<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br>} | `map(any)` | `{}` | no |
| <a name="input_terraform_variables"></a> [terraform\_variables](#input\_terraform\_variables) | (Optional) Map of variables of 'Terraform' category used in the workspace<br><br> Item syntax:<br> {<br> variable1\_name = value1<br> variable2\_name = value2<br> ...<br> } | `map(any)` | `{}` | no |
| <a name="input_terraform_version"></a> [terraform\_version](#input\_terraform\_version) | (Required) The version of Terraform to use for this workspace | `string` | n/a | yes |
| <a name="input_trigger_prefixes"></a> [trigger\_prefixes](#input\_trigger\_prefixes) | (Optional) List of repository-root-relative paths which describe all locations to be tracked for changes | `list(string)` | `[]` | no |
| <a name="input_variables_descriptions"></a> [variables\_descriptions](#input\_variables\_descriptions) | (Optional) Map of descriptions applied to workspace variables<br><br> Item syntax:<br> {<br> variable1\_name = "description"<br> variable2\_name = "description"<br> ...<br> } | `map(string)` | `{}` | no |
| <a name="input_vcs_repository_branch"></a> [vcs\_repository\_branch](#input\_vcs\_repository\_branch) | (Optional) The repository branch that Terraform will execute from | `string` | `""` | no |
| <a name="input_vcs_repository_identifier"></a> [vcs\_repository\_identifier](#input\_vcs\_repository\_identifier) | (Optional) A reference to your VCS repository in the format <organization>/<repository> where <organization> and <repository> refer to the organization and repository in your VCS provider. The format for Azure DevOps is //\_git/ | `string` | `""` | no |
| <a name="input_vcs_repository_ingress_submodules"></a> [vcs\_repository\_ingress\_submodules](#input\_vcs\_repository\_ingress\_submodules) | (Optional) Whether submodules should be fetched when cloning the VCS repository | `bool` | `false` | no |
| <a name="input_working_directory"></a> [working\_directory](#input\_working\_directory) | (Optional) A relative path that Terraform will execute within | `string` | `null` | no |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_id"></a> [id](#output\_id) | The workspace ID |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
57 changes: 57 additions & 0 deletions examples/simple-workspace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# terraform-tfe-workspace

This example will manage a simple Terraform Cloud/Enterprise workspace without
connecting it to the GitHub repository.

## Usage

To run this example, you need to execute the following commands:

```shell
$ terraform init
$ terraform plan
$ terraform apply
```

:memo: **Note:** You will need a Terraform Cloud/Enterprise API token for authentication.
You'll be prompted to insert it to provide a value for "tfc_token" variable.
See [here](https://www.terraform.io/cloud-docs/users-teams-organizations/api-tokens)
for further information.

:warning: **Warning:** This example may create resources that cost money. Execute the command
`terraform destroy` when the resources are no longer needed.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | ~> 1.1.0 |
| <a name="requirement_tfe"></a> [tfe](#requirement\_tfe) | ~>0.31.0 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_simple_workspace"></a> [simple\_workspace](#module\_simple\_workspace) | ../../ | n/a |

## Resources

No resources.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_tfc_token"></a> [tfc\_token](#input\_tfc\_token) | Token for Terraform Cloud Authentication | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_workspace_id"></a> [workspace\_id](#output\_workspace\_id) | The ID of Terraform Cloud/Enterprise workspace |
<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
35 changes: 35 additions & 0 deletions examples/simple-workspace/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
terraform {
required_version = "~> 1.1.0"

required_providers {
tfe = {
source = "hashicorp/tfe"
version = "~>0.31.0"
}
}
}

provider "tfe" {
token = var.tfc_token
}

module "simple_workspace" {
source = "../../"

name = "simple-workspace"
organization = "myorg"
description = "A simple Terraform Cloud/Enterprise workspace"
terraform_version = "1.1.9"

terraform_variables = {
string_variable = "stringvalue"
number_variable = 1
bool_variable = true
}

variables_descriptions = {
string_variable = "A variable containing a value in string format"
number_variable = "A variable containing a value in number format"
bool_variable = "A variable containing a value in boolean format"
}
}
4 changes: 4 additions & 0 deletions examples/simple-workspace/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "workspace_id" {
description = "The ID of Terraform Cloud/Enterprise workspace"
value = module.simple_workspace.id
}
5 changes: 5 additions & 0 deletions examples/simple-workspace/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "tfc_token" {
description = "Token for Terraform Cloud Authentication"
type = string
sensitive = true
}
115 changes: 115 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
locals {
terraform_variables = { for k, v in var.terraform_variables : k =>
{
value = v
category = "terraform"
description = lookup(var.variables_descriptions, k, null)
}
}

terraform_hcl_variables = { for k, v in var.terraform_hcl_variables : k =>
{
#NOTE: using @osterman trick https://github.com/hashicorp/terraform-provider-tfe/issues/188#issuecomment-700212045
value = replace(jsonencode(v), "/(\".*?\"):/", "$1 = ")
category = "terraform"
hcl = true
description = lookup(var.variables_descriptions, k, null)
}
}

terraform_sensitive_variables = { for k, v in var.terraform_sensitive_variables : k =>
{
value = v
category = "terraform"
description = lookup(var.variables_descriptions, k, null)
sensitive = true
}
}

terraform_hcl_sensitive_variables = { for k, v in var.terraform_hcl_sensitive_variables : k =>
{
#NOTE: using @osterman trick https://github.com/hashicorp/terraform-provider-tfe/issues/188#issuecomment-700212045
value = replace(jsonencode(v), "/(\".*?\"):/", "$1 = ")
category = "terraform"
description = lookup(var.variables_descriptions, k, null)
hcl = true
sensitive = true
}
}

environment_variables = { for k, v in var.environment_variables : k =>
{
value = v
category = "env"
description = lookup(var.variables_descriptions, k, null)
}
}

environment_sensitive_variables = { for k, v in var.environment_sensitive_variables : k =>
{
value = v
category = "env"
description = lookup(var.variables_descriptions, k, null)
sensitive = true
}
}

all_variables = merge(
local.terraform_variables,
local.terraform_hcl_variables,
local.terraform_sensitive_variables,
local.terraform_hcl_sensitive_variables,
local.environment_variables,
local.environment_sensitive_variables
)
}

resource "tfe_workspace" "this" {
name = var.name
organization = var.organization
description = var.description
allow_destroy_plan = var.allow_destroy_plan
auto_apply = var.auto_apply
execution_mode = var.execution_mode
file_triggers_enabled = var.file_triggers_enabled
global_remote_state = var.global_remote_state
remote_state_consumer_ids = var.remote_state_consumer_ids
queue_all_runs = var.queue_all_runs
speculative_enabled = var.speculative_enabled
structured_run_output_enabled = var.structured_run_output_enabled
ssh_key_id = var.ssh_key_id
terraform_version = var.terraform_version
trigger_prefixes = var.trigger_prefixes
tag_names = var.tag_names
working_directory = var.working_directory

dynamic "vcs_repo" {
for_each = length(var.vcs_repository_identifier) > 0 && length(var.oauth_token_id) > 0 ? [1] : []

content {
identifier = var.vcs_repository_identifier
branch = var.vcs_repository_branch
ingress_submodules = var.vcs_repository_ingress_submodules
oauth_token_id = var.oauth_token_id
}
}
}

resource "tfe_variable" "this" {
for_each = local.all_variables

key = each.key
value = each.value.value
hcl = try(each.value.hcl, null)
category = each.value.category
description = try(each.value.description, null)
sensitive = try(each.value.sensitive, false)
workspace_id = tfe_workspace.this.id
}

resource "tfe_run_trigger" "this" {
count = length(var.run_triggers)

workspace_id = tfe_workspace.this.id
sourceable_id = var.run_triggers[count.index]
}
4 changes: 4 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "id" {
description = "The workspace ID"
value = tfe_workspace.this.id
}
Loading

0 comments on commit d62082f

Please sign in to comment.