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

Manage extension configuration as plain JSON #84

Merged
merged 9 commits into from
Aug 16, 2018
Merged

Manage extension configuration as plain JSON #84

merged 9 commits into from
Aug 16, 2018

Conversation

pdecat
Copy link
Contributor

@pdecat pdecat commented May 9, 2018

This PR adds support to manage the configuration of extensions.

It is done as plain JSON as the configuration part differs from vendor to vendor: https://v2.developer.pagerduty.com/v2/page/api-reference#!/Extension_Schemas/get_extension_schemas

TODO:

Note: upgrading terraform dependencies as done in https://github.com/pdecat/terraform-provider-pagerduty/tree/upgrade-terraform-deps would allow for more readable terraform configuration snippets using structured locals and advanced jsonencode():

locals {
  extension_config_slack = {
    restrict = "any"

    notify_types {
      resolve     = false
      acknowledge = false
      assignments = false
    }
  }
}

resource "pagerduty_extension" "foo"{
...
  config = "${jsonencode(local.extension_config_slack)}"
}

pdecat added 3 commits June 1, 2018 00:19
…nsion-config branch:

    govendor fetch github.com/heimweh/go-pagerduty/pagerduty::github.com/pdecat/go-pagerduty/pagerduty@=f-extension-config
@pdecat
Copy link
Contributor Author

pdecat commented Jul 10, 2018

Hi @heimweh, what do you think about this change?

If it sounds good to you, I'll proceed with the remaining work.

@pdecat
Copy link
Contributor Author

pdecat commented Jul 10, 2018

Depends on heimweh/go-pagerduty#22

@haines
Copy link

haines commented Jul 10, 2018

Was just looking for a way to do this! If this change is accepted I'd be keen to make a similar one for pagerduty_service_integration.

@samm-git
Copy link

samm-git commented Aug 1, 2018

@pdecat just tested this patch with slack extension - works really good! I been able to create already authorized extension using access_token field.
@heimweh - is there any chance to get this accepted to master?

@pdecat
Copy link
Contributor Author

pdecat commented Aug 9, 2018

@samm-git thanks for this info! I did not expect this would work for access_token.

Copy link
Collaborator

@heimweh heimweh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @pdecat, thank you so much for the PR and sorry for the delay. I added some comments, nothing super critical and overall it looks good but would you be able to update the documentation as well?

Many thanks!

Best regards,

Alexander

Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.ValidateJsonString,
DiffSuppressFunc: jsonExtensionConfigDiffSuppress,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, done.

@@ -58,6 +67,7 @@ func buildExtensionStruct(d *schema.ResourceData) *pagerduty.Extension {
ID: d.Get("extension_schema").(string),
},
ExtensionObjects: expandServiceObjects(d.Get("extension_objects")),
Config: expandExtensionConfig(d.Get("config")),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an optional field I believe you must check if the field is in the configuration using GetOk.

Example:

if v, ok := d.GetOk("config"); ok {
  Extension.Config = v
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, this will avoid misleading unmarshalling errors.
Done.

@@ -174,3 +188,35 @@ func flattenExtensionObjects(serviceList []*pagerduty.ServiceReference) interfac
}
return services
}

func expandExtensionConfig(v interface{}) interface{} {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generic ExpandJsonFromString() function provided by terraform unmarshals JSON-encoded data into map[string]interface{} instead of interface{}

Same for flattenExtensionConfig() that marshals a map[string]interface{} value into JSON-encoded data.

I believe using those would require to change the type of the terraform configuration field config from TypeString to TypeMap and specify a schema for this map.
That last part is what I'm trying to avoid here as this would require to enumerate all possible configuration options.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah makes sense 👍 let's keep it as-is then.

@pdecat
Copy link
Contributor Author

pdecat commented Aug 14, 2018

Hi @heimweh , thanks for your feedback.
I'll be happy to update the documentation once the expand/flatten part is settled as I believe changing it would require to change the configuration format too.

@heimweh
Copy link
Collaborator

heimweh commented Aug 14, 2018

Hi @pdecat, nice work! I agree, let's leave the flatten/expand funcs as they are. I'll do a final review when the documentation is in place. Thank you so much for this!

Best regards,

Alexander

@pdecat
Copy link
Contributor Author

pdecat commented Aug 14, 2018

Great, documentation added.

@@ -98,6 +111,10 @@ func resourcePagerDutyExtensionRead(d *schema.ResourceData, meta interface{}) er
}
d.Set("extension_schema", extension.ExtensionSchema)

if err := d.Set("config", flattenExtensionConfig(extension.Config)); err != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The schema expects a string here but is actually a []byte so this won't work.
Think you must wrap a string() here or have the flatten func return a string.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it does work as is as the acceptance tests pass.

Also, I'm using it with success on our own stack.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sure it works correctly but the problem here is that we're failing to set config as returned by the API (it's never updated).

Note: I'm seeing error setting extension config when I'm running the acctests.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense to me now, thanks!

"acknowledge": false,
"assignments": false
},
"access_token": "XXX"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No biggie but the indentation here looks a bit off :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@@ -68,10 +68,12 @@ func TestAccPagerDutyExtension_Basic(t *testing.T) {
"pagerduty_extension.foo", "extension_schema", "PJFWPEP"),
resource.TestCheckResourceAttr(
"pagerduty_extension.foo", "endpoint_url", url),
resource.TestCheckResourceAttr(
"pagerduty_extension.foo", "config", "{\n\t\"restrict\": \"any\",\n\t\"notify_types\": {\n\t\t\t\"resolve\": false,\n\t\t\t\"acknowledge\": false,\n\t\t\t\"assignments\": false\n\t}\n}\n"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be:

"pagerduty_extension.foo", "config", "{\"notify_types\":{\"acknowledge\":false,\"assignments\":false,\"resolve\":false},\"restrict\":\"any\"}"),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this makes the acceptance to fail:

# make testacc TEST=./pagerduty/ TESTARGS='-run=TestAccPagerDutyExtension_Basic'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./pagerduty/ -v -run=TestAccPagerDutyExtension_Basic -timeout 120m
=== RUN   TestAccPagerDutyExtension_Basic
--- FAIL: TestAccPagerDutyExtension_Basic (10.67s)
        testing.go:459: Step 0 error: Check failed: Check 5/5 error: pagerduty_extension.foo: Attribute 'config' expected "{\"restrict\": \"any\",\"notify_types\": {\"resolve\": false,\"acknowledge\": false,\"assignments\": false}}", got "{\n\t\"restrict\": \"any\",\n\t\"notify_types\": {\n\t\t\t\"resolve\": false,\n\t\t\t\"acknowledge\": false,\n\t\t\t\"assignments\": false\n\t}\n}\n"
FAIL
FAIL    github.com/terraform-providers/terraform-provider-pagerduty/pagerduty   10.674s
GNUmakefile:17: recipe for target 'testacc' failed
make: *** [testacc] Error 1

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's due to the d.Set issue above,
because we're not actually reading back the config from the API.

@@ -80,6 +82,8 @@ func TestAccPagerDutyExtension_Basic(t *testing.T) {
"pagerduty_extension.foo", "extension_schema", "PJFWPEP"),
resource.TestCheckResourceAttr(
"pagerduty_extension.foo", "endpoint_url", url_updated),
resource.TestCheckResourceAttr(
"pagerduty_extension.foo", "config", "{\n\t\"restrict\": \"pd-users\",\n\t\"notify_types\": {\n\t\t\t\"resolve\": true,\n\t\t\t\"acknowledge\": true,\n\t\t\t\"assignments\": true\n\t}\n}\n"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this should be:

"pagerduty_extension.foo", "config", "{\"notify_types\":{\"acknowledge\":true,\"assignments\":true,\"resolve\":true},\"restrict\":\"pd-users\"}"),

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

@pdecat
Copy link
Contributor Author

pdecat commented Aug 16, 2018

Acceptance tests results

# make testacc TEST=./pagerduty/ TESTARGS='-run=TestAccPagerDutyExtension_Basic'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./pagerduty/ -v -run=TestAccPagerDutyExtension_Basic -timeout 120m
=== RUN   TestAccPagerDutyExtension_Basic
--- PASS: TestAccPagerDutyExtension_Basic (18.65s)
PASS
ok      github.com/terraform-providers/terraform-provider-pagerduty/pagerduty   18.655s

@heimweh
Copy link
Collaborator

heimweh commented Aug 16, 2018

I got it to work using the following patch:

diff --git a/pagerduty/resource_pagerduty_extension.go b/pagerduty/resource_pagerduty_extension.go
index 7a7da32..13c9894 100644
--- a/pagerduty/resource_pagerduty_extension.go
+++ b/pagerduty/resource_pagerduty_extension.go
@@ -207,5 +207,5 @@ func flattenExtensionConfig(config interface{}) interface{} {
                log.Printf("[ERROR] Could not marshal extension config %s: %v", config.(string), err)
                return nil
        }
-       return json
+       return string(json)
 }
diff --git a/pagerduty/resource_pagerduty_extension_test.go b/pagerduty/resource_pagerduty_extension_test.go
index 7650404..876582b 100644
--- a/pagerduty/resource_pagerduty_extension_test.go
+++ b/pagerduty/resource_pagerduty_extension_test.go
@@ -69,7 +69,7 @@ func TestAccPagerDutyExtension_Basic(t *testing.T) {
                                        resource.TestCheckResourceAttr(
                                                "pagerduty_extension.foo", "endpoint_url", url),
                                        resource.TestCheckResourceAttr(
-                                               "pagerduty_extension.foo", "config", "{\n\t\"restrict\": \"any\",\n\t\"notify_types\": {\n\t\t\t\"resolve\": false,\n\t\t\t\"acknowledge\": false,\n\t\t\t\"assignments\": false\n\t}\n}\n"),
+                                               "pagerduty_extension.foo", "config", "{\"notify_types\":{\"acknowledge\":false,\"assignments\":false,\"resolve\":false},\"restrict\":\"any\"}"),
                                ),
                        },
                        {
@@ -83,7 +83,7 @@ func TestAccPagerDutyExtension_Basic(t *testing.T) {
                                        resource.TestCheckResourceAttr(
                                                "pagerduty_extension.foo", "endpoint_url", url_updated),
                                        resource.TestCheckResourceAttr(
-                                               "pagerduty_extension.foo", "config", "{\n\t\"restrict\": \"pd-users\",\n\t\"notify_types\": {\n\t\t\t\"resolve\": true,\n\t\t\t\"acknowledge\": true,\n\t\t\t\"assignments\": true\n\t}\n}\n"),
+                                               "pagerduty_extension.foo", "config", "{\"notify_types\":{\"acknowledge\":true,\"assignments\":true,\"resolve\":true},\"restrict\":\"pd-users\"}"),
                                ),
                        },
                },
TF_ACC=1 go test ./pagerduty -v -run=TestAccPagerDutyExtension -timeout 120m
=== RUN   TestAccPagerDutyExtension_import
--- PASS: TestAccPagerDutyExtension_import (16.27s)
=== RUN   TestAccPagerDutyExtension_Basic
--- PASS: TestAccPagerDutyExtension_Basic (19.89s)
PASS
ok      github.com/terraform-providers/terraform-provider-pagerduty/pagerduty   36.175s

@pdecat
Copy link
Contributor Author

pdecat commented Aug 16, 2018

Ok, got it, thanks!

Copy link
Collaborator

@heimweh heimweh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much for this contribution @pdecat! this will be a great addition to the provider 🙏

This LGTM 👍

@heimweh heimweh merged commit 4e2304a into PagerDuty:master Aug 16, 2018
@pdecat pdecat deleted the f-extension-config branch August 17, 2018 05:58
@anirban1c
Copy link

Is this only using slack ? looking to automation adding extentions for MS Teams, is there an example ?

@pdecat
Copy link
Contributor Author

pdecat commented Aug 26, 2020

Hi @anirban1c, the config field should work with all extension schemas that support it.

You can get the extension schema for Microsoft Teams (id P6VL8WI) by invoking the Get an extension vendor API: https://developer.pagerduty.com/api-reference/reference/REST/openapiv3.json/paths/~1extension_schemas~1%7Bid%7D/get

Currently, the API documentation states it supports only one setting:

    "config": {
      "secret": {
        "encrypted": true
      }
    },

You may get additional fields from actual API responses once you create pagerduty_extension resources with terraform.
I'd then suggest to add them to your terraform configuration.

@anirban1c
Copy link

thanks @pdecat, just to clarify this will work with the new integration ? and not the legacy MS Teams V1 integration ?

@pdecat
Copy link
Contributor Author

pdecat commented Aug 26, 2020

I only see one MS Teams extension in the API and the UI.

@anirban1c
Copy link

this is whats confusing me :
on Teams:

The PagerDuty (Legacy) connector sends notifications about triggered incidents. To use this connector, you'll need to create certain settings on the PagerDuty website by following a few easy steps. If you don't already have an account, create one on the PagerDuty (Legacy) website.

@anirban1c
Copy link

MS teams integration works just fine from the UI and notifications flowing btw

@anirban1c
Copy link

this is what I get, let me try this in TF and wondering if anyone has got this working ?

In [10]: json.loads(r.content)
Out[10]:
{'extension_schema': {'id': 'P6VL8WI',
'type': 'extension_schema',
'summary': 'Microsoft Teams',
'self': 'https://api.pagerduty.com/extension_schemas/P6VL8WI',
'html_url': None,
'key': 'msteams',
'label': 'Microsoft Teams',
'description': '',
'url': 'https://app.pagerduty.com/ms-teams/pd_webhooks',
'guide_url': '',
'icon_url': 'https://pdpartner.s3.amazonaws.com/extensions_portal/ms-teams-100.png',
'logo_url': 'https://pdpartner.s3.amazonaws.com/extensions_portal/ms-teams-100.png',
'features': [],
'authorizable': False,
'config': {'secret': {'encrypted': True}},
'send_types': ['trigger',
'acknowledge',
'resolve',
'reopen',
'delegate',
'escalate',
'unacknowledge',
'assign',
'annotate'],
'addon': {'id': 'PQWF3WV',
'type': 'addon_reference',
'summary': 'Microsoft Teams Integration',
'self': 'https://api.pagerduty.com/base_addons/PQWF3WV',
'html_url': None},
'buttons': []}}

In [11]:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants