Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/variables data source #369

Merged
merged 21 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 178 additions & 0 deletions tfe/data_source_variables.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package tfe

import (
"fmt"
"log"

tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func dataSourceTFEWorkspaceVariables() *schema.Resource {
return &schema.Resource{
Read: dataSourceVariableRead,

Schema: map[string]*schema.Schema{
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
"variables": &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this schema is defined 3x, it might be nice to just extract it once and reuse it-- I also removed the redundant &schema.Schema declaration

varSchema := map[string]*schema.Schema{
    "id": {
	    Type:     schema.TypeString,
	    Computed: true,
    },
    "name": {
	    Type:     schema.TypeString,
	    Computed: true,
    },
    "value": {
	    Type:      schema.TypeString,
	    Computed:  true,
	    Sensitive: true,
    },
    "category": {
	    Type:     schema.TypeString,
	    Computed: true,
    },
    "hcl": {
	    Type:     schema.TypeBool,
	    Computed: true,
    },
    "sensitive": {
	    Type:     schema.TypeBool,
	    Computed: true,
    },
}

"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"category": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"hcl": &schema.Schema{
Type: schema.TypeBool,
Computed: true,
},
},
},
},
"terraform": &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"category": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"hcl": &schema.Schema{
Type: schema.TypeBool,
Computed: true,
},
},
},
},
"environment": &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"name": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"value": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"category": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"hcl": &schema.Schema{
Type: schema.TypeBool,
Computed: true,
},
},
},
},
"workspace_id": {
Type: schema.TypeString,
Required: true,
},
},
}
}

func dataSourceVariableRead(d *schema.ResourceData, meta interface{}) error {
tfeClient := meta.(*tfe.Client)

// Get the name and organization.
workspace_id := d.Get("workspace_id").(string)
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved

log.Printf("[DEBUG] Read configuration of workspace: %s", workspace_id)

totalVariables := make([]interface{}, 0)
totalEnvVariables := make([]interface{}, 0)
totalTerraformVariables := make([]interface{}, 0)

options := tfe.VariableListOptions{}

for {
variableList, err := tfeClient.Variables.List(ctx, workspace_id, options)
if err != nil {
return fmt.Errorf("Error retrieving variable list: %v", err)
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
}
terraformVars := make([]interface{}, 0)
envVars := make([]interface{}, 0)
for _, variable := range variableList.Items {
if variable.Category == "terraform" {
result := make(map[string]interface{})
result["id"] = variable.ID
result["name"] = variable.Key
result["category"] = variable.Category
result["hcl"] = variable.HCL
if variable.Sensitive != true {
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
result["value"] = variable.Value
} else {
result["value"] = "***"
}

terraformVars = append(terraformVars, result)
} else if variable.Category == "env" {
result := make(map[string]interface{})
result["id"] = variable.ID
result["name"] = variable.Key
result["category"] = variable.Category
result["hcl"] = variable.HCL
if variable.Sensitive != true {
result["value"] = variable.Value
} else {
result["value"] = "***"
}

envVars = append(envVars, result)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these two conditions are identical, you can use the condition to figure out which slice to append result to:

I would also add "sensitive" to the schema and set that:

Suggested change
if variable.Category == "terraform" {
result := make(map[string]interface{})
result["id"] = variable.ID
result["name"] = variable.Key
result["category"] = variable.Category
result["hcl"] = variable.HCL
if variable.Sensitive != true {
result["value"] = variable.Value
} else {
result["value"] = "***"
}
terraformVars = append(terraformVars, result)
} else if variable.Category == "env" {
result := make(map[string]interface{})
result["id"] = variable.ID
result["name"] = variable.Key
result["category"] = variable.Category
result["hcl"] = variable.HCL
if variable.Sensitive != true {
result["value"] = variable.Value
} else {
result["value"] = "***"
}
envVars = append(envVars, result)
}
result := make(map[string]interface{})
result["id"] = variable.ID
result["name"] = variable.Key
result["category"] = variable.Category
result["hcl"] = variable.HCL
result["sensitive"] = variable.Sensitive
result["value"] = variable.Value
if variable.Category == "terraform" {
terraformVars = append(terraformVars, result)
} else if variable.Category == "env" {
envVars = append(envVars, result)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

big commit incoming solving also this

}
totalVariables = append(totalVariables, terraformVars...)
totalVariables = append(totalVariables, envVars...)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to not interleave pages of terraform and env variables in this collection. At the end, you can just append totalEnvVariables to totalTerraformVariables (see below) so that all the terraform variables come first and all the env variables come after. It also simplifies the code and reduces copying.

Suggested change
totalVariables = append(totalVariables, terraformVars...)
totalVariables = append(totalVariables, envVars...)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

totalEnvVariables = append(totalEnvVariables, envVars...)
totalTerraformVariables = append(totalTerraformVariables, terraformVars...)

// Exit the loop when we've seen all pages.
if variableList.CurrentPage >= variableList.TotalPages {
break
}

// Update the page number to get the next page.
options.PageNumber = variableList.NextPage
}

d.SetId(fmt.Sprintf("variables/%v", workspace_id))
d.Set("variables", totalVariables)
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
d.Set("terraform", totalTerraformVariables)
d.Set("environment", totalEnvVariables)
log.Println(totalVariables)
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
return nil
}
79 changes: 79 additions & 0 deletions tfe/data_source_variables_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package tfe

import (
"fmt"
"math/rand"
"testing"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccTFEVariablesDataSource_basic(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccTFEVariablesDataSourceConfig_basic(rInt),
Check: resource.ComposeAggregateTestCheckFunc(
// variables attribute
resource.TestCheckResourceAttrSet("data.tfe_variables.foobar", "id"),
resource.TestCheckOutput("variables", "foo"),
resource.TestCheckOutput("environment", "foo"),
resource.TestCheckOutput("terraform", "foo"),
),
},
},
},
)
}

func testAccTFEVariablesDataSourceConfig_basic(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "org-%d"
email = "admin@company.com"
}

resource "tfe_workspace" "foobar" {
name = "workspace-foo-%d"
organization = tfe_organization.foobar.id
}

resource "tfe_variable" "terrbar" {
key = "foo"
value = "bar"
category = "terraform"
workspace_id = tfe_workspace.foobar.id
}

resource "tfe_variable" "envbar" {
key = "foo"
value = "bar"
category = "env"
workspace_id = tfe_workspace.foobar.id
}

data "tfe_variables" "foobar" {
workspace_id = tfe_workspace.foobar.id
depends_on = [
tfe_variable.terrbar,
tfe_variable.envbar
]
}

output "variables" {
value = data.tfe_variables.foobar.variables[0]["name"]
}

output "environment" {
value = data.tfe_variables.foobar.environment[0]["name"]
}

output "terraform" {
value = data.tfe_variables.foobar.terraform[0]["name"]
}`, rInt, rInt)
}
1 change: 1 addition & 0 deletions tfe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ func Provider() *schema.Provider {
"tfe_team_access": dataSourceTFETeamAccess(),
"tfe_workspace": dataSourceTFEWorkspace(),
"tfe_workspace_ids": dataSourceTFEWorkspaceIDs(),
"tfe_variables": dataSourceTFEWorkspaceVariables(),
},

ResourcesMap: map[string]*schema.Resource{
Expand Down
44 changes: 44 additions & 0 deletions website/docs/d/variables.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
layout: "tfe"
page_title: "Terraform Enterprise: tfe_variables"
sidebar_current: "docs-datasource-tfe-variables-x"
description: |-
Get information on a workspace variables.
---

# Data Source: tfe_variables

Use this data source to get information about a workspace variables.
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved

## Example Usage

```hcl
data "tfe_workspace" "test" {
name = "my-workspace-name"
organization = "my-org-name"
}

data "tfe_variables" "test" {
worspace_id = data.tfe_workspace.test.id
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
}
```

## Argument Reference

The following arguments are supported:

* `worspace_id` - (Required) Id of the workspace.
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved

## Attributes Reference

* `variables` - List containing variables configured on the workspace
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
* `terraform` - List containing terraform category variables configured on the workspace
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
* `environment` - List containing environment category variables configured on the workspace
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved

The `variables, terraform and environment` blocks contains:

* `id` - The variable Id
* `name` - The variable Key name
* `value` - The variable value if the variable it's marked as sensitive it shows "\*\*\*"
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved
* `category` - The category of the variable (terraform or environment)
* `hcl` - If the variable is marked as HCL or not
kilwa0 marked this conversation as resolved.
Show resolved Hide resolved