Skip to content

Commit 33d58ab

Browse files
author
Sean Sain
committed
Merge branch 'feature/sumologic_connection' of git://github.com/anandkumarpatel/sumologic-terraform-provider into anandkumarpatel-feature/sumologic_connection
2 parents ece3cc3 + c0c1629 commit 33d58ab

File tree

9 files changed

+647
-0
lines changed

9 files changed

+647
-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: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
package sumologic
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"log"
7+
"regexp"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
11+
)
12+
13+
func resourceSumologicConnection() *schema.Resource {
14+
nameValidation := `^([a-zA-Z0-9 +%\-@.,_()]+)$`
15+
return &schema.Resource{
16+
Create: resourceSumologicConnectionCreate,
17+
Read: resourceSumologicConnectionRead,
18+
Delete: resourceSumologicConnectionDelete,
19+
Update: resourceSumologicConnectionUpdate,
20+
Importer: &schema.ResourceImporter{
21+
State: schema.ImportStatePassthrough,
22+
},
23+
24+
Schema: map[string]*schema.Schema{
25+
"type": {
26+
Type: schema.TypeString,
27+
Required: true,
28+
ForceNew: true,
29+
// Only WebhookConnection is supported right now
30+
ValidateFunc: validation.StringInSlice([]string{"WebhookConnection"}, false),
31+
},
32+
"name": {
33+
Type: schema.TypeString,
34+
Required: true,
35+
ForceNew: false,
36+
ValidateFunc: validation.All(
37+
validation.StringLenBetween(1, 128),
38+
validation.StringMatch(regexp.MustCompile(nameValidation), fmt.Sprintf("Must match regex %s", nameValidation)),
39+
),
40+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
41+
newJSON, _ := normalizeJsonString(new)
42+
oldJSON, _ := normalizeJsonString(old)
43+
return newJSON == oldJSON
44+
},
45+
},
46+
"description": {
47+
Type: schema.TypeString,
48+
Optional: true,
49+
ForceNew: false,
50+
ValidateFunc: validation.StringLenBetween(0, 1024),
51+
Default: "",
52+
},
53+
"url": {
54+
Type: schema.TypeString,
55+
Optional: true,
56+
ForceNew: false,
57+
ValidateFunc: validation.IsURLWithHTTPorHTTPS,
58+
},
59+
"headers": {
60+
Type: schema.TypeMap,
61+
Elem: &schema.Schema{
62+
Type: schema.TypeString,
63+
},
64+
Optional: true,
65+
ForceNew: false,
66+
Default: map[string]interface{}{},
67+
},
68+
"custom_headers": {
69+
Type: schema.TypeMap,
70+
Elem: &schema.Schema{
71+
Type: schema.TypeString,
72+
},
73+
Optional: true,
74+
ForceNew: false,
75+
Default: map[string]interface{}{},
76+
},
77+
"default_payload": {
78+
Type: schema.TypeString,
79+
Required: true,
80+
ForceNew: false,
81+
ValidateFunc: validation.StringIsJSON,
82+
},
83+
"webhook_type": {
84+
Type: schema.TypeString,
85+
Optional: true,
86+
ForceNew: false,
87+
ValidateFunc: validation.StringInSlice([]string{"AWSLambda", "Azure", "Datadog", "HipChat", "PagerDuty", "Slack", "Webhook", "NewRelic"}, false),
88+
Default: "Webhook",
89+
},
90+
},
91+
}
92+
}
93+
94+
// Takes a value containing JSON string and passes it through
95+
// the JSON parser to normalize it, returns either a parsing
96+
// error or normalized JSON string.
97+
func normalizeJsonString(jsonString interface{}) (string, error) {
98+
var j interface{}
99+
100+
if jsonString == nil || jsonString.(string) == "" {
101+
return "", nil
102+
}
103+
104+
s := jsonString.(string)
105+
106+
err := json.Unmarshal([]byte(s), &j)
107+
if err != nil {
108+
return s, err
109+
}
110+
111+
bytes, _ := json.Marshal(j)
112+
return string(bytes[:]), nil
113+
}
114+
115+
func resourceSumologicConnectionRead(d *schema.ResourceData, meta interface{}) error {
116+
log.Println("====Begin Connection Read====")
117+
118+
c := meta.(*Client)
119+
id := d.Id()
120+
log.Printf("Connection Id from schema: %s", id)
121+
122+
connection, err := c.GetConnection(id)
123+
if err != nil {
124+
return err
125+
}
126+
127+
if connection == nil {
128+
log.Printf("Connection not found, removing from state: %v - %v", id, err)
129+
d.SetId("")
130+
return nil
131+
}
132+
133+
// Write the newly read connection into the schema
134+
d.Set("type", connection.Type)
135+
d.Set("name", connection.Name)
136+
d.Set("description", connection.Description)
137+
d.Set("url", connection.URL)
138+
d.Set("headers", headersToMap(connection.Headers))
139+
d.Set("custom_headers", headersToMap(connection.CustomHeaders))
140+
d.Set("default_payload", connection.DefaultPayload)
141+
d.Set("webhook_type", connection.WebhookType)
142+
d.SetId(connection.ID)
143+
144+
log.Println("====End Connection Read====")
145+
return nil
146+
}
147+
148+
func resourceSumologicConnectionDelete(d *schema.ResourceData, meta interface{}) error {
149+
log.Println("====Begin Connection Delete====")
150+
connectionType := d.Get("type").(string)
151+
log.Printf("Deleting Connection Id: %s of type: %s", d.Id(), connectionType)
152+
c := meta.(*Client)
153+
err := c.DeleteConnection(d.Id(), connectionType)
154+
log.Println("====End Connection Delete====")
155+
return err
156+
}
157+
158+
func resourceSumologicConnectionCreate(d *schema.ResourceData, meta interface{}) error {
159+
log.Println("====Begin Connection Create====")
160+
c := meta.(*Client)
161+
162+
if d.Id() == "" {
163+
connection := resourceToConnection(d)
164+
printConnection(connection)
165+
166+
id, err := c.CreateConnection(connection)
167+
168+
if err != nil {
169+
return err
170+
}
171+
172+
log.Println("Saving Id to state...")
173+
d.SetId(id)
174+
log.Printf("ConnectionId: %s", id)
175+
}
176+
177+
log.Println("====End Connection Create====")
178+
return resourceSumologicConnectionRead(d, meta)
179+
}
180+
181+
func resourceSumologicConnectionUpdate(d *schema.ResourceData, meta interface{}) error {
182+
log.Println("====Begin Connection Update====")
183+
184+
c := meta.(*Client)
185+
186+
connection := resourceToConnection(d)
187+
printConnection(connection)
188+
189+
err := c.UpdateConnection(connection)
190+
log.Println("====End Connection Update====")
191+
return err
192+
}
193+
194+
func resourceToConnection(d *schema.ResourceData) Connection {
195+
log.Println("Loading data from schema to Connection struct...")
196+
197+
var connection Connection
198+
connection.ID = d.Id()
199+
connection.Type = d.Get("type").(string)
200+
connection.Name = d.Get("name").(string)
201+
connection.Description = d.Get("description").(string)
202+
connection.URL = d.Get("url").(string)
203+
connection.Headers = mapToHeaders(d.Get("headers").(map[string]interface{}))
204+
connection.CustomHeaders = mapToHeaders(d.Get("custom_headers").(map[string]interface{}))
205+
connection.DefaultPayload = d.Get("default_payload").(string)
206+
connection.WebhookType = d.Get("webhook_type").(string)
207+
208+
return connection
209+
}
210+
211+
func mapToHeaders(in map[string]interface{}) []Headers {
212+
headers := []Headers{}
213+
for k, v := range in {
214+
headers = append(headers, Headers{Name: k, Value: v.(string)})
215+
}
216+
217+
return headers
218+
}
219+
220+
func headersToMap(in []Headers) map[string]interface{} {
221+
headerMap := map[string]interface{}{}
222+
for _, header := range in {
223+
headerMap[header.Name] = header.Value
224+
}
225+
226+
return headerMap
227+
}
228+
229+
func printConnection(connection Connection) {
230+
log.Println("Connection values:")
231+
log.Printf("Type: %s", connection.Type)
232+
log.Printf("Name: %s", connection.Name)
233+
log.Printf("Description: %s", connection.Description)
234+
log.Printf("URL: %s", connection.URL)
235+
log.Printf("Headers: %s", connection.Headers)
236+
log.Printf("CustomHeaders: %s", connection.CustomHeaders)
237+
log.Printf("DefaultPayload: %s", connection.DefaultPayload)
238+
log.Printf("WebhookType: %s", connection.WebhookType)
239+
}
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", "type", 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", "default_payload", defaultPayload),
38+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhook_type", 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 := "https://example.com"
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", "type", 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", "default_payload", defaultPayload),
70+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhook_type", 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", "type", 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", "default_payload", defaultPayload),
82+
resource.TestCheckResourceAttr("sumologic_connection.test", "webhook_type", 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+
conn, err := client.GetConnection(connection.ID)
124+
if err == nil && conn == nil {
125+
return nil
126+
}
127+
return fmt.Errorf("Connection still exists")
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+
}

0 commit comments

Comments
 (0)