From 648b23bb0900992779f30be46245b5c1c3daef03 Mon Sep 17 00:00:00 2001 From: Stephen Jung Date: Wed, 28 Feb 2018 16:56:33 -0800 Subject: [PATCH 1/3] Add resource for integrations We only use Slack and PagerDuty here, but adding support for others should be straightforward. --- docs/index.md | 1 + docs/resources/integration.md | 27 ++++ .../signalform/integration.go | 118 ++++++++++++++++++ .../signalform/provider.go | 1 + 4 files changed, 147 insertions(+) create mode 100644 docs/resources/integration.md create mode 100644 src/terraform-provider-signalform/signalform/integration.go diff --git a/docs/index.md b/docs/index.md index 4eafad5..a3bdc9a 100644 --- a/docs/index.md +++ b/docs/index.md @@ -25,6 +25,7 @@ Changelog is available [here](https://github.com/Yelp/terraform-provider-signalf * [Text Note](https://yelp.github.io/terraform-provider-signalform/resources/text_note.html) * [Dashboard](https://yelp.github.io/terraform-provider-signalform/resources/dashboard.html) * [Dashboard Group](https://yelp.github.io/terraform-provider-signalform/resources/dashboard_group.html) + * [Integration](https://yelp.github.io/terraform-provider-signalform/resources/integration.html) * [Build And Install](#build-and-install) * [Build binary from source](#build-binary-from-source) * [Build debian package from source](#build-debian-package-from-source) diff --git a/docs/resources/integration.md b/docs/resources/integration.md new file mode 100644 index 0000000..6725091 --- /dev/null +++ b/docs/resources/integration.md @@ -0,0 +1,27 @@ +# Integration + +SignalFx supports integrations to ingest metrics from other monitoring systems, connect to Single Sign-On providers, and to report notifications for messaging and incident management. Note that your SignalForm API key must have admin permissions to use the SignalFx integration API. + +## Example Usage + +```terraform +resource "signalform_integration" "pagerduty_myteam" { + provider = "signalform" + name = "PD - My Team" + enabled = true + type = "PagerDuty" + api_key = "1234567890" +} +``` + +## Argument Reference + +* `name` - (Required) Name of the integration. +* `enabled` - (Required) Whether the integration is enabled. +* `type` - (Required) Type of the integration. See the full list at . +* `api_key` - (Required for `PagerDuty`) PagerDuty API key. +* `webhook_url` - (Required for `Slack`) Slack incoming webhook URL. + +**Notes** + +This resource does not support all known types of integration. Contributions are welcome to implement more types. diff --git a/src/terraform-provider-signalform/signalform/integration.go b/src/terraform-provider-signalform/signalform/integration.go new file mode 100644 index 0000000..c2d84ca --- /dev/null +++ b/src/terraform-provider-signalform/signalform/integration.go @@ -0,0 +1,118 @@ +package signalform + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/terraform/helper/schema" + "strings" +) + +const ( + INTEGRATION_API_URL = "https://api.signalfx.com/v2/integration" +) + +func integrationResource() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Name of the integration", + }, + "enabled": &schema.Schema{ + Type: schema.TypeBool, + Required: true, + Description: "Whether the integration is enabled or not", + }, + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + Description: "Type of the integration", + ValidateFunc: validateIntegrationType, + }, + "api_key": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "PagerDuty API key", + Sensitive: true, + ConflictsWith: []string{"webhook_url"}, + }, + "webhook_url": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "Slack Incoming Webhook URL", + Sensitive: true, + ConflictsWith: []string{"api_key"}, + }, + }, + + Create: integrationCreate, + Read: integrationRead, + Update: integrationUpdate, + Delete: integrationDelete, + } +} + +func validateIntegrationType(v interface{}, k string) (we []string, errors []error) { + value := v.(string) + allowedWords := []string{"PagerDuty", "Slack"} + for _, word := range allowedWords { + if value == word { + return + } + } + errors = append(errors, fmt.Errorf("%s not allowed; must be one of: %s", value, strings.Join(allowedWords, ", "))) + return +} + +func getPayloadIntegration(d *schema.ResourceData) ([]byte, error) { + integrationType := d.Get("type").(string) + payload := map[string]interface{}{ + "name": d.Get("name").(string), + "enabled": d.Get("enabled").(bool), + "type": integrationType, + } + + switch integrationType { + case "PagerDuty": + payload["apiKey"] = d.Get("api_key").(string) + case "Slack": + payload["webhookUrl"] = d.Get("webhook_url").(string) + } + + return json.Marshal(payload) +} + +func integrationCreate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*signalformConfig) + payload, err := getPayloadIntegration(d) + if err != nil { + return fmt.Errorf("Failed creating json payload: %s", err.Error()) + } + + return resourceCreate(INTEGRATION_API_URL, config.AuthToken, payload, d) +} + +func integrationRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*signalformConfig) + url := fmt.Sprintf("%s/%s", INTEGRATION_API_URL, d.Id()) + + return resourceRead(url, config.AuthToken, d) +} + +func integrationUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*signalformConfig) + payload, err := getPayloadIntegration(d) + if err != nil { + return fmt.Errorf("Failed creating json payload: %s", err.Error()) + } + url := fmt.Sprintf("%s/%s", INTEGRATION_API_URL, d.Id()) + + return resourceUpdate(url, config.AuthToken, payload, d) +} + +func integrationDelete(d *schema.ResourceData, meta interface{}) error { + config := meta.(*signalformConfig) + url := fmt.Sprintf("%s/%s", INTEGRATION_API_URL, d.Id()) + return resourceDelete(url, config.AuthToken, d) +} diff --git a/src/terraform-provider-signalform/signalform/provider.go b/src/terraform-provider-signalform/signalform/provider.go index e9e9f32..910fb98 100644 --- a/src/terraform-provider-signalform/signalform/provider.go +++ b/src/terraform-provider-signalform/signalform/provider.go @@ -40,6 +40,7 @@ func Provider() terraform.ResourceProvider { "signalform_text_chart": textChartResource(), "signalform_dashboard": dashboardResource(), "signalform_dashboard_group": dashboardGroupResource(), + "signalform_integration": integrationResource(), }, ConfigureFunc: signalformConfigure, } From ae979606e052ecd0a92fc9cd385b56fc31a971cc Mon Sep 17 00:00:00 2001 From: Joshua Coats Date: Mon, 9 Apr 2018 13:37:28 -0700 Subject: [PATCH 2/3] Opt out of sending test/validation messages to integrations per the docs at https://developers.signalfx.com/v2/reference#integration-1 --- src/terraform-provider-signalform/signalform/integration.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/terraform-provider-signalform/signalform/integration.go b/src/terraform-provider-signalform/signalform/integration.go index c2d84ca..5a85b11 100644 --- a/src/terraform-provider-signalform/signalform/integration.go +++ b/src/terraform-provider-signalform/signalform/integration.go @@ -3,8 +3,9 @@ package signalform import ( "encoding/json" "fmt" - "github.com/hashicorp/terraform/helper/schema" "strings" + + "github.com/hashicorp/terraform/helper/schema" ) const ( @@ -89,8 +90,9 @@ func integrationCreate(d *schema.ResourceData, meta interface{}) error { if err != nil { return fmt.Errorf("Failed creating json payload: %s", err.Error()) } + url := fmt.Sprintf("%s?skipValidation=true", INTEGRATION_API_URL) - return resourceCreate(INTEGRATION_API_URL, config.AuthToken, payload, d) + return resourceCreate(url, config.AuthToken, payload, d) } func integrationRead(d *schema.ResourceData, meta interface{}) error { From ffea7756003e8522f6d9e9eb95d3fb273c52f6d1 Mon Sep 17 00:00:00 2001 From: Joshua Coats Date: Mon, 9 Apr 2018 15:30:51 -0700 Subject: [PATCH 3/3] Add synced and last_updated fields --- .../signalform/integration.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/terraform-provider-signalform/signalform/integration.go b/src/terraform-provider-signalform/signalform/integration.go index 5a85b11..536da1f 100644 --- a/src/terraform-provider-signalform/signalform/integration.go +++ b/src/terraform-provider-signalform/signalform/integration.go @@ -15,6 +15,17 @@ const ( func integrationResource() *schema.Resource { return &schema.Resource{ Schema: map[string]*schema.Schema{ + "synced": &schema.Schema{ + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: "Whether the resource in SignalForm and SignalFx are identical or not. Used internally for syncing.", + }, + "last_updated": &schema.Schema{ + Type: schema.TypeFloat, + Computed: true, + Description: "Latest timestamp the resource was updated", + }, "name": &schema.Schema{ Type: schema.TypeString, Required: true,