From 72d57adf7f458259f94b2784a6387772f93b973c Mon Sep 17 00:00:00 2001 From: Carlos Gajardo Date: Fri, 15 Mar 2024 11:21:32 -0300 Subject: [PATCH 1/4] Migrate data source license --- pagerduty/data_source_pagerduty_license.go | 175 ------------------ pagerduty/data_source_pagerduty_licenses.go | 61 ++++++ pagerduty/provider.go | 1 - .../data_source_pagerduty_license.go | 167 +++++++++++++++++ .../data_source_pagerduty_license_test.go | 14 +- pagerdutyplugin/provider.go | 5 +- 6 files changed, 238 insertions(+), 185 deletions(-) delete mode 100644 pagerduty/data_source_pagerduty_license.go create mode 100644 pagerdutyplugin/data_source_pagerduty_license.go rename {pagerduty => pagerdutyplugin}/data_source_pagerduty_license_test.go (89%) diff --git a/pagerduty/data_source_pagerduty_license.go b/pagerduty/data_source_pagerduty_license.go deleted file mode 100644 index d3e7bfca5..000000000 --- a/pagerduty/data_source_pagerduty_license.go +++ /dev/null @@ -1,175 +0,0 @@ -package pagerduty - -import ( - "fmt" - "log" - "net/http" - "strings" - "time" - - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/heimweh/go-pagerduty/pagerduty" -) - -var licenseSchema = map[string]*schema.Schema{ - "id": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "type": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "name": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "summary": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "description": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "role_group": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "current_value": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "allocations_available": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - }, - "valid_roles": { - Type: schema.TypeList, - Optional: true, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, - }, - "self": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, - "html_url": { - Type: schema.TypeString, - Optional: true, - Computed: true, - }, -} - -func dataSourcePagerDutyLicense() *schema.Resource { - return &schema.Resource{ - Read: dataSourcePagerDutyLicenseRead, - Schema: licenseSchema, - } -} - -func dataSourcePagerDutyLicenseRead(d *schema.ResourceData, meta interface{}) error { - client, err := meta.(*Config).Client() - if err != nil { - return err - } - - log.Printf("[INFO] Fetching PagerDuty Licenses") - - return retry.Retry(5*time.Minute, func() *retry.RetryError { - licenses, _, err := client.Licenses.List() - if err != nil { - if isErrCode(err, http.StatusBadRequest) { - return retry.NonRetryableError(err) - } - - // Delaying retry by 30s as recommended by PagerDuty - // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit - time.Sleep(30 * time.Second) - return retry.RetryableError(err) - } - - id, name, description := d.Get("id").(string), d.Get("name").(string), d.Get("description").(string) - found := findBestMatchLicense(licenses, id, name, description) - - if found == nil { - ids := licensesToStringOfIds(licenses) - return retry.NonRetryableError( - fmt.Errorf("Unable to locate any license with ids in [%s] with the configured id: '%s', name: '%s' or description: '%s'", ids, id, name, description)) - } - - d.SetId(found.ID) - d.Set("name", found.Name) - d.Set("description", found.Description) - d.Set("type", found.Type) - d.Set("summary", found.Summary) - d.Set("role_group", found.RoleGroup) - d.Set("allocations_available", found.AllocationsAvailable) - d.Set("current_value", found.CurrentValue) - d.Set("valid_roles", found.ValidRoles) - d.Set("self", found.Self) - d.Set("html_url", found.HTMLURL) - - return nil - }) -} - -func licensesToStringOfIds(licenses []*pagerduty.License) string { - ids := make([]string, len(licenses)) - for i, v := range licenses { - ids[i] = v.ID - } - return strings.Join(ids, ", ") -} - -func findBestMatchLicense(licenses []*pagerduty.License, id, name, description string) *pagerduty.License { - var found *pagerduty.License - for _, license := range licenses { - if licenseIsExactMatch(license, id, name, description) { - found = license - break - } - } - - // If there is no exact match for a license, check for substring matches - // This allows customers to use a term such as "Full User", which is included - // in the names of all licenses that support creating full users. However, - // if id is set then it must match with licenseIsExactMatch - if id == "" && found == nil { - for _, license := range licenses { - if licenseContainsMatch(license, name, description) { - found = license - break - } - } - } - - return found -} - -func licenseIsExactMatch(license *pagerduty.License, id, name, description string) bool { - if id != "" { - return license.ID == id && matchesOrIsUnset(license.Name, name) && matchesOrIsUnset(license.Description, description) - } - return license.Name == name && license.Description == description -} - -func matchesOrIsUnset(licenseAttr, config string) bool { - return config == "" || config == licenseAttr -} - -func licenseContainsMatch(license *pagerduty.License, name, description string) bool { - return strings.Contains(license.Name, name) && strings.Contains(license.Description, description) -} diff --git a/pagerduty/data_source_pagerduty_licenses.go b/pagerduty/data_source_pagerduty_licenses.go index 62b810a6a..3310a3b83 100644 --- a/pagerduty/data_source_pagerduty_licenses.go +++ b/pagerduty/data_source_pagerduty_licenses.go @@ -91,3 +91,64 @@ func flattenLicense(l *pagerduty.License) map[string]interface{} { return license } + +var licenseSchema = map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "summary": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "role_group": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "current_value": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "allocations_available": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + }, + "valid_roles": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "self": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "html_url": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, +} diff --git a/pagerduty/provider.go b/pagerduty/provider.go index 3f5c7bdb3..bcbc8e2b0 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -90,7 +90,6 @@ func Provider(isMux bool) *schema.Provider { "pagerduty_schedule": dataSourcePagerDutySchedule(), "pagerduty_user": dataSourcePagerDutyUser(), "pagerduty_users": dataSourcePagerDutyUsers(), - "pagerduty_license": dataSourcePagerDutyLicense(), "pagerduty_licenses": dataSourcePagerDutyLicenses(), "pagerduty_user_contact_method": dataSourcePagerDutyUserContactMethod(), "pagerduty_team": dataSourcePagerDutyTeam(), diff --git a/pagerdutyplugin/data_source_pagerduty_license.go b/pagerdutyplugin/data_source_pagerduty_license.go new file mode 100644 index 000000000..ed69d4bbb --- /dev/null +++ b/pagerdutyplugin/data_source_pagerduty_license.go @@ -0,0 +1,167 @@ +package pagerduty + +import ( + "context" + "fmt" + "log" + "strings" + "time" + + "github.com/PagerDuty/go-pagerduty" + "github.com/PagerDuty/terraform-provider-pagerduty/util" + "github.com/hashicorp/terraform-plugin-framework/attr" + "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" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" +) + +type dataSourceLicense struct{ client *pagerduty.Client } + +var _ datasource.DataSourceWithConfigure = (*dataSourceLicense)(nil) + +func (*dataSourceLicense) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "pagerduty_license" +} + +func (*dataSourceLicense) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{Optional: true, Computed: true}, + "name": schema.StringAttribute{Optional: true, Computed: true}, + "description": schema.StringAttribute{Optional: true, Computed: true}, + "type": schema.StringAttribute{Computed: true}, + "summary": schema.StringAttribute{Computed: true}, + "role_group": schema.StringAttribute{Computed: true}, + "current_value": schema.Int64Attribute{Computed: true}, + "allocations_available": schema.Int64Attribute{Computed: true}, + "valid_roles": schema.ListAttribute{Computed: true, ElementType: types.StringType}, + "self": schema.StringAttribute{Computed: true}, + "html_url": schema.StringAttribute{Computed: true}, + }, + } +} + +func (d *dataSourceLicense) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + resp.Diagnostics.Append(ConfigurePagerdutyClient(&d.client, req.ProviderData)...) +} + +func (d *dataSourceLicense) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + log.Println("[INFO] Fetching PagerDuty licenses") + + var searchName, searchID, searchDescription types.String + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("name"), &searchName)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("id"), &searchID)...) + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("description"), &searchDescription)...) + if resp.Diagnostics.HasError() { + return + } + + var found *pagerduty.License + err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { + list, err := d.client.ListLicensesWithContext(ctx) + if err != nil { + if util.IsBadRequestError(err) { + return retry.NonRetryableError(err) + } + return retry.RetryableError(err) + } + + found = findBestMatchLicense(list.Licenses, searchID.ValueString(), searchName.ValueString(), searchDescription.ValueString()) + return nil + }) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error reading PagerDuty license %s", searchName), + err.Error(), + ) + } + + if found == nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Unable to locate any license with the name: %s", searchName), + "", + ) + return + } + + model := flattenLicense(found) + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} + +type dataSourceLicenseModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` + Type types.String `tfsdk:"type"` + Summary types.String `tfsdk:"summary"` + RoleGroup types.String `tfsdk:"role_group"` + AllocationsAvailable types.Int64 `tfsdk:"allocations_available"` + CurrentValue types.Int64 `tfsdk:"current_value"` + ValidRoles types.List `tfsdk:"valid_roles"` + Self types.String `tfsdk:"self"` + HTMLURL types.String `tfsdk:"html_url"` +} + +func flattenLicense(license *pagerduty.License) dataSourceLicenseModel { + return dataSourceLicenseModel{ + ID: types.StringValue(license.ID), + Name: types.StringValue(license.Name), + Type: types.StringValue(license.Type), + Description: types.StringValue(license.Description), + Summary: types.StringValue(license.Summary), + RoleGroup: types.StringValue(license.RoleGroup), + AllocationsAvailable: types.Int64Value(int64(license.AllocationsAvailable)), + CurrentValue: types.Int64Value(int64(license.CurrentValue)), + Self: types.StringValue(license.Self), + HTMLURL: types.StringValue(license.HTMLURL), + ValidRoles: flattenLicenseValidRoles(license.ValidRoles), + } +} + +func flattenLicenseValidRoles(roles []string) types.List { + elements := make([]attr.Value, 0, len(roles)) + for _, e := range roles { + elements = append(elements, types.StringValue(e)) + } + return types.ListValueMust(types.StringType, elements) +} + +func findBestMatchLicense(licenses []pagerduty.License, id, name, description string) *pagerduty.License { + var found *pagerduty.License + for _, license := range licenses { + if licenseIsExactMatch(&license, id, name, description) { + found = &license + break + } + } + + // If there is no exact match for a license, check for substring matches + // This allows customers to use a term such as "Full User", which is included + // in the names of all licenses that support creating full users. However, + // if id is set then it must match with licenseIsExactMatch + if id == "" && found == nil { + for _, license := range licenses { + if licenseContainsMatch(&license, name, description) { + found = &license + break + } + } + } + + return found +} + +func licenseIsExactMatch(license *pagerduty.License, id, name, description string) bool { + if id != "" { + return license.ID == id && + (license.Name == name || name == "") && + (license.Description == description || description == "") + } + return license.Name == name && license.Description == description +} + +func licenseContainsMatch(license *pagerduty.License, name, description string) bool { + return strings.Contains(license.Name, name) && strings.Contains(license.Description, description) +} diff --git a/pagerduty/data_source_pagerduty_license_test.go b/pagerdutyplugin/data_source_pagerduty_license_test.go similarity index 89% rename from pagerduty/data_source_pagerduty_license_test.go rename to pagerdutyplugin/data_source_pagerduty_license_test.go index a521c6cf2..9286ef99b 100644 --- a/pagerduty/data_source_pagerduty_license_test.go +++ b/pagerdutyplugin/data_source_pagerduty_license_test.go @@ -20,7 +20,7 @@ func TestAccDataSourcePagerDutyLicense_Basic(t *testing.T) { testAccPreCheck(t) testAccPreCheckLicenseNameTests(t, name) }, - Providers: testAccProviders, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyLicenseConfig(reference, name, description), @@ -40,8 +40,8 @@ func TestAccDataSourcePagerDutyLicense_Empty(t *testing.T) { reference := "full_user" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourceEmptyPagerDutyLicenseConfig(reference), @@ -58,8 +58,8 @@ func TestAccDataSourcePagerDutyLicense_Error(t *testing.T) { expectedErrorString := "Unable to locate any license" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyLicenseConfigError(reference), @@ -77,8 +77,8 @@ func TestAccDataSourcePagerDutyLicense_ErrorWithID(t *testing.T) { name := "Full User" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyLicenseConfigErrorWithID(reference, name), diff --git a/pagerdutyplugin/provider.go b/pagerdutyplugin/provider.go index fd0afa3a1..e63e1405b 100644 --- a/pagerdutyplugin/provider.go +++ b/pagerdutyplugin/provider.go @@ -53,12 +53,13 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro func (p *Provider) DataSources(_ context.Context) [](func() datasource.DataSource) { return [](func() datasource.DataSource){ func() datasource.DataSource { return &dataSourceBusinessService{} }, - func() datasource.DataSource { return &dataSourceIntegration{} }, func() datasource.DataSource { return &dataSourceExtensionSchema{} }, + func() datasource.DataSource { return &dataSourceIntegration{} }, + func() datasource.DataSource { return &dataSourceLicense{} }, + func() datasource.DataSource { return &dataSourceService{} }, func() datasource.DataSource { return &dataSourceStandardsResourceScores{} }, func() datasource.DataSource { return &dataSourceStandardsResourcesScores{} }, func() datasource.DataSource { return &dataSourceStandards{} }, - func() datasource.DataSource { return &dataSourceService{} }, func() datasource.DataSource { return &dataSourceTag{} }, } } From 9103f30a9c5201903dacba55bc9eb671599a0db1 Mon Sep 17 00:00:00 2001 From: Carlos Gajardo Date: Fri, 15 Mar 2024 11:50:28 -0300 Subject: [PATCH 2/4] Migrate data source licenses --- pagerduty/data_source_pagerduty_licenses.go | 1 + pagerduty/provider.go | 1 + .../data_source_pagerduty_license.go | 30 ++-- .../data_source_pagerduty_licenses.go | 130 ++++++++++++++++++ .../data_source_pagerduty_licenses_test.go | 10 +- pagerdutyplugin/provider.go | 1 + 6 files changed, 153 insertions(+), 20 deletions(-) create mode 100644 pagerdutyplugin/data_source_pagerduty_licenses.go rename {pagerduty => pagerdutyplugin}/data_source_pagerduty_licenses_test.go (89%) diff --git a/pagerduty/data_source_pagerduty_licenses.go b/pagerduty/data_source_pagerduty_licenses.go index 3310a3b83..04cc68f19 100644 --- a/pagerduty/data_source_pagerduty_licenses.go +++ b/pagerduty/data_source_pagerduty_licenses.go @@ -11,6 +11,7 @@ import ( "github.com/heimweh/go-pagerduty/pagerduty" ) +// Deprecated: Migrated to pagerdutyplugin.dataSourceLicenses. Kept for testing purposes. func dataSourcePagerDutyLicenses() *schema.Resource { return &schema.Resource{ Read: dataSourcePagerDutyLicensesRead, diff --git a/pagerduty/provider.go b/pagerduty/provider.go index bcbc8e2b0..ca29bec28 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -154,6 +154,7 @@ func Provider(isMux bool) *schema.Provider { if isMux { delete(p.DataSourcesMap, "pagerduty_business_service") + delete(p.DataSourcesMap, "pagerduty_licenses") delete(p.DataSourcesMap, "pagerduty_service") delete(p.DataSourcesMap, "pagerduty_service_integration") diff --git a/pagerdutyplugin/data_source_pagerduty_license.go b/pagerdutyplugin/data_source_pagerduty_license.go index ed69d4bbb..72e661a3c 100644 --- a/pagerdutyplugin/data_source_pagerduty_license.go +++ b/pagerdutyplugin/data_source_pagerduty_license.go @@ -26,21 +26,21 @@ func (*dataSourceLicense) Metadata(ctx context.Context, req datasource.MetadataR } func (*dataSourceLicense) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = schema.Schema{ - Attributes: map[string]schema.Attribute{ - "id": schema.StringAttribute{Optional: true, Computed: true}, - "name": schema.StringAttribute{Optional: true, Computed: true}, - "description": schema.StringAttribute{Optional: true, Computed: true}, - "type": schema.StringAttribute{Computed: true}, - "summary": schema.StringAttribute{Computed: true}, - "role_group": schema.StringAttribute{Computed: true}, - "current_value": schema.Int64Attribute{Computed: true}, - "allocations_available": schema.Int64Attribute{Computed: true}, - "valid_roles": schema.ListAttribute{Computed: true, ElementType: types.StringType}, - "self": schema.StringAttribute{Computed: true}, - "html_url": schema.StringAttribute{Computed: true}, - }, - } + resp.Schema = schema.Schema{Attributes: dataSourceLicenseAttributes} +} + +var dataSourceLicenseAttributes = map[string]schema.Attribute{ + "id": schema.StringAttribute{Optional: true, Computed: true}, + "name": schema.StringAttribute{Optional: true, Computed: true}, + "description": schema.StringAttribute{Optional: true, Computed: true}, + "type": schema.StringAttribute{Computed: true}, + "summary": schema.StringAttribute{Computed: true}, + "role_group": schema.StringAttribute{Computed: true}, + "current_value": schema.Int64Attribute{Computed: true}, + "allocations_available": schema.Int64Attribute{Computed: true}, + "valid_roles": schema.ListAttribute{Computed: true, ElementType: types.StringType}, + "self": schema.StringAttribute{Computed: true}, + "html_url": schema.StringAttribute{Computed: true}, } func (d *dataSourceLicense) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { diff --git a/pagerdutyplugin/data_source_pagerduty_licenses.go b/pagerdutyplugin/data_source_pagerduty_licenses.go new file mode 100644 index 000000000..90e89858f --- /dev/null +++ b/pagerdutyplugin/data_source_pagerduty_licenses.go @@ -0,0 +1,130 @@ +package pagerduty + +import ( + "context" + "log" + "time" + + "github.com/PagerDuty/go-pagerduty" + "github.com/PagerDuty/terraform-provider-pagerduty/util" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" +) + +type dataSourceLicenses struct{ client *pagerduty.Client } + +var _ datasource.DataSourceWithConfigure = (*dataSourceLicenses)(nil) + +func (*dataSourceLicenses) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "pagerduty_licenses" +} + +func (*dataSourceLicenses) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{Optional: true}, + "licenses": schema.ListAttribute{ + Computed: true, + ElementType: licenseObjectType, + }, + }, + } +} + +func (d *dataSourceLicenses) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + resp.Diagnostics.Append(ConfigurePagerdutyClient(&d.client, req.ProviderData)...) +} + +func (d *dataSourceLicenses) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var model dataSourceLicensesModel + log.Println("[INFO] Reading PagerDuty licenses") + + diags := req.Config.Get(ctx, &model) + if resp.Diagnostics.Append(diags...); diags.HasError() { + return + } + + uid := "" + if model.ID.IsNull() { + uid = id.UniqueId() + } else { + uid = model.ID.ValueString() + } + + err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError { + list, err := d.client.ListLicensesWithContext(ctx) + if err != nil { + if util.IsBadRequestError(err) { + return retry.NonRetryableError(err) + } + return retry.RetryableError(err) + } + + model = flattenLicenses(uid, list.Licenses, &resp.Diagnostics) + return nil + }) + if err != nil { + resp.Diagnostics.AddError( + "Error reading PagerDuty licenses", + err.Error(), + ) + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} + +type dataSourceLicensesModel struct { + ID types.String `tfsdk:"id"` + Licenses types.List `tfsdk:"licenses"` +} + +func flattenLicenses(uid string, licenses []pagerduty.License, diags *diag.Diagnostics) dataSourceLicensesModel { + elements := make([]attr.Value, 0, len(licenses)) + for _, license := range licenses { + model := flattenLicense(&license) + e, d := types.ObjectValue(licenseObjectType.AttrTypes, map[string]attr.Value{ + "id": model.ID, + "name": model.Name, + "description": model.Description, + "type": model.Type, + "summary": model.Summary, + "role_group": model.RoleGroup, + "current_value": model.CurrentValue, + "allocations_available": model.AllocationsAvailable, + "valid_roles": model.ValidRoles, + "self": model.Self, + "html_url": model.HTMLURL, + }) + diags.Append(d...) + if d.HasError() { + continue + } + elements = append(elements, e) + } + + return dataSourceLicensesModel{ + Licenses: types.ListValueMust(licenseObjectType, elements), + ID: types.StringValue(uid), + } +} + +var licenseObjectType = types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "name": types.StringType, + "description": types.StringType, + "type": types.StringType, + "summary": types.StringType, + "role_group": types.StringType, + "current_value": types.Int64Type, + "allocations_available": types.Int64Type, + "valid_roles": types.ListType{ElemType: types.StringType}, + "self": types.StringType, + "html_url": types.StringType, + }, +} diff --git a/pagerduty/data_source_pagerduty_licenses_test.go b/pagerdutyplugin/data_source_pagerduty_licenses_test.go similarity index 89% rename from pagerduty/data_source_pagerduty_licenses_test.go rename to pagerdutyplugin/data_source_pagerduty_licenses_test.go index b5b45e817..e7f9b75bd 100644 --- a/pagerduty/data_source_pagerduty_licenses_test.go +++ b/pagerdutyplugin/data_source_pagerduty_licenses_test.go @@ -13,8 +13,8 @@ func TestAccDataSourcePagerDutyLicenses_Basic(t *testing.T) { name := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyLicensesConfig(name), @@ -30,8 +30,8 @@ func TestAccDataSourcePagerDutyLicenses_WithID(t *testing.T) { name := fmt.Sprintf("tf-%s", acctest.RandString(5)) resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyLicensesConfigWithID(name), @@ -80,7 +80,7 @@ func testAccDataSourcePagerDutyLicensesWithID(n string, id string) resource.Test a := r.Primary.Attributes if val, ok := a["id"]; !ok || val != id { - return fmt.Errorf("Expected id to match provided value: %s", id) + return fmt.Errorf("Expected id to match provided value: %s\n%#v", id, a) } return testLicenses(a) diff --git a/pagerdutyplugin/provider.go b/pagerdutyplugin/provider.go index e63e1405b..eba69b028 100644 --- a/pagerdutyplugin/provider.go +++ b/pagerdutyplugin/provider.go @@ -56,6 +56,7 @@ func (p *Provider) DataSources(_ context.Context) [](func() datasource.DataSourc func() datasource.DataSource { return &dataSourceExtensionSchema{} }, func() datasource.DataSource { return &dataSourceIntegration{} }, func() datasource.DataSource { return &dataSourceLicense{} }, + func() datasource.DataSource { return &dataSourceLicenses{} }, func() datasource.DataSource { return &dataSourceService{} }, func() datasource.DataSource { return &dataSourceStandardsResourceScores{} }, func() datasource.DataSource { return &dataSourceStandardsResourcesScores{} }, From 78c3f01867d23b4fb35584a8aa7b2b291986d1c9 Mon Sep 17 00:00:00 2001 From: Carlos Gajardo Date: Fri, 15 Mar 2024 13:30:11 -0300 Subject: [PATCH 3/4] Migrate data source priority --- pagerduty/data_source_pagerduty_priority.go | 1 + pagerduty/provider.go | 1 + .../data_source_pagerduty_priority.go | 97 +++++++++++++++++++ .../data_source_pagerduty_priority_test.go | 9 +- pagerdutyplugin/provider.go | 1 + 5 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 pagerdutyplugin/data_source_pagerduty_priority.go rename {pagerduty => pagerdutyplugin}/data_source_pagerduty_priority_test.go (82%) diff --git a/pagerduty/data_source_pagerduty_priority.go b/pagerduty/data_source_pagerduty_priority.go index e969be065..5c6f7b263 100644 --- a/pagerduty/data_source_pagerduty_priority.go +++ b/pagerduty/data_source_pagerduty_priority.go @@ -12,6 +12,7 @@ import ( "github.com/heimweh/go-pagerduty/pagerduty" ) +// Deprecated: Migrated to pagerdutyplugin.dataSourcePriority. Kept for testing purposes. func dataSourcePagerDutyPriority() *schema.Resource { return &schema.Resource{ Read: dataSourcePagerDutyPriorityRead, diff --git a/pagerduty/provider.go b/pagerduty/provider.go index ca29bec28..7e0c6be8e 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -155,6 +155,7 @@ func Provider(isMux bool) *schema.Provider { if isMux { delete(p.DataSourcesMap, "pagerduty_business_service") delete(p.DataSourcesMap, "pagerduty_licenses") + delete(p.DataSourcesMap, "pagerduty_priority") delete(p.DataSourcesMap, "pagerduty_service") delete(p.DataSourcesMap, "pagerduty_service_integration") diff --git a/pagerdutyplugin/data_source_pagerduty_priority.go b/pagerdutyplugin/data_source_pagerduty_priority.go new file mode 100644 index 000000000..37e99eb32 --- /dev/null +++ b/pagerdutyplugin/data_source_pagerduty_priority.go @@ -0,0 +1,97 @@ +package pagerduty + +import ( + "context" + "fmt" + "log" + "strings" + + "github.com/PagerDuty/go-pagerduty" + "github.com/PagerDuty/terraform-provider-pagerduty/util/apiutil" + "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 dataSourcePriority struct{ client *pagerduty.Client } + +var _ datasource.DataSourceWithConfigure = (*dataSourcePriority)(nil) + +func (*dataSourcePriority) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = "pagerduty_priority" +} + +func (*dataSourcePriority) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{Computed: true}, + "name": schema.StringAttribute{ + Required: true, + Description: "The name of the priority to find in the PagerDuty API", + }, + "description": schema.StringAttribute{Computed: true}, + }, + } +} + +func (d *dataSourcePriority) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + resp.Diagnostics.Append(ConfigurePagerdutyClient(&d.client, req.ProviderData)...) +} + +func (d *dataSourcePriority) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + log.Println("[INFO] Reading PagerDuty priority") + + var searchName types.String + resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("name"), &searchName)...) + if resp.Diagnostics.HasError() { + return + } + + var found *pagerduty.Priority + err := apiutil.All(ctx, apiutil.AllFunc(func(offset int) (bool, error) { + list, err := d.client.ListPrioritiesWithContext(ctx, pagerduty.ListPrioritiesOptions{ + Limit: apiutil.Limit, + Offset: uint(offset), + }) + if err != nil { + return false, err + } + + for _, priority := range list.Priorities { + if strings.EqualFold(priority.Name, searchName.ValueString()) { + found = &priority + return false, nil + } + } + + return list.More, nil + })) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Error reading PagerDuty priority %s", searchName), + err.Error(), + ) + } + + if found == nil { + resp.Diagnostics.AddError( + fmt.Sprintf("Unable to locate any priority with the name: %s", searchName), + "", + ) + return + } + + model := dataSourcePriorityModel{ + ID: types.StringValue(found.ID), + Name: types.StringValue(found.Name), + Description: types.StringValue(found.Description), + } + resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) +} + +type dataSourcePriorityModel struct { + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Description types.String `tfsdk:"description"` +} diff --git a/pagerduty/data_source_pagerduty_priority_test.go b/pagerdutyplugin/data_source_pagerduty_priority_test.go similarity index 82% rename from pagerduty/data_source_pagerduty_priority_test.go rename to pagerdutyplugin/data_source_pagerduty_priority_test.go index 222160f0a..00dd8d709 100644 --- a/pagerduty/data_source_pagerduty_priority_test.go +++ b/pagerdutyplugin/data_source_pagerduty_priority_test.go @@ -9,8 +9,8 @@ import ( func TestAccDataSourcePagerDutyPriority_Basic(t *testing.T) { dataSourceName := "data.pagerduty_priority.p1" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyPriorityConfig, @@ -22,11 +22,12 @@ func TestAccDataSourcePagerDutyPriority_Basic(t *testing.T) { }, }) } + func TestAccDataSourcePagerDutyPriority_P2(t *testing.T) { dataSourceName := "data.pagerduty_priority.p2" resource.Test(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(), Steps: []resource.TestStep{ { Config: testAccDataSourcePagerDutyP2Config, diff --git a/pagerdutyplugin/provider.go b/pagerdutyplugin/provider.go index eba69b028..44899e9a0 100644 --- a/pagerdutyplugin/provider.go +++ b/pagerdutyplugin/provider.go @@ -57,6 +57,7 @@ func (p *Provider) DataSources(_ context.Context) [](func() datasource.DataSourc func() datasource.DataSource { return &dataSourceIntegration{} }, func() datasource.DataSource { return &dataSourceLicense{} }, func() datasource.DataSource { return &dataSourceLicenses{} }, + func() datasource.DataSource { return &dataSourcePriority{} }, func() datasource.DataSource { return &dataSourceService{} }, func() datasource.DataSource { return &dataSourceStandardsResourceScores{} }, func() datasource.DataSource { return &dataSourceStandardsResourcesScores{} }, From cae8aabd30d3105e939f83d1db435b8850e8cc7e Mon Sep 17 00:00:00 2001 From: Carlos Gajardo Date: Fri, 8 Mar 2024 14:51:26 -0300 Subject: [PATCH 4/4] Migrate resource team --- pagerduty/provider.go | 1 + pagerduty/provider_test.go | 26 ++ pagerduty/resource_pagerduty_team.go | 1 + .../import_pagerduty_team_test.go | 6 +- pagerdutyplugin/provider.go | 1 + pagerdutyplugin/resource_pagerduty_team.go | 270 ++++++++++++++++++ .../resource_pagerduty_team_test.go | 53 ++-- 7 files changed, 325 insertions(+), 33 deletions(-) rename {pagerduty => pagerdutyplugin}/import_pagerduty_team_test.go (74%) create mode 100644 pagerdutyplugin/resource_pagerduty_team.go rename {pagerduty => pagerdutyplugin}/resource_pagerduty_team_test.go (82%) diff --git a/pagerduty/provider.go b/pagerduty/provider.go index 7e0c6be8e..7de7b701f 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -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) { diff --git a/pagerduty/provider_test.go b/pagerduty/provider_test.go index 5077b3f02..57118dd9b 100644 --- a/pagerduty/provider_test.go +++ b/pagerduty/provider_test.go @@ -11,6 +11,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" ) @@ -189,6 +190,7 @@ resource "pagerduty_service" "foo" { } `, username, email, escalationPolicy, service) } + func testAccCheckPagerDutyProviderAuthWithMultipleMethodsConfig(username, email, escalationPolicy, service string) string { return fmt.Sprintf(` provider "pagerduty" { @@ -331,3 +333,27 @@ func testAccGetPagerDutyAccountDomain(t *testing.T) string { } return accountDomain } + +func testAccCheckPagerDutyTeamDestroy(s *terraform.State) error { + client, _ := testAccProvider.Meta().(*Config).Client() + for _, r := range s.RootModule().Resources { + if r.Type != "pagerduty_team" { + continue + } + + if _, _, err := client.Teams.Get(r.Primary.ID); err == nil { + 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) +} diff --git a/pagerduty/resource_pagerduty_team.go b/pagerduty/resource_pagerduty_team.go index 71dd3f8f4..3b3ee1a6e 100644 --- a/pagerduty/resource_pagerduty_team.go +++ b/pagerduty/resource_pagerduty_team.go @@ -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, diff --git a/pagerduty/import_pagerduty_team_test.go b/pagerdutyplugin/import_pagerduty_team_test.go similarity index 74% rename from pagerduty/import_pagerduty_team_test.go rename to pagerdutyplugin/import_pagerduty_team_test.go index 5dbce3a58..8094b1206 100644 --- a/pagerduty/import_pagerduty_team_test.go +++ b/pagerdutyplugin/import_pagerduty_team_test.go @@ -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), diff --git a/pagerdutyplugin/provider.go b/pagerdutyplugin/provider.go index 44899e9a0..4a6f7e795 100644 --- a/pagerdutyplugin/provider.go +++ b/pagerdutyplugin/provider.go @@ -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{} }, } } diff --git a/pagerdutyplugin/resource_pagerduty_team.go b/pagerdutyplugin/resource_pagerduty_team.go new file mode 100644 index 000000000..a9187c80e --- /dev/null +++ b/pagerdutyplugin/resource_pagerduty_team.go @@ -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 +} diff --git a/pagerduty/resource_pagerduty_team_test.go b/pagerdutyplugin/resource_pagerduty_team_test.go similarity index 82% rename from pagerduty/resource_pagerduty_team_test.go rename to pagerdutyplugin/resource_pagerduty_team_test.go index 883b0168e..fd35cdfb1 100644 --- a/pagerduty/resource_pagerduty_team_test.go +++ b/pagerdutyplugin/resource_pagerduty_team_test.go @@ -1,15 +1,16 @@ package pagerduty import ( + "context" "fmt" "log" "strings" "testing" + "github.com/PagerDuty/go-pagerduty" "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" ) func init() { @@ -25,25 +26,16 @@ func init() { } func testSweepTeam(region string) error { - config, err := sharedConfigForRegion(region) + ctx := context.Background() + response, err := testAccProvider.client.ListTeamsWithContext(ctx, pagerduty.ListTeamOptions{}) if err != nil { return err } - client, err := config.Client() - if err != nil { - return err - } - - resp, _, err := client.Teams.List(&pagerduty.ListTeamsOptions{}) - if err != nil { - return err - } - - for _, team := range resp.Teams { + for _, team := range response.Teams { if strings.HasPrefix(team.Name, "test") || strings.HasPrefix(team.Name, "tf-") { log.Printf("Destroying team %s (%s)", team.Name, team.ID) - if _, err := client.Teams.Delete(team.ID); err != nil { + if err := testAccProvider.client.DeleteTeamWithContext(ctx, team.ID); err != nil { return err } } @@ -57,9 +49,9 @@ func TestAccPagerDutyTeam_Basic(t *testing.T) { teamUpdated := 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), @@ -111,9 +103,9 @@ func TestAccPagerDutyTeam_DefaultRole(t *testing.T) { defaultRoleUpdated := "none" 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: testAccCheckPagerDutyTeamDefaultRoleConfig(team, defaultRole), @@ -143,9 +135,9 @@ func TestAccPagerDutyTeam_Parent(t *testing.T) { parent := 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: testAccCheckPagerDutyTeamWithParentConfig(team, parent), @@ -169,13 +161,14 @@ func TestAccPagerDutyTeam_Parent(t *testing.T) { } func testAccCheckPagerDutyTeamDestroy(s *terraform.State) error { - client, _ := testAccProvider.Meta().(*Config).Client() + ctx := context.Background() + for _, r := range s.RootModule().Resources { if r.Type != "pagerduty_team" { continue } - if _, _, err := client.Teams.Get(r.Primary.ID); err == nil { + if _, err := testAccProvider.client.GetTeamWithContext(ctx, r.Primary.ID); err == nil { return fmt.Errorf("Team still exists") } @@ -183,11 +176,11 @@ func testAccCheckPagerDutyTeamDestroy(s *terraform.State) error { return nil } -func testAccCheckPagerDutyTeamExists(n string) resource.TestCheckFunc { +func testAccCheckPagerDutyTeamExists(_ string) resource.TestCheckFunc { return func(s *terraform.State) error { - client, _ := testAccProvider.Meta().(*Config).Client() for _, r := range s.RootModule().Resources { - if _, _, err := client.Teams.Get(r.Primary.ID); err != nil { + ctx := context.Background() + if _, err := testAccProvider.client.GetTeamWithContext(ctx, r.Primary.ID); err != nil { return fmt.Errorf("Received an error retrieving team %s ID: %s", err, r.Primary.ID) } } @@ -246,8 +239,8 @@ func testAccExternallyDestroyTeam(n string) resource.TestCheckFunc { return fmt.Errorf("No Team ID is set") } - client, _ := testAccProvider.Meta().(*Config).Client() - _, err := client.Teams.Delete(rs.Primary.ID) + ctx := context.Background() + err := testAccProvider.client.DeleteTeamWithContext(ctx, rs.Primary.ID) if err != nil { return err }