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

New resource: aws_grafana_workspace_api_key #25286

Merged
merged 51 commits into from
Aug 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ca238f0
wip-For-Internal-AWS-Review
Jun 12, 2022
11a37b9
Grafana new resource aws_grafana_workspace_api_key
Jul 4, 2022
4afdc5b
Grafana new resource aws_grafana_workspace_api_key
Jul 4, 2022
a305e0b
Grafana new resource aws_grafana_workspace_api_key
Jul 4, 2022
f495674
Grafana new resource aws_grafana_workspace_api_key
Jul 4, 2022
849759a
Fix Linting Issues
Jul 4, 2022
aa5c4b2
address change in Provider.Go
Jul 13, 2022
73cff8d
linting fix
Jul 13, 2022
6b6f3bd
incorporate review comments
Jul 25, 2022
0280b59
incorporate review comments
Aug 3, 2022
1d633de
incorporate review comments
Aug 4, 2022
73acdc3
added newly created accttest factories
Aug 4, 2022
67ae57d
Merge branch 'main' into f-aws_grafana_workspace_api_key
meetreks Aug 4, 2022
eef5fc6
Create workspace_api_key.go
bschaatsbergen Aug 18, 2022
6782ffc
Create provider entry for `aws_grafana_workspace_api_key`
bschaatsbergen Aug 18, 2022
662197c
Create grafana_workspace_api_key.html.markdown
bschaatsbergen Aug 18, 2022
dc1c31f
Create 26383.txt
bschaatsbergen Aug 18, 2022
e10eb39
Remove custom timeout
bschaatsbergen Aug 18, 2022
3e32805
Fix casing typoops
bschaatsbergen Aug 18, 2022
d71728b
ForceNew on required attributes
bschaatsbergen Aug 18, 2022
00e65e8
Create workspace_api_key_test.go
bschaatsbergen Aug 18, 2022
4be49dd
Use `EDITOR` as `key_role`
bschaatsbergen Aug 18, 2022
8c75558
pass `rName` to `key_name` and fmt
bschaatsbergen Aug 18, 2022
493888a
Add `testAccWorkspaceApiKey_basic` to `TestAccGrafana_serial`
bschaatsbergen Aug 18, 2022
340061d
post fix test name with `Config`
bschaatsbergen Aug 18, 2022
ddaec83
Update internal/service/grafana/workspace_api_key_test.go
bschaatsbergen Aug 19, 2022
246ce9b
Update internal/service/grafana/workspace_api_key_test.go
bschaatsbergen Aug 19, 2022
5ab5cfe
Update internal/service/grafana/workspace_api_key_test.go
bschaatsbergen Aug 19, 2022
3fe1fec
Update grafana_workspace_api_key.html.markdown
bschaatsbergen Aug 19, 2022
6f4f7ce
fix casing on `API` > `Api`
bschaatsbergen Aug 19, 2022
61230a4
Update casing to match semgrep rule
bschaatsbergen Aug 21, 2022
9ba1c43
Revert "Update casing to match semgrep rule"
ewbankkit Aug 22, 2022
f286d65
Revert "fix casing on `API` > `Api`"
ewbankkit Aug 22, 2022
6ca17f1
Revert "Update grafana_workspace_api_key.html.markdown"
ewbankkit Aug 22, 2022
d3cc2df
Revert "Update internal/service/grafana/workspace_api_key_test.go"
ewbankkit Aug 22, 2022
54da3d1
Revert "Update internal/service/grafana/workspace_api_key_test.go"
ewbankkit Aug 22, 2022
f8539cd
Revert "Update internal/service/grafana/workspace_api_key_test.go"
ewbankkit Aug 22, 2022
18141b5
Revert "post fix test name with `Config`"
ewbankkit Aug 22, 2022
00bf390
Revert "Add `testAccWorkspaceApiKey_basic` to `TestAccGrafana_serial`"
ewbankkit Aug 22, 2022
1df13f7
Revert "pass `rName` to `key_name` and fmt"
ewbankkit Aug 22, 2022
54e75f0
Revert "Use `EDITOR` as `key_role`"
ewbankkit Aug 22, 2022
f80724a
Revert "Create workspace_api_key_test.go"
ewbankkit Aug 22, 2022
fb84a4f
Revert "ForceNew on required attributes"
ewbankkit Aug 22, 2022
de8f06b
Revert "Fix casing typoops"
ewbankkit Aug 22, 2022
3e1d76e
Revert "Remove custom timeout"
ewbankkit Aug 22, 2022
0fd72f5
Revert "Create 26383.txt"
ewbankkit Aug 22, 2022
8d9b427
Revert "Create grafana_workspace_api_key.html.markdown"
ewbankkit Aug 22, 2022
9422d22
Revert "Create provider entry for `aws_grafana_workspace_api_key`"
ewbankkit Aug 22, 2022
8442338
Revert "Create workspace_api_key.go"
ewbankkit Aug 22, 2022
29bb6be
Merge commit '844233865862b1678b18ea736da55a9d30b5f9f8' into HEAD
ewbankkit Aug 22, 2022
c38010e
r/aws_grafana_workspace_api_key: Incorporate some tweaks from #26383.
ewbankkit Aug 22, 2022
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
3 changes: 3 additions & 0 deletions .changelog/25286.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_grafana_workspace_api_key
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1550,6 +1550,7 @@ func New(_ context.Context) (*schema.Provider, error) {
"aws_grafana_license_association": grafana.ResourceLicenseAssociation(),
"aws_grafana_role_association": grafana.ResourceRoleAssociation(),
"aws_grafana_workspace": grafana.ResourceWorkspace(),
"aws_grafana_workspace_api_key": grafana.ResourceWorkspaceAPIKey(),
"aws_grafana_workspace_saml_configuration": grafana.ResourceWorkspaceSAMLConfiguration(),

"aws_guardduty_detector": guardduty.ResourceDetector(),
Expand Down
124 changes: 124 additions & 0 deletions internal/service/grafana/workspace_api_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package grafana

import (
"fmt"
"log"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/managedgrafana"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
)

func ResourceWorkspaceAPIKey() *schema.Resource {
return &schema.Resource{
Create: resourceWorkspaceAPIKeyCreate,
Read: schema.Noop,
Update: schema.Noop,
Delete: resourceWorkspaceAPIKeyDelete,

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.

Please include a Key attribute to expose the response element Key. The Key is a token, and the value is to be used as a bearer token to authenticate HTTP requests to the workspace.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added Key in the Resource Structure.

"key": {
Type: schema.TypeString,
Computed: true,
},
"key_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 100),
},
"key_role": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(managedgrafana.Role_Values(), false),
},
"seconds_to_live": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(1, 2592000),
},
"workspace_id": {
Type: schema.TypeString,
Required: true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add validation that matches the API documentation.

Would recommend including a regex to verify the format if possible. I know the other resources in grafana don't include it. And it is not required since users will most likely be using a reference to a resource.id and not typing it in.

^g-[0-9a-f]{10}$

ForceNew: true,
},
},
}
}

func resourceWorkspaceAPIKeyCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).GrafanaConn

keyName := d.Get("key_name").(string)
workspaceID := d.Get("workspace_id").(string)
id := WorkspaceAPIKeyCreateResourceID(workspaceID, keyName)
input := &managedgrafana.CreateWorkspaceApiKeyInput{
KeyName: aws.String(keyName),
KeyRole: aws.String(d.Get("key_role").(string)),
SecondsToLive: aws.Int64(int64(d.Get("seconds_to_live").(int))),
WorkspaceId: aws.String(workspaceID),
}

log.Printf("[DEBUG] Creating Grafana Workspace API Key: %s", input)
output, err := conn.CreateWorkspaceApiKey(input)

if err != nil {
return fmt.Errorf("creating Grafana Workspace API Key (%s): %w", id, err)
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Set Id after the response error check.

I believe that a grafana workspace instance supports multiple API keys, each with different names? If this is true (please verify with the service team), the Id for this resource should be a composite Id. There is an example of a composite key.

Suggested change
d.SetId(fmt.Sprintf("%s/%s", d.Get("workspace_id").(string), d.Get("key_name").(string)))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Checked with the Service team and they mentioned that a Single Grafana Workspace can have multiple API keys and incorporated the changes as requested.

d.SetId(id)
d.Set("key", output.Key)

return nil
}

func resourceWorkspaceAPIKeyDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).GrafanaConn

workspaceID, keyName, error := WorkspaceAPIKeyParseResourceID(d.Id())

if error != nil {
return error
}

log.Printf("[DEBUG] Deleting Grafana Workspace API Key: %s", d.Id())
_, err := conn.DeleteWorkspaceApiKey(&managedgrafana.DeleteWorkspaceApiKeyInput{
KeyName: aws.String(keyName),
WorkspaceId: aws.String(workspaceID),
})

if tfawserr.ErrCodeEquals(err, managedgrafana.ErrCodeResourceNotFoundException) {
return nil
}

if err != nil {
return fmt.Errorf("deleting Grafana Workspace API Key (%s): %w", d.Id(), err)
}

return nil

}

const workspaceAPIKeyIDSeparator = "/"

func WorkspaceAPIKeyCreateResourceID(workspaceID, keyName string) string {
parts := []string{workspaceID, keyName}
id := strings.Join(parts, workspaceAPIKeyIDSeparator)

return id
}

func WorkspaceAPIKeyParseResourceID(id string) (string, string, error) {
parts := strings.Split(id, workspaceAPIKeyIDSeparator)

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("unexpected format for ID (%[1]s), expected workspace-id%[2]skey-name", id, workspaceAPIKeyIDSeparator)
}

return parts[0], parts[1], nil
}
72 changes: 72 additions & 0 deletions internal/service/grafana/workspace_api_key_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package grafana_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/managedgrafana"
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
)

func testAccWorkspaceAPIKey_basic(t *testing.T) {
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_grafana_workspace_api_key.test"
workspaceResourceName := "aws_grafana_workspace.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(managedgrafana.EndpointsID, t) },
ErrorCheck: acctest.ErrorCheck(t, managedgrafana.EndpointsID),
CheckDestroy: acctest.CheckDestroyNoop,
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccWorkspaceAPIKeyConfig_basic(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(resourceName, "key"),
resource.TestCheckResourceAttr(resourceName, "key_name", rName),
resource.TestCheckResourceAttr(resourceName, "key_role", managedgrafana.RoleEditor),
resource.TestCheckResourceAttr(resourceName, "seconds_to_live", "3600"),
resource.TestCheckResourceAttrPair(resourceName, "workspace_id", workspaceResourceName, "id"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please add an evaluation of the requested Key computed output.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added as requested.

),
},
},
})
}

func testAccWorkspaceAPIKeyConfig_basic(rName string) string {
return fmt.Sprintf(`
Copy link
Collaborator

Choose a reason for hiding this comment

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

unnecessary use of return fmt.Sprintf(, as no strings are being formatted/interpolated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed.

resource "aws_iam_role" "test" {
name = %[1]q

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "grafana.amazonaws.com"
}
},
]
})
}

resource "aws_grafana_workspace" "test" {
account_access_type = "CURRENT_ACCOUNT"
authentication_providers = ["SAML"]
permission_type = "SERVICE_MANAGED"
role_arn = aws_iam_role.test.arn
}

resource "aws_grafana_workspace_api_key" "test" {
key_name = %[1]q
key_role = "EDITOR"
seconds_to_live = 3600
workspace_id = aws_grafana_workspace.test.id
}
`, rName)
}
3 changes: 3 additions & 0 deletions internal/service/grafana/workspace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func TestAccGrafana_serial(t *testing.T) {
"notificationDestinations": testAccWorkspace_notificationDestinations,
"tags": testAccWorkspace_tags,
},
"ApiKey": {
"basic": testAccWorkspaceAPIKey_basic,
},
"DataSource": {
"basic": testAccWorkspaceDataSource_basic,
},
Expand Down
39 changes: 39 additions & 0 deletions website/docs/r/grafana_workspace_api_key.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
subcategory: "Managed Grafana"
layout: "aws"
page_title: "AWS: aws_grafana_workspace_api_key"
description: |-
Creates a Grafana API key for the workspace. This key can be used to authenticate requests sent to the workspace's HTTP API.
---

# Resource: aws_grafana_workspace_api_key

Provides an Amazon Managed Grafana workspace API Key resource.

## Example Usage

### Basic configuration

```terraform
resource "aws_grafana_workspace_api_key" "key" {
key_name = "test-key"
key_role = "VIEWER"
seconds_to_live = 3600
workspace_id = aws_grafana_workspace.test.id
}
```

## Argument Reference

The following arguments are required:

- `key_name` - (Required) Specifies the name of the API key. Key names must be unique to the workspace.
- `key_role` - (Required) Specifies the permission level of the API key. Valid values are `VIEWER`, `EDITOR`, or `ADMIN`.
- `seconds_to_live` - (Required) Specifies the time in seconds until the API key expires. Keys can be valid for up to 30 days.
- `workspace_id` - (Required) The ID of the workspace that the API key is valid for.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `key` - The key token in JSON format. Use this value as a bearer token to authenticate HTTP requests to the workspace.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I do not see how this value is exported as the _, err = conn.CreateWorkspaceApiKey(input) call is discarding the CreateWorkspaceApiKeyOutput.

Please verify?