Skip to content

Commit

Permalink
Add support for Amazon Managed Service for Prometheus (#16882)
Browse files Browse the repository at this point in the history
* add support for AWS Managed Prometheus (preview)

this PR adds support for the new AWS Managed Prometheus service (preview).

* add support for AWS Managed Prometheus (preview)

this PR adds support for the new AWS Managed Prometheus service (preview).

* Apply suggestions from code review

* Update aws/resource_aws_prometheus_workspace_test.go

* Update aws/resource_aws_prometheus_workspace.go

Co-authored-by: Brian Flad <[email protected]>
  • Loading branch information
nicolai86 and bflad committed Jan 28, 2021
1 parent 5800943 commit 2258cd7
Show file tree
Hide file tree
Showing 11 changed files with 438 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .hashibot.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ behavior "regexp_issue_labeler_v2" "service_labels" {
"service/pricing" = [
"aws_pricing_",
],
"service/prometheusservice" = [
"aws_prometheus_",
],
"service/qldb" = [
"aws_qldb_",
],
Expand Down Expand Up @@ -1332,6 +1335,11 @@ behavior "pull_request_path_labeler" "service_labels" {
"**/*_pricing_*",
"**/pricing_*"
]
"service/prometheusservice" = [
"aws/internal/service/prometheus/**/*",
"**/*_prometheus_*",
"**/prometheus_*",
]
"service/qldb" = [
"aws/internal/service/qldb/**/*",
"**/*_qldb_*",
Expand Down
3 changes: 3 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ import (
"github.com/aws/aws-sdk-go/service/personalize"
"github.com/aws/aws-sdk-go/service/pinpoint"
"github.com/aws/aws-sdk-go/service/pricing"
"github.com/aws/aws-sdk-go/service/prometheusservice"
"github.com/aws/aws-sdk-go/service/qldb"
"github.com/aws/aws-sdk-go/service/quicksight"
"github.com/aws/aws-sdk-go/service/ram"
Expand Down Expand Up @@ -320,6 +321,7 @@ type AWSClient struct {
outpostsconn *outposts.Outposts
partition string
personalizeconn *personalize.Personalize
prometheusserviceconn *prometheusservice.PrometheusService
pinpointconn *pinpoint.Pinpoint
pricingconn *pricing.Pricing
qldbconn *qldb.QLDB
Expand Down Expand Up @@ -559,6 +561,7 @@ func (c *Config) Client() (interface{}, error) {
outpostsconn: outposts.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["outposts"])})),
partition: partition,
personalizeconn: personalize.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["personalize"])})),
prometheusserviceconn: prometheusservice.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["prometheusservice"])})),
pinpointconn: pinpoint.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["pinpoint"])})),
pricingconn: pricing.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["pricing"])})),
qldbconn: qldb.New(sess.Copy(&aws.Config{Endpoint: aws.String(c.Endpoints["qldb"])})),
Expand Down
62 changes: 62 additions & 0 deletions aws/internal/service/prometheusservice/waiter/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package waiter

import (
"context"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/prometheusservice"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const (
ResourceStatusFailed = "Failed"
ResourceStatusUnknown = "Unknown"
ResourceStatusDeleted = "Deleted"
)

// WorkspaceCreatedStatus fetches the Workspace and its Status.
func WorkspaceCreatedStatus(ctx context.Context, conn *prometheusservice.PrometheusService, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &prometheusservice.DescribeWorkspaceInput{
WorkspaceId: aws.String(id),
}

output, err := conn.DescribeWorkspaceWithContext(ctx, input)

if err != nil {
return output, ResourceStatusFailed, err
}

if output == nil || output.Workspace == nil {
return output, ResourceStatusUnknown, nil
}

return output.Workspace, aws.StringValue(output.Workspace.Status.StatusCode), nil
}
}

// WorkspaceDeletedStatus fetches the Workspace and its Status
func WorkspaceDeletedStatus(ctx context.Context, conn *prometheusservice.PrometheusService, id string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &prometheusservice.DescribeWorkspaceInput{
WorkspaceId: aws.String(id),
}

output, err := conn.DescribeWorkspaceWithContext(ctx, input)

if tfawserr.ErrCodeEquals(err, prometheusservice.ErrCodeResourceNotFoundException) {
return output, ResourceStatusDeleted, nil
}

if err != nil {
return output, ResourceStatusUnknown, err
}

if output == nil || output.Workspace == nil {
return output, ResourceStatusUnknown, nil
}

return output.Workspace, aws.StringValue(output.Workspace.Status.StatusCode), nil
}
}
50 changes: 50 additions & 0 deletions aws/internal/service/prometheusservice/waiter/waiter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package waiter

import (
"context"
"time"

"github.com/aws/aws-sdk-go/service/prometheusservice"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const (
// Maximum amount of time to wait for a Workspace to be created, updated, or deleted
WorkspaceTimeout = 5 * time.Minute
)

// WorkspaceCreated waits for a Workspace to return "Active"
func WorkspaceCreated(ctx context.Context, conn *prometheusservice.PrometheusService, id string) (*prometheusservice.WorkspaceSummary, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{prometheusservice.WorkspaceStatusCodeCreating},
Target: []string{prometheusservice.WorkspaceStatusCodeActive},
Refresh: WorkspaceCreatedStatus(ctx, conn, id),
Timeout: WorkspaceTimeout,
}

outputRaw, err := stateConf.WaitForState()

if v, ok := outputRaw.(*prometheusservice.WorkspaceSummary); ok {
return v, err
}

return nil, err
}

// WorkspaceDeleted waits for a Workspace to return "Deleted"
func WorkspaceDeleted(ctx context.Context, conn *prometheusservice.PrometheusService, arn string) (*prometheusservice.WorkspaceSummary, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{prometheusservice.WorkspaceStatusCodeDeleting},
Target: []string{ResourceStatusDeleted},
Refresh: WorkspaceDeletedStatus(ctx, conn, arn),
Timeout: WorkspaceTimeout,
}

outputRaw, err := stateConf.WaitForState()

if v, ok := outputRaw.(*prometheusservice.WorkspaceSummary); ok {
return v, err
}

return nil, err
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,7 @@ func Provider() *schema.Provider {
"aws_organizations_policy_attachment": resourceAwsOrganizationsPolicyAttachment(),
"aws_organizations_organizational_unit": resourceAwsOrganizationsOrganizationalUnit(),
"aws_placement_group": resourceAwsPlacementGroup(),
"aws_prometheus_workspace": resourceAwsPrometheusWorkspace(),
"aws_proxy_protocol_policy": resourceAwsProxyProtocolPolicy(),
"aws_qldb_ledger": resourceAwsQLDBLedger(),
"aws_quicksight_group": resourceAwsQuickSightGroup(),
Expand Down
133 changes: 133 additions & 0 deletions aws/resource_aws_prometheus_workspace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package aws

import (
"context"
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/prometheusservice"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/prometheusservice/waiter"
)

func resourceAwsPrometheusWorkspace() *schema.Resource {
return &schema.Resource{
CreateContext: resourceAwsPrometheusWorkspaceCreate,
ReadContext: resourceAwsPrometheusWorkspaceRead,
UpdateContext: resourceAwsPrometheusWorkspaceUpdate,
DeleteContext: resourceAwsPrometheusWorkspaceDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"alias": {
Type: schema.TypeString,
Optional: true,
},
"prometheus_endpoint": {
Type: schema.TypeString,
Computed: true,
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsPrometheusWorkspaceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Reading AMP workspace %s", d.Id())
conn := meta.(*AWSClient).prometheusserviceconn

details, err := conn.DescribeWorkspaceWithContext(ctx, &prometheusservice.DescribeWorkspaceInput{
WorkspaceId: aws.String(d.Id()),
})
if tfawserr.ErrCodeEquals(err, prometheusservice.ErrCodeResourceNotFoundException) {
log.Printf("[WARN] Prometheus Workspace (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

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

if details == nil || details.Workspace == nil {
return diag.FromErr(fmt.Errorf("error reading Prometheus Workspace (%s): empty response", d.Id()))
}

ws := details.Workspace

d.Set("alias", ws.Alias)
d.Set("arn", ws.Arn)
d.Set("prometheus_endpoint", ws.PrometheusEndpoint)

return nil
}

func resourceAwsPrometheusWorkspaceUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Updating AMP workspace %s", d.Id())

req := &prometheusservice.UpdateWorkspaceAliasInput{
WorkspaceId: aws.String(d.Id()),
}
if v, ok := d.GetOk("alias"); ok {
req.Alias = aws.String(v.(string))
}
conn := meta.(*AWSClient).prometheusserviceconn
if _, err := conn.UpdateWorkspaceAliasWithContext(ctx, req); err != nil {
return diag.FromErr(fmt.Errorf("error updating Prometheus WorkSpace (%s): %w", d.Id(), err))
}

return resourceAwsPrometheusWorkspaceRead(ctx, d, meta)
}

func resourceAwsPrometheusWorkspaceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Creating AMP workspace %s", d.Id())
conn := meta.(*AWSClient).prometheusserviceconn

req := &prometheusservice.CreateWorkspaceInput{}
if v, ok := d.GetOk("alias"); ok {
req.Alias = aws.String(v.(string))
}

result, err := conn.CreateWorkspaceWithContext(ctx, req)
if err != nil {
return diag.FromErr(fmt.Errorf("error creating Prometheus WorkSpace (%s): %w", d.Id(), err))
}
d.SetId(aws.StringValue(result.WorkspaceId))

if _, err := waiter.WorkspaceCreated(ctx, conn, d.Id()); err != nil {
return diag.FromErr(fmt.Errorf("error waiting for Workspace (%s) to be created: %w", d.Id(), err))
}

return resourceAwsPrometheusWorkspaceRead(ctx, d, meta)
}

func resourceAwsPrometheusWorkspaceDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
log.Printf("[INFO] Deleting AMP workspace %s", d.Id())
conn := meta.(*AWSClient).prometheusserviceconn

_, err := conn.DeleteWorkspaceWithContext(ctx, &prometheusservice.DeleteWorkspaceInput{
WorkspaceId: aws.String(d.Id()),
})

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

if err != nil {
return diag.FromErr(fmt.Errorf("error deleting Prometheus Workspace (%s): %w", d.Id(), err))
}

if _, err := waiter.WorkspaceDeleted(ctx, conn, d.Id()); err != nil {
return diag.FromErr(fmt.Errorf("error waiting for Prometheus Workspace (%s) to be deleted: %w", d.Id(), err))
}

return nil
}
Loading

0 comments on commit 2258cd7

Please sign in to comment.