Skip to content

Commit

Permalink
refactor how workspacename names arg matches
Browse files Browse the repository at this point in the history
  • Loading branch information
laurenolivia committed Nov 30, 2022
1 parent 50a4204 commit 632be83
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Unreleased

FEATURES:
* d/tfe_workspace_ids: Add support for filtering workspace names with partial matching using `*` ([#698](https://github.com/hashicorp/terraform-provider-tfe/pull/698))
* r/tfe_workspace: Add preemptive check for resources under management when `force_delete` attribute is false ([#699](https://github.com/hashicorp/terraform-provider-tfe/pull/699))
* r/tfe_policy: Add OPA support for policies. `tfe_policy` is a new resource that supports both Sentinel as well as OPA policies. `tfe_sentinel_policy` now includes a deprecation warning. ([#690](https://github.com/hashicorp/terraform-provider-tfe/pull/690))
* r/tfe_policy_set: Add OPA support for policy sets. ([#691](https://github.com/hashicorp/terraform-provider-tfe/pull/691))
Expand Down
36 changes: 33 additions & 3 deletions tfe/data_source_workspace_ids.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,38 @@ func dataSourceTFEWorkspaceIDs() *schema.Resource {
}
}

func includedByName(names map[string]bool, workspaceName string) bool {
for name := range names {
switch {
case len(name) == 0:
continue
case !strings.HasPrefix(name, "*") && !strings.HasSuffix(name, "*"):
if strings.Contains(workspaceName, name) {
return true
}
case strings.HasPrefix(name, "*") && strings.HasSuffix(name, "*"):
if len(name) == 1 {
return true
}
x := name[1 : len(name)-1]
if strings.Contains(workspaceName, x) {
return true
}
case strings.HasPrefix(name, "*"):
x := name[1:]
if strings.HasSuffix(workspaceName, x) {
return true
}
case strings.HasSuffix(name, "*"):
x := name[:len(name)-1]
if strings.HasPrefix(workspaceName, x) {
return true
}
}
}
return false
}

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

Expand All @@ -68,7 +100,6 @@ func dataSourceTFEWorkspaceIDsRead(d *schema.ResourceData, meta interface{}) err
id += name.(string)
names[name.(string)] = true
}
isWildcard := names["*"]

// Create two maps to hold the results.
fullNames := make(map[string]string, len(names))
Expand Down Expand Up @@ -115,7 +146,6 @@ func dataSourceTFEWorkspaceIDsRead(d *schema.ResourceData, meta interface{}) err
}

for _, w := range wl.Items {
nameIncluded := isWildcard || names[w.Name]
// fallback for tfe instances that don't yet support exclude-tags
hasExcludedTag := false
for _, tag := range w.TagNames {
Expand All @@ -124,7 +154,7 @@ func dataSourceTFEWorkspaceIDsRead(d *schema.ResourceData, meta interface{}) err
break
}
}
if (hasOnlyTags || nameIncluded) && !hasExcludedTag {
if (hasOnlyTags || includedByName(names, w.Name)) && !hasExcludedTag {
fullNames[w.Name] = organization + "/" + w.Name
ids[w.Name] = w.ID
}
Expand Down
146 changes: 142 additions & 4 deletions tfe/data_source_workspace_ids_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestAccTFEWorkspaceIDsDataSource_wildcard(t *testing.T) {
CheckDestroy: testAccCheckTFEWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt),
Config: testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt, "*"),
Check: resource.ComposeAggregateTestCheckFunc(
// names attribute
resource.TestCheckResourceAttr(
Expand Down Expand Up @@ -122,6 +122,144 @@ func TestAccTFEWorkspaceIDsDataSource_wildcard(t *testing.T) {
})
}

func TestAccTFEWorkspaceIDsDataSource_prefixWildcard(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
fooWorkspaceName := fmt.Sprintf("*-foo-%d", rInt)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt, fooWorkspaceName),
Check: resource.ComposeAggregateTestCheckFunc(
// names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.#", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.0", fooWorkspaceName),

// organization attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "organization", orgName),

// full_names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "full_names.%", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar",
fmt.Sprintf("full_names.workspace-foo-%d", rInt),
fmt.Sprintf("tst-terraform-%d/workspace-foo-%d", rInt, rInt),
),

// ids attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "ids.%", "1"),
resource.TestCheckResourceAttrSet(
"data.tfe_workspace_ids.foobar", fmt.Sprintf("ids.workspace-foo-%d", rInt)),

// id attribute
resource.TestCheckResourceAttrSet("data.tfe_workspace_ids.foobar", "id"),
),
},
},
})
}

func TestAccTFEWorkspaceIDsDataSource_suffixWildcard(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
fooWorkspaceName := "workspace-foo-*"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt, fooWorkspaceName),
Check: resource.ComposeAggregateTestCheckFunc(
// names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.#", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.0", fooWorkspaceName),

// organization attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "organization", orgName),

// full_names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "full_names.%", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar",
fmt.Sprintf("full_names.workspace-foo-%d", rInt),
fmt.Sprintf("tst-terraform-%d/workspace-foo-%d", rInt, rInt),
),

// ids attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "ids.%", "1"),
resource.TestCheckResourceAttrSet(
"data.tfe_workspace_ids.foobar", fmt.Sprintf("ids.workspace-foo-%d", rInt)),

// id attribute
resource.TestCheckResourceAttrSet("data.tfe_workspace_ids.foobar", "id"),
),
},
},
})
}

func TestAccTFEWorkspaceIDsDataSource_substringWildcard(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
fooWorkspaceName := "*-foo-*"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt, fooWorkspaceName),
Check: resource.ComposeAggregateTestCheckFunc(
// names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.#", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "names.0", fooWorkspaceName),

// organization attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "organization", orgName),

// full_names attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "full_names.%", "1"),
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar",
fmt.Sprintf("full_names.workspace-foo-%d", rInt),
fmt.Sprintf("tst-terraform-%d/workspace-foo-%d", rInt, rInt),
),

// ids attribute
resource.TestCheckResourceAttr(
"data.tfe_workspace_ids.foobar", "ids.%", "1"),
resource.TestCheckResourceAttrSet(
"data.tfe_workspace_ids.foobar", fmt.Sprintf("ids.workspace-foo-%d", rInt)),

// id attribute
resource.TestCheckResourceAttrSet("data.tfe_workspace_ids.foobar", "id"),
),
},
},
})
}

func TestAccTFEWorkspaceIDsDataSource_tags(t *testing.T) {
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
orgName := fmt.Sprintf("tst-terraform-%d", rInt)
Expand Down Expand Up @@ -357,7 +495,7 @@ data "tfe_workspace_ids" "foobar" {
}`, rInt, rInt, rInt, rInt)
}

func testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt int) string {
func testAccTFEWorkspaceIDsDataSourceConfig_wildcard(rInt int, wildcardName string) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
Expand All @@ -380,14 +518,14 @@ resource "tfe_workspace" "dummy" {
}
data "tfe_workspace_ids" "foobar" {
names = ["*"]
names = ["%s"]
organization = tfe_workspace.dummy.organization
depends_on = [
tfe_workspace.foo,
tfe_workspace.bar,
tfe_workspace.dummy
]
}`, rInt, rInt, rInt, rInt)
}`, rInt, rInt, rInt, rInt, wildcardName)
}

func testAccTFEWorkspaceIDsDataSourceConfig_tags(rInt int) string {
Expand Down
4 changes: 2 additions & 2 deletions website/docs/d/workspace_ids.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ data "tfe_workspace_ids" "prod-only" {
The following arguments are supported. At least one of `names` or `tag_names` must be present. Both can be used together.

* `names` - (Optional) A list of workspace names to search for. Names that don't
match a real workspace will be omitted from the results, but are not an error.
match a valid workspace will be omitted from the results, but are not an error.

To select _all_ workspaces for an organization, provide a list with a single
asterisk, like `["*"]`. No other use of wildcards is supported.
asterisk, like `["*"]`. The asterisk also supports partial matching on prefix and/or suffix, like `[*-prod]`, `[test-*]`, `[*dev*]`.
* `tag_names` - (Optional) A list of tag names to search for.
* `exclude_tags` - (Optional) A list of tag names to exclude when searching.
* `organization` - (Required) Name of the organization.
Expand Down

0 comments on commit 632be83

Please sign in to comment.