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

Nf/mar23 temp cikick 826 #828

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ FEATURES:
* **New Data Source**: d/tfe_organization_tags is a new data source to allow reading all workspace tags within an organization, by @rhughes1 ([#773](https://github.com/hashicorp/terraform-provider-tfe/pull/773))
* r/workspace, d/workspace: Add `source_name` and `source_url` to workspaces ([#527](https://github.com/hashicorp/terraform-provider-tfe/pull/527))
* `r/tfe_team`: Add `read_projects` and `read_workspaces` to the `organization_access` block. ([#796](https://github.com/hashicorp/terraform-provider-tfe/pull/796))
* **New Resource**: `r/tfe_workspace_lock` allows locking workspaces. ([#824](https://github.com/hashicorp/terraform-provider-tfe/pull/824))

ENHANCEMENTS:
* r/tfe_organization_membership: Organization Memberships can now be imported using `<ORGANIZATION NAME>/<USER EMAIL>` ([#715](https://github.com/hashicorp/terraform-provider-tfe/pull/715))
Expand Down
1 change: 1 addition & 0 deletions tfe/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ func Provider() *schema.Provider {
"tfe_variable_set": resourceTFEVariableSet(),
"tfe_workspace_variable_set": resourceTFEWorkspaceVariableSet(),
"tfe_workspace_policy_set": resourceTFEWorkspacePolicySet(),
"tfe_workspace_lock": resourceTFEWorkspaceLock(),
},
ConfigureContextFunc: configure(),
}
Expand Down
96 changes: 96 additions & 0 deletions tfe/resource_tfe_workspace_lock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tfe

import (
"fmt"
"log"

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

func resourceTFEWorkspaceLock() *schema.Resource {
return &schema.Resource{
Create: resourceTFEWorkspaceLockCreate,
Read: resourceTFEWorkspaceLockRead,
Delete: resourceTFEWorkspaceLockDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"workspace_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"reason": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
},
}
}

func resourceTFEWorkspaceLockCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

wID := d.Get("workspace_id").(string)

applyOptions := tfe.WorkspaceLockOptions{}

if v, ok := d.GetOk("reason"); ok {
applyOptions.Reason = tfe.String(v.(string))
}

_, err := config.Client.Workspaces.Lock(ctx, wID, applyOptions)
if err != nil {
return fmt.Errorf(
"Error locking workspace %s: %w", wID, err)
}

d.SetId(wID)

return resourceTFEWorkspaceLockRead(d, meta)
}

func resourceTFEWorkspaceLockRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

wID := d.Id()

log.Printf("[DEBUG] Read configuration of workspace %s", d.Id())
ws, err := config.Client.Workspaces.ReadByID(ctx, wID)

if err != nil {
return fmt.Errorf("Error reading Workspace %s: %w", d.Id(), err)
}

if !ws.Locked {
log.Printf("[DEBUG] Workspace ID %s is no longer locked", d.Id())
d.SetId("")
return nil
}
d.SetId(wID)

return nil
}

func resourceTFEWorkspaceLockDelete(d *schema.ResourceData, meta interface{}) error {
config := meta.(ConfiguredClient)

wID := d.Id()

log.Printf("[DEBUG] Unlock workspace (%s)", wID)

_, err := config.Client.Workspaces.Unlock(ctx, wID)
if err != nil {
return fmt.Errorf(
"Error unlocking workspace %s: %w", wID, err)
}

return nil
}
128 changes: 128 additions & 0 deletions tfe/resource_tfe_workspace_lock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package tfe

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

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

func TestAccTFEWorkspaceLock_basic(t *testing.T) {
workspace := &tfe.Workspace{}
rInt := rand.New(rand.NewSource(time.Now().UnixNano())).Int()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckTFEWorkspaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccTFEWorkspace_lock(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEWorkspaceExists(
"tfe_workspace.foobar", workspace, testAccProvider),
testAccCheckTFEWorkspaceLocked(workspace, true),
testAccCheckTFEWorkspaceLockedID(
"tfe_workspace.foobar", "tfe_workspace_lock.foobar"),
resource.TestCheckResourceAttr(
"tfe_workspace_lock.foobar", "reason", "test"),
),
},
{
Config: testAccTFEWorkspace_unlock(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckTFEWorkspaceExists(
"tfe_workspace.foobar", workspace, testAccProvider),
testAccCheckTFEWorkspaceLocked(workspace, false),
),
},
},
})
}

func testAccCheckTFEWorkspaceLocked(
workspace *tfe.Workspace, locked bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
if workspace.Locked != locked {
return fmt.Errorf("Expected workspaces lock status to be %t but got %t name", locked, workspace.Locked)
}
return nil
}
}

func testAccCheckTFEWorkspaceLockedID(ws, lock string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[ws]
if !ok {
return fmt.Errorf("Not found: %s", ws)
}

wID := rs.Primary.ID

if wID == "" {
return fmt.Errorf("No ID is set")
}

rs, ok = s.RootModule().Resources[lock]
if !ok {
return fmt.Errorf("Not found: %s", ws)
}

if wID != rs.Primary.ID {
return fmt.Errorf("expected lock ID to be workspace ID %s but got %s", wID, rs.Primary.ID)
}
if wID != rs.Primary.Attributes["workspace_id"] {
return fmt.Errorf("expected lock workspace ID to be workspace ID %s but got %s", wID, rs.Primary.Attributes["workspace_id"])
}

return nil
}
}

func testAccTFEWorkspace_lock(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
description = "My favorite workspace!"
allow_destroy_plan = false
auto_apply = true
tag_names = ["fav", "test"]
}

resource "tfe_workspace_lock" "foobar" {
workspace_id = tfe_workspace.foobar.id
reason = "test"
}
`, rInt)
}

func testAccTFEWorkspace_unlock(rInt int) string {
return fmt.Sprintf(`
resource "tfe_organization" "foobar" {
name = "tst-terraform-%d"
email = "[email protected]"
}

resource "tfe_workspace" "foobar" {
name = "workspace-test"
organization = tfe_organization.foobar.id
description = "My favorite workspace!"
allow_destroy_plan = false
auto_apply = true
tag_names = ["fav", "test"]
}
`, rInt)
}
48 changes: 48 additions & 0 deletions website/docs/r/workspace_lock.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
layout: "tfe"
page_title: "Terraform Enterprise: tfe_workspace_lock"
description: |-
Lock Workspace.
---

# tfe_workspace_lock

[Lock](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/settings#locking) a workspace
to prevent any runs from happening. When this resource is detroyed, the workspace is unlocked.

## Example Usage

```hcl
resource "tfe_organization" "test" {
name = "my-org-name"
email = "[email protected]"
}

resource "tfe_workspace" "test" {
name = "my-workspace-name"
organization = tfe_organization.test.name
}

resource "tfe_workspace_lock" "test" {
workspace_id = tfe_workspace.test.id
}
```

## Argument Reference

The following arguments are supported:

* `tfe_workspace` - (Required) Workspace ID
* `reason` - (Optional) Reason for locking the workspace

## Attributes Reference

* `id` - The ID of the Workspace locked.

## Import

Import an existing lock with the workspace ID.

```shell
terraform import tfe_workspace_lock.test ws-12345
```