Skip to content

Commit

Permalink
Migrate datasource and resource pagerduty_tag
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgajard committed Feb 6, 2024
1 parent 5931b5f commit f9a13f5
Show file tree
Hide file tree
Showing 7 changed files with 490 additions and 2 deletions.
2 changes: 0 additions & 2 deletions pagerduty/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ func Provider() *schema.Provider {
"pagerduty_business_service": dataSourcePagerDutyBusinessService(),
"pagerduty_priority": dataSourcePagerDutyPriority(),
"pagerduty_ruleset": dataSourcePagerDutyRuleset(),
"pagerduty_tag": dataSourcePagerDutyTag(),
"pagerduty_event_orchestration": dataSourcePagerDutyEventOrchestration(),
"pagerduty_event_orchestrations": dataSourcePagerDutyEventOrchestrations(),
"pagerduty_event_orchestration_integration": dataSourcePagerDutyEventOrchestrationIntegration(),
Expand Down Expand Up @@ -120,7 +119,6 @@ func Provider() *schema.Provider {
"pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(),
"pagerduty_business_service": resourcePagerDutyBusinessService(),
"pagerduty_response_play": resourcePagerDutyResponsePlay(),
"pagerduty_tag": resourcePagerDutyTag(),
"pagerduty_tag_assignment": resourcePagerDutyTagAssignment(),
"pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(),
"pagerduty_slack_connection": resourcePagerDutySlackConnection(),
Expand Down
87 changes: 87 additions & 0 deletions pagerdutyplugin/data_source_pagerduty_tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package pagerduty

import (
"context"
"fmt"
"log"

"github.com/PagerDuty/go-pagerduty"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
)

type dataSourceTag struct {
client *pagerduty.Client
}

var _ datasource.DataSourceWithConfigure = (*dataSourceStandards)(nil)

func (d *dataSourceTag) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
resp.Diagnostics.Append(ConfigurePagerdutyClient(&d.client, req.ProviderData)...)
}

func (d *dataSourceTag) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = "pagerduty_tag"
}

func (d *dataSourceTag) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"label": schema.StringAttribute{
Required: true,
Description: "The label of the tag to find in the PagerDuty API",
},
"id": schema.StringAttribute{Computed: true},
},
}
}

func (d *dataSourceTag) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var searchTag string
if d := req.Config.GetAttribute(ctx, path.Root("label"), &searchTag); d.HasError() {
resp.Diagnostics.Append(d...)
return
}

log.Printf("[INFO] Reading PagerDuty tag")

// TODO: retry
list, err := d.client.ListTags(pagerduty.ListTagOptions{Query: searchTag})
if err != nil {
// TODO: if 400 non retryable
resp.Diagnostics.AddError("Error calling ListTags", err.Error())
// TODO: wait 30 + retry
return
}

var found *pagerduty.Tag

for _, tag := range list.Tags {
if tag.Label == searchTag {
found = tag
break
}
}

if found == nil {
// return retry.NonRetryableError(
resp.Diagnostics.AddError(
fmt.Sprintf("Unable to locate any tag with label: %s", searchTag),
"",
)
return
}

model := dataSourceTagModel{
ID: types.StringValue(found.ID),
Label: types.StringValue(found.Label),
}
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}

type dataSourceTagModel struct {
ID types.String `tfsdk:"id"`
Label types.String `tfsdk:"label"`
}
63 changes: 63 additions & 0 deletions pagerdutyplugin/data_source_pagerduty_tag_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package pagerduty

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)

func TestAccDataSourcePagerDutyTag_Basic(t *testing.T) {
tag := fmt.Sprintf("tf-%s", acctest.RandString(5))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(),
Steps: []resource.TestStep{
{
Config: testAccDataSourcePagerDutyTagConfig(tag),
Check: resource.ComposeTestCheckFunc(
testAccDataSourcePagerDutyTag("pagerduty_tag.test", "data.pagerduty_tag.by_label"),
),
},
},
})
}

func testAccDataSourcePagerDutyTag(src, n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
srcR := s.RootModule().Resources[src]
srcA := srcR.Primary.Attributes

r := s.RootModule().Resources[n]
a := r.Primary.Attributes

if a["id"] == "" {
return fmt.Errorf("Expected to get a tag ID from PagerDuty")
}

testAtts := []string{"id", "label"}

for _, att := range testAtts {
if a[att] != srcA[att] {
return fmt.Errorf("Expected the tag %s to be: %s, but got: %s", att, srcA[att], a[att])
}
}

return nil
}
}

func testAccDataSourcePagerDutyTagConfig(tag string) string {
return fmt.Sprintf(`
resource "pagerduty_tag" "test" {
label = "%s"
}
data "pagerduty_tag" "by_label" {
label = pagerduty_tag.test.label
}
`, tag)
}
2 changes: 2 additions & 0 deletions pagerdutyplugin/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func (p *Provider) Schema(ctx context.Context, req provider.SchemaRequest, resp

func (p *Provider) DataSources(ctx context.Context) [](func() datasource.DataSource) {
return [](func() datasource.DataSource){
func() datasource.DataSource { return &dataSourceTag{} },
func() datasource.DataSource { return &dataSourceStandards{} },
func() datasource.DataSource { return &dataSourceStandardsResourceScores{} },
func() datasource.DataSource { return &dataSourceStandardsResourcesScores{} },
Expand All @@ -57,6 +58,7 @@ func (p *Provider) DataSources(ctx context.Context) [](func() datasource.DataSou

func (p *Provider) Resources(ctx context.Context) [](func() resource.Resource) {
return [](func() resource.Resource){
func() resource.Resource { return &resourceTag{} },
func() resource.Resource { return &resourceServiceDependency{} },
}
}
Expand Down
167 changes: 167 additions & 0 deletions pagerdutyplugin/resource_pagerduty_tag.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package pagerduty

import (
"context"
"errors"
"log"
"time"

"github.com/PagerDuty/go-pagerduty"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/terraform-providers/terraform-provider-pagerduty/util"
)

type resourceTag struct {
client *pagerduty.Client
}

var (
_ resource.ResourceWithConfigure = (*resourceTag)(nil)
_ resource.ResourceWithImportState = (*resourceTag)(nil)
)

func (r *resourceTag) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
resp.Diagnostics.Append(ConfigurePagerdutyClient(&r.client, req.ProviderData)...)
}

func (r *resourceTag) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = "pagerduty_tag"
}

func (r *resourceTag) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"label": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"html_url": schema.StringAttribute{Computed: true},
"id": schema.StringAttribute{Computed: true},
"summary": schema.StringAttribute{Computed: true},
},
}
}

func (r *resourceTag) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var model resourceTagModel
if d := req.Config.Get(ctx, &model); d.HasError() {
resp.Diagnostics.Append(d...)
}
tagBody := buildTag(&model)
log.Printf("[INFO] Creating PagerDuty tag %s", tagBody.Label)

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
tag, err := r.client.CreateTagWithContext(ctx, tagBody)
if err != nil {
var apiErr pagerduty.APIError
if errors.As(err, &apiErr) && apiErr.StatusCode == 400 {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}
model = flattenTag(tag)
return nil
})
if err != nil {
resp.Diagnostics.AddError("Error calling CreateTagWithContext", err.Error())
}
resp.State.Set(ctx, &model)
}

func (r *resourceTag) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var tagID types.String
if d := req.State.GetAttribute(ctx, path.Root("id"), &tagID); d.HasError() {
resp.Diagnostics.Append(d...)
}
log.Printf("[INFO] Reading PagerDuty tag %s", tagID)

var model resourceTagModel
err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
tag, err := r.client.GetTagWithContext(ctx, tagID.ValueString())
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
if util.IsNotFoundError(err) {
log.Printf("[WARN] Removing %s because it's gone", tagID.String())
resp.State.RemoveResource(ctx)
return nil
}
return retry.RetryableError(err)
}
model = flattenTag(tag)
return nil
})
if err != nil {
resp.Diagnostics.AddError("Error calling GetTagWithContext", err.Error())
}
resp.State.Set(ctx, &model)
}

func (r *resourceTag) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
}

func (r *resourceTag) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var model resourceTagModel
if d := req.State.Get(ctx, &model); d.HasError() {
resp.Diagnostics.Append(d...)
}
log.Printf("[INFO] Removing PagerDuty tag %s", model.ID)

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
err := r.client.DeleteTagWithContext(ctx, model.ID.ValueString())
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
if util.IsNotFoundError(err) {
resp.State.RemoveResource(ctx)
return nil
}
return retry.RetryableError(err)
}
return nil
})
if err != nil {
resp.Diagnostics.AddError("Error calling DeleteTagWithContext", err.Error())
return
}
resp.State.RemoveResource(ctx)
}

func (r *resourceTag) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

type resourceTagModel struct {
ID types.String `tfsdk:"id"`
HtmlUrl types.String `tfsdk:"html_url"`
Label types.String `tfsdk:"label"`
Summary types.String `tfsdk:"summary"`
}

func buildTag(model *resourceTagModel) *pagerduty.Tag {
tag := &pagerduty.Tag{
Label: model.Label.ValueString(),
}
tag.Type = "tag"
return tag
}

func flattenTag(tag *pagerduty.Tag) resourceTagModel {
model := resourceTagModel{
ID: types.StringValue(tag.ID),
HtmlUrl: types.StringValue(tag.HTMLURL),
Label: types.StringValue(tag.Label),
Summary: types.StringValue(tag.Summary),
}
return model
}
Loading

0 comments on commit f9a13f5

Please sign in to comment.