Skip to content

Commit 72e61bd

Browse files
add sumologic_connection resource
1 parent e81e409 commit 72e61bd

File tree

6 files changed

+548
-0
lines changed

6 files changed

+548
-0
lines changed

sumologic/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ func Provider() terraform.ResourceProvider {
5151
"sumologic_scheduled_view": resourceSumologicScheduledView(),
5252
"sumologic_partition": resourceSumologicPartition(),
5353
"sumologic_field_extraction_rule": resourceSumologicFieldExtractionRule(),
54+
"sumologic_connection": resourceSumologicConnection(),
5455
},
5556
DataSourcesMap: map[string]*schema.Resource{
5657
"sumologic_caller_identity": dataSourceSumologicCallerIdentity(),
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"regexp"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
10+
)
11+
12+
func resourceSumologicConnection() *schema.Resource {
13+
nameValidation := `^([a-zA-Z0-9 +%\-@.,_()]+)$`
14+
return &schema.Resource{
15+
Create: resourceSumologicConnectionCreate,
16+
Read: resourceSumologicConnectionRead,
17+
Delete: resourceSumologicConnectionDelete,
18+
Update: resourceSumologicConnectionUpdate,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
23+
Schema: map[string]*schema.Schema{
24+
"type": {
25+
Type: schema.TypeString,
26+
Required: true,
27+
ForceNew: true,
28+
// Only WebhookConnection is supported right now
29+
ValidateFunc: validation.StringInSlice([]string{"WebhookConnection"}, false),
30+
},
31+
"name": {
32+
Type: schema.TypeString,
33+
Required: true,
34+
ForceNew: false,
35+
ValidateFunc: validation.All(
36+
validation.StringLenBetween(1, 128),
37+
validation.StringMatch(regexp.MustCompile(nameValidation), fmt.Sprintf("Must match regex %s", nameValidation)),
38+
),
39+
},
40+
"description": {
41+
Type: schema.TypeString,
42+
Optional: true,
43+
ForceNew: false,
44+
ValidateFunc: validation.StringLenBetween(0, 1024),
45+
Default: "",
46+
},
47+
"url": {
48+
Type: schema.TypeString,
49+
Optional: true,
50+
ForceNew: false,
51+
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
52+
},
53+
"headers": {
54+
Type: schema.TypeMap,
55+
Elem: &schema.Schema{
56+
Type: schema.TypeString,
57+
},
58+
Optional: true,
59+
ForceNew: false,
60+
Default: map[string]interface{}{},
61+
},
62+
"custom_headers": {
63+
Type: schema.TypeMap,
64+
Elem: &schema.Schema{
65+
Type: schema.TypeString,
66+
},
67+
Optional: true,
68+
ForceNew: false,
69+
Default: map[string]interface{}{},
70+
},
71+
"default_payload": {
72+
Type: schema.TypeString,
73+
Required: true,
74+
ForceNew: false,
75+
ValidateFunc: validation.StringIsJSON,
76+
},
77+
"webhook_type": {
78+
Type: schema.TypeString,
79+
Optional: true,
80+
ForceNew: false,
81+
ValidateFunc: validation.StringInSlice([]string{"AWSLambda", "Azure", "Datadog", "HipChat", "PagerDuty", "Slack", "Webhook", "NewRelic"}, false),
82+
Default: "Webhook",
83+
},
84+
},
85+
}
86+
}
87+
88+
func resourceSumologicConnectionRead(d *schema.ResourceData, meta interface{}) error {
89+
log.Println("====Begin Connection Read====")
90+
91+
c := meta.(*Client)
92+
id := d.Id()
93+
log.Printf("Connection Id from schema: %s", id)
94+
95+
connection, err := c.GetConnection(id)
96+
if err != nil {
97+
return err
98+
}
99+
100+
if connection == nil {
101+
log.Printf("Connection not found, removing from state: %v - %v", id, err)
102+
d.SetId("")
103+
return nil
104+
}
105+
106+
// Write the newly read connection into the schema
107+
d.Set("type", connection.Type)
108+
d.Set("name", connection.Name)
109+
d.Set("description", connection.Description)
110+
d.Set("url", connection.URL)
111+
d.Set("headers", headersToMap(connection.Headers))
112+
d.Set("custom_headers", headersToMap(connection.CustomHeaders))
113+
d.Set("default_payload", connection.DefaultPayload)
114+
d.Set("webhook_type", connection.WebhookType)
115+
d.SetId(connection.ID)
116+
117+
log.Println("====End Connection Read====")
118+
return nil
119+
}
120+
121+
func resourceSumologicConnectionDelete(d *schema.ResourceData, meta interface{}) error {
122+
log.Println("====Begin Connection Delete====")
123+
connectionType := d.Get("type").(string)
124+
log.Printf("Deleting Connection Id: %s of type: %s", d.Id(), connectionType)
125+
c := meta.(*Client)
126+
err := c.DeleteConnection(d.Id(), connectionType)
127+
log.Println("====End Connection Delete====")
128+
return err
129+
}
130+
131+
func resourceSumologicConnectionCreate(d *schema.ResourceData, meta interface{}) error {
132+
log.Println("====Begin Connection Create====")
133+
c := meta.(*Client)
134+
135+
if d.Id() == "" {
136+
connection := resourceToConnection(d)
137+
printConnection(connection)
138+
139+
id, err := c.CreateConnection(connection)
140+
141+
if err != nil {
142+
return err
143+
}
144+
145+
log.Println("Saving Id to state...")
146+
d.SetId(id)
147+
log.Printf("ConnectionId: %s", id)
148+
}
149+
150+
log.Println("====End Connection Create====")
151+
return resourceSumologicConnectionRead(d, meta)
152+
}
153+
154+
func resourceSumologicConnectionUpdate(d *schema.ResourceData, meta interface{}) error {
155+
log.Println("====Begin Connection Update====")
156+
157+
c := meta.(*Client)
158+
159+
connection := resourceToConnection(d)
160+
printConnection(connection)
161+
162+
err := c.UpdateConnection(connection)
163+
log.Println("====End Connection Update====")
164+
return err
165+
}
166+
167+
func resourceToConnection(d *schema.ResourceData) Connection {
168+
log.Println("Loading data from schema to Connection struct...")
169+
170+
var connection Connection
171+
connection.ID = d.Id()
172+
connection.Type = d.Get("type").(string)
173+
connection.Name = d.Get("name").(string)
174+
connection.Description = d.Get("description").(string)
175+
connection.URL = d.Get("url").(string)
176+
connection.Headers = mapToHeaders(d.Get("headers").(map[string]interface{}))
177+
connection.CustomHeaders = mapToHeaders(d.Get("custom_headers").(map[string]interface{}))
178+
connection.DefaultPayload = d.Get("default_payload").(string)
179+
connection.WebhookType = d.Get("webhook_type").(string)
180+
181+
return connection
182+
}
183+
184+
func mapToHeaders(in map[string]interface{}) []Headers {
185+
headers := []Headers{}
186+
for k, v := range in {
187+
headers = append(headers, Headers{Name: k, Value: v.(string)})
188+
}
189+
190+
return headers
191+
}
192+
193+
func headersToMap(in []Headers) map[string]interface{} {
194+
headerMap := map[string]interface{}{}
195+
for _, header := range in {
196+
headerMap[header.Name] = header.Value
197+
}
198+
199+
return headerMap
200+
}
201+
202+
func printConnection(connection Connection) {
203+
log.Println("Connection values:")
204+
log.Printf("Type: %s", connection.Type)
205+
log.Printf("Name: %s", connection.Name)
206+
log.Printf("Description: %s", connection.Description)
207+
log.Printf("URL: %s", connection.URL)
208+
log.Printf("Headers: %s", connection.Headers)
209+
log.Printf("CustomHeaders: %s", connection.CustomHeaders)
210+
log.Printf("DefaultPayload: %s", connection.DefaultPayload)
211+
log.Printf("WebhookType: %s", connection.WebhookType)
212+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
9+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
10+
)
11+
12+
//Testing create functionality for Connection resources
13+
func TestAccConnection_create(t *testing.T) {
14+
connectionType := "WebhookConnection"
15+
name := acctest.RandomWithPrefix("tf-connection-test-name")
16+
description := acctest.RandomWithPrefix("tf-connection-test-description")
17+
url := acctest.RandomWithPrefix("https://")
18+
defaultPayload := `{"eventType" : "{{SearchName}}"}`
19+
webhookType := "Webhook"
20+
21+
var connection Connection
22+
23+
resource.Test(t, resource.TestCase{
24+
PreCheck: func() { testAccPreCheck(t) },
25+
Providers: testAccProviders,
26+
CheckDestroy: testAccCheckConnectionDestroy(connection),
27+
Steps: []resource.TestStep{
28+
{
29+
Config: createConnectionConfig(name, connectionType, description, url, webhookType, defaultPayload),
30+
Check: resource.ComposeTestCheckFunc(
31+
testAccCheckConnectionExists("sumologic_connection.test", &connection, t),
32+
testAccCheckConnectionAttributes("sumologic_connection.test"),
33+
resource.TestCheckResourceAttr("sumologic_connection.test", "connectionType", connectionType),
34+
resource.TestCheckResourceAttr("sumologic_connection.test", "name", name),
35+
resource.TestCheckResourceAttr("sumologic_connection.test", "description", description),
36+
resource.TestCheckResourceAttr("sumologic_connection.test", "url", url),
37+
resource.TestCheckResourceAttr("sumologic_connection.test", "defaultPayload", defaultPayload),
38+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhookType", webhookType),
39+
),
40+
},
41+
},
42+
})
43+
}
44+
45+
func TestAccConnection_update(t *testing.T) {
46+
var connection Connection
47+
connectionType := "WebhookConnection"
48+
name := acctest.RandomWithPrefix("tf-connection-test-name")
49+
url := acctest.RandomWithPrefix("https://")
50+
defaultPayload := `{"eventType" : "{{SearchName}}"}`
51+
webhookType := "Webhook"
52+
fDescription := acctest.RandomWithPrefix("tf-connection-test-description")
53+
sDescription := acctest.RandomWithPrefix("tf-connection-test-description")
54+
55+
resource.Test(t, resource.TestCase{
56+
PreCheck: func() { testAccPreCheck(t) },
57+
Providers: testAccProviders,
58+
CheckDestroy: testAccCheckConnectionDestroy(connection),
59+
Steps: []resource.TestStep{
60+
{
61+
Config: createConnectionConfig(name, connectionType, fDescription, url, webhookType, defaultPayload),
62+
Check: resource.ComposeTestCheckFunc(
63+
testAccCheckConnectionExists("sumologic_connection.test", &connection, t),
64+
testAccCheckConnectionAttributes("sumologic_connection.test"),
65+
resource.TestCheckResourceAttr("sumologic_connection.test", "connectionType", connectionType),
66+
resource.TestCheckResourceAttr("sumologic_connection.test", "name", name),
67+
resource.TestCheckResourceAttr("sumologic_connection.test", "description", fDescription),
68+
resource.TestCheckResourceAttr("sumologic_connection.test", "url", url),
69+
resource.TestCheckResourceAttr("sumologic_connection.test", "defaultPayload", defaultPayload),
70+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhookType", webhookType),
71+
),
72+
}, {
73+
Config: createConnectionConfig(name, connectionType, sDescription, url, webhookType, defaultPayload),
74+
Check: resource.ComposeTestCheckFunc(
75+
testAccCheckConnectionExists("sumologic_connection.test", &connection, t),
76+
testAccCheckConnectionAttributes("sumologic_connection.test"),
77+
resource.TestCheckResourceAttr("sumologic_connection.test", "connectionType", connectionType),
78+
resource.TestCheckResourceAttr("sumologic_connection.test", "name", name),
79+
resource.TestCheckResourceAttr("sumologic_connection.test", "description", sDescription),
80+
resource.TestCheckResourceAttr("sumologic_connection.test", "url", url),
81+
resource.TestCheckResourceAttr("sumologic_connection.test", "defaultPayload", defaultPayload),
82+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhookType", webhookType),
83+
),
84+
},
85+
},
86+
})
87+
}
88+
89+
func testAccCheckConnectionExists(name string, connection *Connection, t *testing.T) resource.TestCheckFunc {
90+
return func(s *terraform.State) error {
91+
rs, ok := s.RootModule().Resources[name]
92+
if !ok {
93+
return fmt.Errorf("Connection not found: %s", name)
94+
}
95+
96+
if rs.Primary.ID == "" {
97+
return fmt.Errorf("Connection ID is not set")
98+
}
99+
100+
id := rs.Primary.ID
101+
c := testAccProvider.Meta().(*Client)
102+
newConnection, err := c.GetConnection(id)
103+
if err != nil {
104+
return fmt.Errorf("Connection %s not found", id)
105+
}
106+
connection = newConnection
107+
return nil
108+
}
109+
}
110+
111+
func testAccCheckConnectionAttributes(name string) resource.TestCheckFunc {
112+
return func(s *terraform.State) error {
113+
f := resource.ComposeTestCheckFunc(
114+
resource.TestCheckResourceAttrSet(name, "id"),
115+
)
116+
return f(s)
117+
}
118+
}
119+
120+
func testAccCheckConnectionDestroy(connection Connection) resource.TestCheckFunc {
121+
return func(s *terraform.State) error {
122+
client := testAccProvider.Meta().(*Client)
123+
_, err := client.GetConnection(connection.ID)
124+
if err == nil {
125+
return fmt.Errorf("Connection still exists")
126+
}
127+
return nil
128+
}
129+
}
130+
131+
func createConnectionConfig(name, connectionType, desc, url, webhookType, defaultPayload string) string {
132+
return fmt.Sprintf(`
133+
resource "sumologic_connection" "test" {
134+
name = "%s"
135+
type = "%s"
136+
description = "%s"
137+
url = "%s"
138+
webhook_type = "%s"
139+
default_payload = <<JSON
140+
%s
141+
JSON
142+
}
143+
`, name, connectionType, desc, url, webhookType, defaultPayload)
144+
}

sumologic/sumologic_client.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,3 +334,22 @@ type Content struct {
334334
Config string `json:"-"`
335335
ParentId string `json:"-"`
336336
}
337+
338+
// Connection is used to describe a connection.
339+
type Connection struct {
340+
ID string `json:"id,omitempty"`
341+
Type string `json:"type"`
342+
Name string `json:"name"`
343+
Description string `json:"description,omitempty"`
344+
URL string `json:"url"`
345+
Headers []Headers `json:"headers,omitempty"`
346+
CustomHeaders []Headers `json:"customHeaders,omitempty"`
347+
DefaultPayload string `json:"defaultPayload"`
348+
WebhookType string `json:"webhookType"`
349+
}
350+
351+
// Headers is used to describe headers for http requests.
352+
type Headers struct {
353+
Name string `json:"name"`
354+
Value string `json:"value"`
355+
}

0 commit comments

Comments
 (0)