diff --git a/client/destinations.go b/client/destinations.go
index b3823dbe..beeda5c6 100644
--- a/client/destinations.go
+++ b/client/destinations.go
@@ -39,6 +39,13 @@ type ServiceNowAttributes struct {
Auth Auth `json:"auth"`
}
+type OpsgenieAttributes struct {
+ Name string `json:"name"`
+ DestinationType string `json:"destination_type"`
+ URL string `json:"url"`
+ Auth Auth `json:"auth"`
+}
+
type Auth struct {
Username string `json:"username"`
// Password is only set for requests. Will be empty for API responses
diff --git a/docs/data-sources/stream.md b/docs/data-sources/stream.md
index 6650a55a..421c0535 100644
--- a/docs/data-sources/stream.md
+++ b/docs/data-sources/stream.md
@@ -25,3 +25,5 @@ Use this data source to retrieve information about an existing stream for use in
- `id` (String) The ID of this resource.
- `stream_name` (String)
- `stream_query` (String) Stream query
+
+
diff --git a/docs/resources/opsgenie_destination.md b/docs/resources/opsgenie_destination.md
new file mode 100644
index 00000000..6ffaa965
--- /dev/null
+++ b/docs/resources/opsgenie_destination.md
@@ -0,0 +1,37 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "lightstep_opsgenie_destination Resource - terraform-provider-lightstep"
+subcategory: ""
+description: |-
+
+---
+
+# lightstep_opsgenie_destination (Resource)
+
+
+
+
+
+
+## Schema
+
+### Required
+
+- `auth` (Block List, Min: 1, Max: 1) Basic auth used to authenticate with the Opsgenie instance (see [below for nested schema](#nestedblock--auth))
+- `destination_name` (String) Name of the Opsgenie destination
+- `project_name` (String)
+- `url` (String) Opsgenie instance URL
+
+### Read-Only
+
+- `id` (String) The ID of this resource.
+
+
+### Nested Schema for `auth`
+
+Required:
+
+- `password` (String, Sensitive)
+- `username` (String)
+
+
diff --git a/docs/resources/user_role_binding.md b/docs/resources/user_role_binding.md
index 5184cba1..8fadf038 100644
--- a/docs/resources/user_role_binding.md
+++ b/docs/resources/user_role_binding.md
@@ -94,3 +94,5 @@ resource "lightstep_user_role_binding" "proj_viewer" {
### Read-Only
- `id` (String) The ID of this resource.
+
+
diff --git a/lightstep/provider.go b/lightstep/provider.go
index cdd3b835..5013db8e 100644
--- a/lightstep/provider.go
+++ b/lightstep/provider.go
@@ -58,6 +58,7 @@ func Provider() *schema.Provider {
"lightstep_pagerduty_destination": resourcePagerdutyDestination(),
"lightstep_slack_destination": resourceSlackDestination(),
"lightstep_servicenow_destination": resourceServiceNowDestination(),
+ "lightstep_opsgenie_destination": resourceOpsgenieDestination(),
"lightstep_alerting_rule": resourceAlertingRule(),
"lightstep_dashboard": resourceUnifiedDashboard(UnifiedChartSchema),
"lightstep_alert": resourceUnifiedCondition(UnifiedConditionSchema),
diff --git a/lightstep/provider_test.go b/lightstep/provider_test.go
index 180f760b..ab9a6769 100644
--- a/lightstep/provider_test.go
+++ b/lightstep/provider_test.go
@@ -24,7 +24,7 @@ func init() {
testProject = os.Getenv("LIGHTSTEP_PROJECT")
if testProject == "" {
- testProject = "terraform-provider-tests"
+ testProject = "terraform-provider-test"
}
}
diff --git a/lightstep/resource_opsgenie_destination.go b/lightstep/resource_opsgenie_destination.go
new file mode 100644
index 00000000..4d94a364
--- /dev/null
+++ b/lightstep/resource_opsgenie_destination.go
@@ -0,0 +1,128 @@
+package lightstep
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
+
+ "github.com/lightstep/terraform-provider-lightstep/client"
+)
+
+func resourceOpsgenieDestination() *schema.Resource {
+ return &schema.Resource{
+ CreateContext: resourceOpsgenieDestinationCreate,
+ ReadContext: resourceDestinationRead,
+ DeleteContext: resourceDestinationDelete,
+ Importer: &schema.ResourceImporter{
+ StateContext: resourceOpsgenieDestinationImport,
+ },
+ Schema: map[string]*schema.Schema{
+ "project_name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "destination_name": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "Name of the Opsgenie destination",
+ },
+ "url": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ Description: "Opsgenie instance URL",
+ ValidateFunc: validation.IsURLWithScheme([]string{"https"}),
+ },
+ "auth": {
+ Type: schema.TypeList,
+ MinItems: 1,
+ MaxItems: 1,
+ Required: true,
+ ForceNew: true,
+ Description: "Basic auth used to authenticate with the Opsgenie instance",
+ Elem: &schema.Resource{
+ Schema: map[string]*schema.Schema{
+ "username": {
+ Type: schema.TypeString,
+ Required: true,
+ ForceNew: true,
+ },
+ "password": {
+ Type: schema.TypeString,
+ Sensitive: true,
+ Required: true,
+ ForceNew: true,
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+func resourceOpsgenieDestinationCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
+ c := m.(*client.Client)
+ attrs := client.OpsgenieAttributes{
+ Name: d.Get("destination_name").(string),
+ DestinationType: "opsgenie",
+ URL: d.Get("url").(string),
+ }
+ auth := d.Get("auth").([]interface{})[0].(map[string]interface{})
+ attrs.Auth = client.Auth{
+ Username: auth["username"].(string),
+ Password: auth["password"].(string),
+ }
+ dest := client.Destination{
+ Type: "destination",
+ Attributes: attrs,
+ }
+
+ destination, err := c.CreateDestination(ctx, d.Get("project_name").(string), dest)
+ if err != nil {
+ return diag.FromErr(fmt.Errorf("failed to create Opsgenie destination %v: %v", attrs.Name, err))
+ }
+
+ d.SetId(destination.ID)
+ return resourceDestinationRead(ctx, d, m)
+}
+
+func resourceOpsgenieDestinationImport(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) {
+ c := m.(*client.Client)
+
+ ids := strings.Split(d.Id(), ".")
+ if len(ids) != 2 {
+ return []*schema.ResourceData{}, fmt.Errorf("error importing lightstep_opsgenie_destination. Expecting an ID formed as '.'")
+ }
+
+ project, id := ids[0], ids[1]
+ dest, err := c.GetDestination(ctx, project, id)
+ if err != nil {
+ return []*schema.ResourceData{}, fmt.Errorf("failed to get Opsgenie destination: %v", err)
+ }
+
+ d.SetId(dest.ID)
+ if err := d.Set("project_name", project); err != nil {
+ return []*schema.ResourceData{}, fmt.Errorf("unable to set project_name resource field: %v", err)
+ }
+
+ attributes := dest.Attributes.(map[string]interface{})
+ if err := d.Set("destination_name", attributes["name"]); err != nil {
+ return []*schema.ResourceData{}, fmt.Errorf("unable to set destination_name resource field: %v", err)
+ }
+
+ if err := d.Set("url", attributes["url"]); err != nil {
+ return []*schema.ResourceData{}, fmt.Errorf("unable to set url resource field: %v", err)
+ }
+
+ if err := d.Set("auth", []interface{}{attributes["auth"]}); err != nil {
+ return []*schema.ResourceData{}, fmt.Errorf("unable to set auth resource field: %v", err)
+ }
+
+ return []*schema.ResourceData{d}, nil
+}
diff --git a/lightstep/resource_opsgenie_destination_test.go b/lightstep/resource_opsgenie_destination_test.go
new file mode 100644
index 00000000..093dce40
--- /dev/null
+++ b/lightstep/resource_opsgenie_destination_test.go
@@ -0,0 +1,150 @@
+package lightstep
+
+import (
+ "context"
+ "fmt"
+ "regexp"
+ "testing"
+
+ "github.com/lightstep/terraform-provider-lightstep/client"
+
+ "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
+ "github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
+)
+
+func TestAccOpsgenieDestination(t *testing.T) {
+ var destination client.Destination
+
+ missingUrlConfig := `
+resource "lightstep_opsgenie_destination" "missing_url" {
+ project_name = ` + fmt.Sprintf("\"%s\"", testProject) + `
+ destination_name = "my-destination"
+ auth {
+ username = ""
+ password = "pass123"
+ }
+}
+`
+ missingAuthConfig := `
+resource "lightstep_opsgenie_destination" "missing_auth" {
+ project_name = ` + fmt.Sprintf("\"%s\"", testProject) + `
+ destination_name = "my-destination"
+ url = "https://example.com"
+}
+`
+
+ destinationConfig := `
+resource "lightstep_opsgenie_destination" "opsgenie" {
+ project_name = ` + fmt.Sprintf("\"%s\"", testProject) + `
+ destination_name = "my-destination"
+ url = "https://example.com"
+ auth {
+ username = ""
+ password = "pass123"
+ }
+}
+`
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ CheckDestroy: testAccOpsgenieDestinationDestroy,
+ Steps: []resource.TestStep{
+ {
+ Config: missingUrlConfig,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckOpsgenieDestinationExists("lightstep_opsgenie_destination.missing_url", &destination),
+ ),
+ ExpectError: regexp.MustCompile("The argument \"url\" is required, but no definition was found."),
+ },
+ {
+ Config: missingAuthConfig,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckOpsgenieDestinationExists("lightstep_opsgenie_destination.missing_auth", &destination),
+ ),
+ ExpectError: regexp.MustCompile("Insufficient auth blocks"),
+ },
+ {
+ Config: destinationConfig,
+ Check: resource.ComposeTestCheckFunc(
+ testAccCheckWebhookDestinationExists("lightstep_opsgenie_destination.opsgenie", &destination),
+ resource.TestCheckResourceAttr("lightstep_opsgenie_destination.opsgenie", "destination_name", "my-destination"),
+ resource.TestCheckResourceAttr("lightstep_opsgenie_destination.opsgenie", "url", "https://example.com"),
+ resource.TestCheckResourceAttr("lightstep_opsgenie_destination.opsgenie", "auth.0.username", ""),
+ resource.TestCheckResourceAttr("lightstep_opsgenie_destination.opsgenie", "auth.0.password", "pass123"),
+ ),
+ },
+ },
+ })
+
+}
+
+func TestAccOpsgenieDestinationImport(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ Providers: testAccProviders,
+ Steps: []resource.TestStep{
+ {
+ Config: `
+resource "lightstep_opsgenie_destination" "opsgenie" {
+ project_name = ` + fmt.Sprintf("\"%s\"", testProject) + `
+ destination_name = "do-not-delete-opsgenie"
+ url = "https://example.com"
+ auth {
+ username = ""
+ password = "pass123"
+ }
+}
+`,
+ },
+ {
+ ResourceName: "lightstep_opsgenie_destination.opsgenie",
+ ImportState: true,
+ ImportStateVerify: true,
+ ImportStateVerifyIgnore: []string{"auth.0.password"},
+ ImportStateIdPrefix: fmt.Sprintf("%s.", testProject),
+ },
+ },
+ })
+}
+
+func testAccCheckOpsgenieDestinationExists(resourceName string, destination *client.Destination) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ // get destination from TF state
+ tfDestination, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ if tfDestination.Primary.ID == "" {
+ return fmt.Errorf("id is not set")
+ }
+
+ // get destination from LS
+ client := testAccProvider.Meta().(*client.Client)
+ d, err := client.GetDestination(context.Background(), testProject, tfDestination.Primary.ID)
+ if err != nil {
+ return err
+ }
+
+ destination = d
+ return nil
+ }
+}
+
+func testAccOpsgenieDestinationDestroy(s *terraform.State) error {
+ conn := testAccProvider.Meta().(*client.Client)
+ for _, resource := range s.RootModule().Resources {
+ if resource.Type != "lightstep_opsgenie_destination" {
+ continue
+ }
+
+ s, err := conn.GetDestination(context.Background(), testProject, resource.Primary.ID)
+ if err == nil {
+ if s.ID == resource.Primary.ID {
+ return fmt.Errorf("destination with ID (%v) still exists.", resource.Primary.ID)
+ }
+ }
+
+ }
+ return nil
+}