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

Migrate resource pagerduty_schedule to Terraform plugin framework #865

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
1 change: 1 addition & 0 deletions pagerduty/data_source_pagerduty_service_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/heimweh/go-pagerduty/pagerduty"
)

// Deprecated: Migrated to pagerdutyplugin.dataSourceIntegration. Kept for testing purposes.
func dataSourcePagerDutyServiceIntegration() *schema.Resource {
return &schema.Resource{
Read: dataSourcePagerDutyServiceIntegrationRead,
Expand Down
5 changes: 4 additions & 1 deletion pagerduty/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ func Provider(isMux bool) *schema.Provider {
"pagerduty_ruleset": resourcePagerDutyRuleset(),
"pagerduty_ruleset_rule": resourcePagerDutyRulesetRule(),
"pagerduty_business_service": resourcePagerDutyBusinessService(),
"pagerduty_service_dependency": resourcePagerDutyServiceDependency(),
"pagerduty_response_play": resourcePagerDutyResponsePlay(),
"pagerduty_service_event_rule": resourcePagerDutyServiceEventRule(),
"pagerduty_slack_connection": resourcePagerDutySlackConnection(),
Expand Down Expand Up @@ -150,8 +149,12 @@ func Provider(isMux bool) *schema.Provider {

if isMux {
delete(p.DataSourcesMap, "pagerduty_business_service")
delete(p.DataSourcesMap, "pagerduty_service")
delete(p.DataSourcesMap, "pagerduty_service_integration")

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

p.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Expand Down
15 changes: 15 additions & 0 deletions pagerduty/resource_pagerduty_maintenance_window_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,18 @@ resource "pagerduty_maintenance_window" "foo" {
}
`, desc, start, end)
}

func testAccCheckPagerDutyAddonDestroy(s *terraform.State) error {
client, _ := testAccProvider.Meta().(*Config).Client()
for _, r := range s.RootModule().Resources {
if r.Type != "pagerduty_addon" {
continue
}

if _, _, err := client.Addons.Get(r.Primary.ID); err == nil {
return fmt.Errorf("Add-on still exists")
}

}
return nil
}
23 changes: 14 additions & 9 deletions pagerdutyplugin/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ type Config struct {
mu sync.Mutex

// The PagerDuty API URL
ApiUrl string
APIURL string

// Override default PagerDuty API URL
ApiUrlOverride string
APIURLOverride string

// The PagerDuty APP URL
AppUrl string
AppURL string

// The PagerDuty API V2 token
Token string
Expand All @@ -52,7 +52,7 @@ type Config struct {
}

type AppOauthScopedToken struct {
ClientId, ClientSecret, Subdomain string
ClientID, ClientSecret, Subdomain string
}

const invalidCreds = `
Expand All @@ -61,6 +61,11 @@ Please see https://www.terraform.io/docs/providers/pagerduty/index.html
for more information on providing credentials for this provider.
`

// RetryNotFound is defined to have a named boolean when passing it to
// requestThing functions. If true, they should be further attempts to get a
// resource from the API even if we receive a 404 during a time window.
const RetryNotFound = true

// Client returns a PagerDuty client, initializing when necessary.
func (c *Config) Client(ctx context.Context) (*pagerduty.Client, error) {
c.mu.Lock()
Expand All @@ -75,17 +80,17 @@ func (c *Config) Client(ctx context.Context) (*pagerduty.Client, error) {
httpClient.Timeout = 1 * time.Minute
httpClient.Transport = logging.NewTransport("PagerDuty", http.DefaultTransport)

apiUrl := c.ApiUrl
if c.ApiUrlOverride != "" {
apiUrl = c.ApiUrlOverride
apiURL := c.APIURL
if c.APIURLOverride != "" {
apiURL = c.APIURLOverride
}

maxRetries := 1
retryInterval := 60 // seconds

clientOpts := []pagerduty.ClientOptions{
WithHTTPClient(httpClient),
pagerduty.WithAPIEndpoint(apiUrl),
pagerduty.WithAPIEndpoint(apiURL),
pagerduty.WithTerraformProvider(c.TerraformVersion),
pagerduty.WithRetryPolicy(maxRetries, retryInterval),
}
Expand All @@ -97,7 +102,7 @@ func (c *Config) Client(ctx context.Context) (*pagerduty.Client, error) {
accountAndScopes = append(accountAndScopes, availableOauthScopes()...)
opt := pagerduty.WithScopedOAuthAppTokenSource(pagerduty.NewFileTokenSource(
ctx,
c.AppOauthScopedToken.ClientId,
c.AppOauthScopedToken.ClientID,
c.AppOauthScopedToken.ClientSecret,
accountAndScopes,
tokenFile,
Expand Down
6 changes: 3 additions & 3 deletions pagerdutyplugin/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestConfigSkipCredsValidation(t *testing.T) {
func TestConfigCustomApiUrl(t *testing.T) {
config := Config{
Token: "foo",
ApiUrl: "https://api.domain.tld",
APIURL: "https://api.domain.tld",
SkipCredsValidation: true,
}

Expand All @@ -45,7 +45,7 @@ func TestConfigCustomApiUrl(t *testing.T) {
func TestConfigCustomApiUrlOverride(t *testing.T) {
config := Config{
Token: "foo",
ApiUrlOverride: "https://api.domain-override.tld",
APIURLOverride: "https://api.domain-override.tld",
SkipCredsValidation: true,
}

Expand All @@ -58,7 +58,7 @@ func TestConfigCustomApiUrlOverride(t *testing.T) {
func TestConfigCustomAppUrl(t *testing.T) {
config := Config{
Token: "foo",
AppUrl: "https://app.domain.tld",
AppURL: "https://app.domain.tld",
SkipCredsValidation: true,
}

Expand Down
6 changes: 3 additions & 3 deletions pagerdutyplugin/data_source_pagerduty_business_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ type dataSourceBusinessService struct{ client *pagerduty.Client }

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

func (*dataSourceBusinessService) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
func (*dataSourceBusinessService) Metadata(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = "pagerduty_business_service"
}

func (*dataSourceBusinessService) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
func (*dataSourceBusinessService) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{Computed: true},
Expand All @@ -33,7 +33,7 @@ func (*dataSourceBusinessService) Schema(ctx context.Context, req datasource.Sch
}
}

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

Expand Down
6 changes: 3 additions & 3 deletions pagerdutyplugin/data_source_pagerduty_extension_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ type dataSourceExtensionSchema struct{ client *pagerduty.Client }

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

func (*dataSourceExtensionSchema) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
func (*dataSourceExtensionSchema) Metadata(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = "pagerduty_extension_schema"
}

func (*dataSourceExtensionSchema) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
func (*dataSourceExtensionSchema) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{Computed: true},
Expand All @@ -34,7 +34,7 @@ func (*dataSourceExtensionSchema) Schema(ctx context.Context, req datasource.Sch
}
}

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

Expand Down
18 changes: 0 additions & 18 deletions pagerdutyplugin/data_source_pagerduty_extension_schema_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package pagerduty

import (
"context"
"fmt"
"testing"

"github.com/PagerDuty/go-pagerduty"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
)
Expand Down Expand Up @@ -56,19 +54,3 @@ data "pagerduty_extension_schema" "foo" {
name = "ServiceNow (v7)"
}
`

func testAccCheckPagerDutyScheduleDestroy(s *terraform.State) error {
for _, r := range s.RootModule().Resources {
if r.Type != "pagerduty_schedule" {
continue
}

ctx := context.Background()
opts := pagerduty.GetScheduleOptions{}
if _, err := testAccProvider.client.GetScheduleWithContext(ctx, r.Primary.ID, opts); err == nil {
return fmt.Errorf("Schedule still exists")
}

}
return nil
}
147 changes: 147 additions & 0 deletions pagerdutyplugin/data_source_pagerduty_integration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
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/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
)

type dataSourceIntegration struct{ client *pagerduty.Client }

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

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

func (*dataSourceIntegration) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{Computed: true},
"service_name": schema.StringAttribute{Required: true},
"integration_key": schema.StringAttribute{Computed: true, Sensitive: true},
"integration_summary": schema.StringAttribute{
Required: true,
Description: `examples "Amazon CloudWatch", "New Relic"`,
},
},
}
}

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

func (d *dataSourceIntegration) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
log.Println("[INFO] Reading PagerDuty service integration")

var searchName types.String
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("service_name"), &searchName)...)
if resp.Diagnostics.HasError() {
return
}

var found *pagerduty.Service
err := retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
list, err := d.client.ListServicesWithContext(ctx, pagerduty.ListServiceOptions{})
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}

for _, service := range list.Services {
if service.Name == searchName.ValueString() {
found = &service
break
}
}
return nil
})
if err != nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Error reading PagerDuty service integration %s", searchName),
err.Error(),
)
}

if found == nil {
resp.Diagnostics.AddError(
fmt.Sprintf("Unable to locate any service with the name: %s", searchName),
"",
)
return
}

var summary types.String
resp.Diagnostics.Append(req.Config.GetAttribute(ctx, path.Root("integration_summary"), &summary)...)
if resp.Diagnostics.HasError() {
return
}

var foundIntegration *pagerduty.Integration
for _, integration := range found.Integrations {
if strings.EqualFold(integration.Summary, summary.ValueString()) {
foundIntegration = &integration
break
}
}

if foundIntegration == nil {
resp.Diagnostics.Append(dataSourceIntegrationNotFoundError(nil, searchName, summary))
return
}

var model dataSourceIntegrationModel
err = retry.RetryContext(ctx, 2*time.Minute, func() *retry.RetryError {
details, err := d.client.GetIntegrationWithContext(ctx, found.ID, foundIntegration.ID, pagerduty.GetIntegrationOptions{})
if err != nil {
if util.IsBadRequestError(err) {
return retry.NonRetryableError(err)
}
return retry.RetryableError(err)
}

model = dataSourceIntegrationModel{
ID: types.StringValue(foundIntegration.ID),
ServiceName: types.StringValue(found.Name),
IntegrationKey: types.StringValue(details.IntegrationKey),
}
return nil
})
if err != nil {
resp.Diagnostics.Append(dataSourceIntegrationNotFoundError(err, searchName, summary))
}

resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}

type dataSourceIntegrationModel struct {
ID types.String `tfsdk:"id"`
ServiceName types.String `tfsdk:"service_name"`
IntegrationKey types.String `tfsdk:"integration_key"`
IntegrationSummary types.String `tfsdk:"integration_summary"`
}

func dataSourceIntegrationNotFoundError(err error, service, summary types.String) diag.Diagnostic {
errMsg := ""
if err != nil {
errMsg = err.Error()
}
return diag.NewErrorDiagnostic(
fmt.Sprintf("Unable to locate any integration of type %s on service %s", summary, service),
errMsg,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ func TestAccDataSourcePagerDutyIntegration_Basic(t *testing.T) {
serviceIntegration := "Datadog"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
PreCheck: func() { testAccPreCheck(t) },
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(),
Steps: []resource.TestStep{
{
Config: testAccDataSourcePagerDutyIntegrationConfigStep1(service, serviceIntegration, email, escalationPolicy),
Check: func(state *terraform.State) error {
resource.Test(t, resource.TestCase{
Providers: testAccProviders,
ProtoV5ProviderFactories: testAccProtoV5ProviderFactories(),
Steps: []resource.TestStep{
{
Config: testAccDataSourcePagerDutyIntegrationConfigStep2(service, serviceIntegration),
Check: verifyOutput("output_id"),
}},
},
},
})
return nil
},
Expand Down
Loading
Loading