Skip to content

Commit

Permalink
Migrate resource team
Browse files Browse the repository at this point in the history
  • Loading branch information
cjgajard committed Jul 2, 2024
1 parent bb75f1c commit cbac4fa
Show file tree
Hide file tree
Showing 7 changed files with 327 additions and 33 deletions.
1 change: 1 addition & 0 deletions pagerduty/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ func Provider(isMux bool) *schema.Provider {

delete(p.ResourcesMap, "pagerduty_addon")
delete(p.ResourcesMap, "pagerduty_business_service")
delete(p.ResourcesMap, "pagerduty_team")
}

p.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Expand Down
28 changes: 28 additions & 0 deletions pagerduty/provider_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package pagerduty

import (
"context"
"fmt"
"log"
"net/url"
Expand All @@ -11,6 +12,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/heimweh/go-pagerduty/pagerduty"
)

Expand Down Expand Up @@ -189,6 +191,7 @@ resource "pagerduty_service" "foo" {
}
`, username, email, escalationPolicy, service)
}

func testAccCheckPagerDutyProviderAuthWithMultipleMethodsConfig(username, email, escalationPolicy, service string) string {
return fmt.Sprintf(`
provider "pagerduty" {
Expand Down Expand Up @@ -331,3 +334,28 @@ func testAccGetPagerDutyAccountDomain(t *testing.T) string {
}
return accountDomain
}

func testAccCheckPagerDutyTeamDestroy(s *terraform.State) error {
ctx := context.Background()

for _, r := range s.RootModule().Resources {
if r.Type != "pagerduty_team" {
continue
}

if _, err := testAccProvider.client.GetTeamWithContext(ctx, r.Primary.ID); err == nil {

Check failure on line 346 in pagerduty/provider_test.go

View workflow job for this annotation

GitHub Actions / test

testAccProvider.client undefined (type *schema.Provider has no field or method client)
return fmt.Errorf("Team still exists")
}

}
return nil
}

func testAccCheckPagerDutyTeamConfig(team string) string {
return fmt.Sprintf(`
resource "pagerduty_team" "foo" {
name = "%s"
description = "foo"
}`, team)
}
1 change: 1 addition & 0 deletions pagerduty/resource_pagerduty_team.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/heimweh/go-pagerduty/pagerduty"
)

// Deprecated: Migrated to pagerdutyplugin.resourceTeam. Kept for testing purposes.
func resourcePagerDutyTeam() *schema.Resource {
return &schema.Resource{
Create: resourcePagerDutyTeamCreate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ func TestAccPagerDutyTeam_import(t *testing.T) {
team := fmt.Sprintf("tf-%s", acctest.RandString(5))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckPagerDutyTeamDestroy,
PreCheck: func() { testAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(),
CheckDestroy: testAccCheckPagerDutyTeamDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckPagerDutyTeamConfig(team),
Expand Down
1 change: 1 addition & 0 deletions pagerdutyplugin/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func (p *Provider) Resources(_ context.Context) [](func() resource.Resource) {
func() resource.Resource { return &resourceServiceDependency{} },
func() resource.Resource { return &resourceTagAssignment{} },
func() resource.Resource { return &resourceTag{} },
func() resource.Resource { return &resourceTeam{} },
func() resource.Resource { return &resourceUserHandoffNotificationRule{} },
}
}
Expand Down
270 changes: 270 additions & 0 deletions pagerdutyplugin/resource_pagerduty_team.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
package pagerduty

import (
"context"
"fmt"
"log"
"time"

"github.com/PagerDuty/go-pagerduty"
"github.com/PagerDuty/terraform-provider-pagerduty/util"
"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/stringdefault"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
)

type resourceTeam struct{ client *pagerduty.Client }

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

func (r *resourceTeam) Metadata(_ context.Context, _ resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = "pagerduty_team"
}

func (r *resourceTeam) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{Computed: true},
"name": schema.StringAttribute{Required: true},
"description": schema.StringAttribute{
Optional: true,
Computed: true,
Default: stringdefault.StaticString("Managed by Terraform"),
},
"html_url": schema.StringAttribute{Computed: true},
"parent": schema.StringAttribute{Optional: true},
"default_role": schema.StringAttribute{
Computed: true,
Optional: true,
},
},
}
}

func (r *resourceTeam) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var model resourceTeamModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
plan := buildPagerdutyTeam(&model)
log.Printf("[INFO] Creating PagerDuty team %s", plan.Name)

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
response, err := r.client.CreateTeamWithContext(ctx, plan)
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}
plan.ID = response.ID
return nil
})
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error creating PagerDuty team %s", plan.Name),
err.Error(),
)
return
}

retryNotFound := true
model, err = requestGetTeam(ctx, r.client, plan, retryNotFound)
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error reading PagerDuty team %s", plan.Name),
err.Error(),
)
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}

func (r *resourceTeam) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state resourceTeamModel

resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
log.Printf("[INFO] Reading PagerDuty team %s", state.ID)

plan := buildPagerdutyTeam(&state)

retryNotFound := false
state, err := requestGetTeam(ctx, r.client, plan, retryNotFound)
if err != nil {
if util.IsNotFoundError(err) {
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError(
fmt.Sprintf("Error reading PagerDuty team %s", plan.ID),
err.Error(),
)
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
}

func (r *resourceTeam) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var model resourceTeamModel

resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}

plan := buildPagerdutyTeam(&model)
if plan.ID == "" {
var id string
req.State.GetAttribute(ctx, path.Root("id"), &id)
plan.ID = id
}
log.Printf("[INFO] Updating PagerDuty team %s", plan.ID)

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
team, err := r.client.UpdateTeamWithContext(ctx, plan.ID, plan)
if err != nil {
if util.IsBadRequestError(err) || util.IsNotFoundError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}
model = flattenTeam(team, plan)
return nil
})
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error updating PagerDuty team %s", plan.ID),
err.Error(),
)
return
}

retryNotFound := false
model, err = requestGetTeam(ctx, r.client, plan, retryNotFound)
if err != nil {
if util.IsNotFoundError(err) {
resp.State.RemoveResource(ctx)
return
}
resp.Diagnostics.AddError(
fmt.Sprintf("Error updating PagerDuty team %s", plan.ID),
err.Error(),
)
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}

func (r *resourceTeam) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var id types.String

resp.Diagnostics.Append(req.State.GetAttribute(ctx, path.Root("id"), &id)...)
if resp.Diagnostics.HasError() {
return
}
log.Printf("[INFO] Deleting PagerDuty team %s", id)

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
err := r.client.DeleteTeamWithContext(ctx, id.ValueString())
if err != nil {
if util.IsBadRequestError(err) || util.IsNotFoundError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}
return nil
})
if err != nil && !util.IsNotFoundError(err) {
resp.Diagnostics.AddError(
fmt.Sprintf("Error deleting PagerDuty team %s", id),
err.Error(),
)
return
}

resp.State.RemoveResource(ctx)
}

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

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

type resourceTeamModel struct {
ID types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
DefaultRole types.String `tfsdk:"default_role"`
Description types.String `tfsdk:"description"`
HTMLURL types.String `tfsdk:"html_url"`
Parent types.String `tfsdk:"parent"`
}

func requestGetTeam(ctx context.Context, client *pagerduty.Client, plan *pagerduty.Team, retryNotFound bool) (resourceTeamModel, error) {
var model resourceTeamModel

err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
team, err := client.GetTeamWithContext(ctx, plan.ID)
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
if !retryNotFound && util.IsNotFoundError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}
model = flattenTeam(team, plan)
return nil
})

return model, err
}

func buildPagerdutyTeam(model *resourceTeamModel) *pagerduty.Team {
var parent *pagerduty.APIObject
if !model.Parent.IsNull() && !model.Parent.IsUnknown() {
parent = &pagerduty.APIObject{
ID: model.Parent.ValueString(),
Type: "team_reference",
}
}
team := pagerduty.Team{
Name: model.Name.ValueString(),
Description: model.Description.ValueString(),
Parent: parent,
DefaultRole: model.DefaultRole.ValueString(),
}
team.ID = model.ID.ValueString()
return &team
}

func flattenTeam(response *pagerduty.Team, plan *pagerduty.Team) resourceTeamModel {
model := resourceTeamModel{
ID: types.StringValue(response.ID),
Name: types.StringValue(response.Name),
Description: types.StringValue(response.Description),
HTMLURL: types.StringValue(response.HTMLURL),
DefaultRole: types.StringValue(response.DefaultRole),
}
if plan.Parent != nil {
model.Parent = types.StringValue(plan.Parent.ID)
}
if response.Parent != nil {
model.Parent = types.StringValue(response.Parent.ID)
}
return model
}
Loading

0 comments on commit cbac4fa

Please sign in to comment.