Skip to content

Commit 83928e7

Browse files
authored
Add universal source (#93)
* add sumologic universal source * cleanup * remove dependency on base source for universal source * add acc tests * add sumologic universal source * cleanup * remove dependency on base source for universal source * add acc tests * add doc * fix linter * ignore lint for time.sleep usage * address PR comments * replace universal source with cloud-to-cloud source * rename files and update documentation * rename in documentation * address PR comments
1 parent 806f580 commit 83928e7

File tree

5 files changed

+462
-0
lines changed

5 files changed

+462
-0
lines changed

sumologic/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func Provider() terraform.ResourceProvider {
4949
"sumologic_cloudtrail_source": resourceSumologicGenericPollingSource(),
5050
"sumologic_elb_source": resourceSumologicGenericPollingSource(),
5151
"sumologic_cloudfront_source": resourceSumologicGenericPollingSource(),
52+
"sumologic_cloud_to_cloud_source": resourceSumologicCloudToCloudSource(),
5253
"sumologic_metadata_source": resourceSumologicMetadataSource(),
5354
"sumologic_cloudsyslog_source": resourceSumologicCloudsyslogSource(),
5455
"sumologic_role": resourceSumologicRole(),
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package sumologic
2+
3+
import (
4+
"encoding/json"
5+
"log"
6+
"strconv"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/structure"
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
11+
)
12+
13+
func resourceSumologicCloudToCloudSource() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceSumologicCloudToCloudSourceCreate,
16+
Read: resourceSumologicCloudToCloudSourceRead,
17+
Update: resourceSumologicCloudToCloudSourceUpdate,
18+
Delete: resourceSumologicCloudToCloudSourceDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: resourceSumologicSourceImport,
21+
},
22+
Schema: map[string]*schema.Schema{
23+
"config": {
24+
Type: schema.TypeString,
25+
ValidateFunc: validation.StringIsJSON,
26+
Required: true,
27+
DiffSuppressFunc: structure.SuppressJsonDiff,
28+
},
29+
"schema_ref": {
30+
Type: schema.TypeMap,
31+
Required: true,
32+
Elem: &schema.Schema{
33+
Type: schema.TypeString,
34+
},
35+
},
36+
"collector_id": {
37+
Type: schema.TypeInt,
38+
Required: true,
39+
ForceNew: true,
40+
},
41+
},
42+
}
43+
}
44+
45+
func resourceSumologicCloudToCloudSourceCreate(d *schema.ResourceData, meta interface{}) error {
46+
c := meta.(*Client)
47+
48+
if d.Id() == "" {
49+
source := resourceToCloudToCloudSource(d)
50+
log.Printf("SchemaRef %s", source.SchemaRef)
51+
log.Printf("Config: %s", source.Config)
52+
53+
id, err := c.CreateCloudToCloudSource(*source, d.Get("collector_id").(int))
54+
55+
if err != nil {
56+
return err
57+
}
58+
59+
d.SetId(strconv.Itoa(id))
60+
}
61+
62+
return resourceSumologicCloudToCloudSourceRead(d, meta)
63+
}
64+
65+
func resourceSumologicCloudToCloudSourceUpdate(d *schema.ResourceData, meta interface{}) error {
66+
c := meta.(*Client)
67+
68+
source := resourceToCloudToCloudSource(d)
69+
70+
err := c.UpdateCloudToCloudSource(*source, d.Get("collector_id").(int))
71+
72+
if err != nil {
73+
return err
74+
}
75+
76+
return resourceSumologicCloudToCloudSourceRead(d, meta)
77+
}
78+
79+
func resourceSumologicCloudToCloudSourceDelete(d *schema.ResourceData, meta interface{}) error {
80+
c := meta.(*Client)
81+
82+
id, _ := strconv.Atoi(d.Id())
83+
collectorID, _ := d.Get("collector_id").(int)
84+
85+
return c.DestroySource(id, collectorID)
86+
87+
}
88+
89+
func resourceToCloudToCloudSource(d *schema.ResourceData) *CloudToCloudSource {
90+
id, _ := strconv.Atoi(d.Id())
91+
var cloudToCloudSource CloudToCloudSource
92+
var jsonRawConf json.RawMessage
93+
94+
cloudToCloudSource.Type = "Universal"
95+
96+
conf := []byte(d.Get("config").(string))
97+
98+
err := json.Unmarshal(conf, &jsonRawConf)
99+
if err != nil {
100+
log.Println("Unable to unmarshal the Json configuration")
101+
return nil
102+
}
103+
104+
cloudToCloudSource.ID = id
105+
cloudToCloudSource.Config = jsonRawConf
106+
cloudToCloudSource.SchemaRef = getSourceSchemaRef(d)
107+
108+
return &cloudToCloudSource
109+
}
110+
111+
func resourceSumologicCloudToCloudSourceRead(d *schema.ResourceData, meta interface{}) error {
112+
c := meta.(*Client)
113+
114+
id, _ := strconv.Atoi(d.Id())
115+
source, err := c.GetCloudToCloudSource(d.Get("collector_id").(int), id)
116+
117+
if err != nil {
118+
return err
119+
}
120+
121+
if source == nil {
122+
log.Printf("[WARN] Cloud-to-Cloud source not found, removing from state: %v - %v", id, err)
123+
d.SetId("")
124+
125+
return nil
126+
}
127+
128+
return nil
129+
}
130+
func getSourceSchemaRef(d *schema.ResourceData) SchemaReference {
131+
sourceSchema := d.Get("schema_ref").(map[string]interface{})
132+
schemaR := SchemaReference{}
133+
134+
if len(sourceSchema) > 0 {
135+
schemaR.Type = sourceSchema["type"].(string)
136+
if sourceSchema["version"] != nil {
137+
schemaR.Version = sourceSchema["version"].(string)
138+
}
139+
}
140+
141+
return schemaR
142+
}
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"strconv"
6+
"testing"
7+
"time"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/terraform"
11+
)
12+
13+
func TestAccSumologicCloudToCloudSource_create(t *testing.T) {
14+
var cloudToCloudSource CloudToCloudSource
15+
var collector Collector
16+
cName, cDescription, cCategory := getRandomizedParams()
17+
cloudToCloudResourceName := "sumologic_cloud_to_cloud_source.okta"
18+
resource.Test(t, resource.TestCase{
19+
PreCheck: func() { testAccPreCheck(t) },
20+
Providers: testAccProviders,
21+
CheckDestroy: testAccCheckCloudToCloudSourceDestroy,
22+
Steps: []resource.TestStep{
23+
{
24+
Config: testAccSumologicCloudToCloudSourceConfig(cName, cDescription, cCategory, configJSON),
25+
Check: resource.ComposeTestCheckFunc(
26+
testAccCheckCloudToCloudSourceExists(cloudToCloudResourceName, &cloudToCloudSource),
27+
testAccCheckCollectorExists("sumologic_collector.test", &collector),
28+
testAccCheckCollectorValues(&collector, cName, cDescription, cCategory, "Etc/UTC", ""),
29+
resource.TestCheckResourceAttrSet(cloudToCloudResourceName, "id"),
30+
),
31+
},
32+
},
33+
})
34+
}
35+
36+
func TestAccSumologicCloudToCloudSource_update(t *testing.T) {
37+
var cloudToCloudSource CloudToCloudSource
38+
cName, cDescription, cCategory := getRandomizedParams()
39+
cloudToCloudResourceName := "sumologic_cloud_to_cloud_source.okta"
40+
resource.Test(t, resource.TestCase{
41+
PreCheck: func() { testAccPreCheck(t) },
42+
Providers: testAccProviders,
43+
CheckDestroy: testAccCheckHTTPSourceDestroy,
44+
Steps: []resource.TestStep{
45+
{
46+
Config: testAccSumologicCloudToCloudSourceConfig(cName, cDescription, cCategory, configJSON),
47+
Check: resource.ComposeTestCheckFunc(
48+
testAccCheckCloudToCloudSourceExists(cloudToCloudResourceName, &cloudToCloudSource),
49+
resource.TestCheckResourceAttrSet(cloudToCloudResourceName, "id"),
50+
testAccWaitCloudToCloudSource(),
51+
),
52+
},
53+
{
54+
Config: testAccSumologicCloudToCloudSourceConfig(cName, cDescription, cCategory, updatedConfigJSON),
55+
Check: resource.ComposeTestCheckFunc(
56+
testAccCheckCloudToCloudSourceExists(cloudToCloudResourceName, &cloudToCloudSource),
57+
resource.TestCheckResourceAttrSet(cloudToCloudResourceName, "id"),
58+
),
59+
},
60+
},
61+
})
62+
}
63+
64+
// wait function for waiting before perfroming an update to cloud-to-cloud source as updates are blocked when the source is in pending state
65+
func testAccWaitCloudToCloudSource() resource.TestCheckFunc {
66+
return func(s *terraform.State) error {
67+
//lintignore:R018
68+
time.Sleep(30 * time.Second)
69+
return nil
70+
}
71+
}
72+
73+
func testAccCheckCloudToCloudSourceDestroy(s *terraform.State) error {
74+
75+
client := testAccProvider.Meta().(*Client)
76+
for _, rs := range s.RootModule().Resources {
77+
if rs.Type != "sumologic_cloud_to_cloud_source" {
78+
continue
79+
}
80+
if rs.Primary.ID == "" {
81+
return fmt.Errorf("Cloud-to-Cloud Source destruction check: Cloud-to-Cloud Source ID is not set")
82+
}
83+
id, err := strconv.Atoi(rs.Primary.ID)
84+
if err != nil {
85+
return fmt.Errorf("Encountered an error: " + err.Error())
86+
}
87+
collectorID, err := strconv.Atoi(rs.Primary.Attributes["collector_id"])
88+
if err != nil {
89+
return fmt.Errorf("Encountered an error: " + err.Error())
90+
}
91+
s, err := client.GetCloudToCloudSource(collectorID, id)
92+
if err != nil {
93+
return fmt.Errorf("Encountered an error: " + err.Error())
94+
}
95+
if s != nil {
96+
return fmt.Errorf("Cloud-to-Cloud Source still exists")
97+
}
98+
}
99+
return nil
100+
}
101+
func testAccCheckCloudToCloudSourceExists(n string, cloudToCloudSource *CloudToCloudSource) resource.TestCheckFunc {
102+
return func(s *terraform.State) error {
103+
rs, ok := s.RootModule().Resources[n]
104+
if !ok {
105+
return fmt.Errorf("not found: %s", n)
106+
}
107+
if rs.Primary.ID == "" {
108+
return fmt.Errorf("Cloud-to-Cloud Source ID is not set")
109+
}
110+
id, err := strconv.Atoi(rs.Primary.ID)
111+
if err != nil {
112+
return fmt.Errorf("Cloud-to-Cloud Source id should be int; got %s", rs.Primary.ID)
113+
}
114+
collectorID, err := strconv.Atoi(rs.Primary.Attributes["collector_id"])
115+
if err != nil {
116+
return fmt.Errorf("Encountered an error: " + err.Error())
117+
}
118+
c := testAccProvider.Meta().(*Client)
119+
cloudToCloudSourceResp, err := c.GetCloudToCloudSource(collectorID, id)
120+
if err != nil {
121+
return err
122+
}
123+
*cloudToCloudSource = *cloudToCloudSourceResp
124+
return nil
125+
}
126+
}
127+
128+
func testAccSumologicCloudToCloudSourceConfig(cName, cDescription, cCategory, sConfig string) string {
129+
return fmt.Sprintf(`
130+
resource "sumologic_collector" "test" {
131+
name = "%s"
132+
description = "%s"
133+
category = "%s"
134+
}
135+
136+
resource "sumologic_cloud_to_cloud_source" "okta" {
137+
collector_id = sumologic_collector.test.id
138+
schema_ref = {
139+
type = "Okta"
140+
}
141+
config = <<JSON
142+
%s
143+
JSON
144+
}
145+
`, cName, cDescription, cCategory, sConfig)
146+
}
147+
148+
var configJSON = `{
149+
"name":"Okta_source",
150+
"domain":"demo.okta.com",
151+
"collectAll":true,
152+
"apiKey":"secret",
153+
"fields":{
154+
"_siemForward":false
155+
},
156+
"pollingInterval": 30
157+
}`
158+
159+
var updatedConfigJSON = `{
160+
"name":"Okta_source_new",
161+
"domain":"demo.okta.com",
162+
"collectAll":true,
163+
"apiKey":"secret",
164+
"fields":{
165+
"_siemForward":false
166+
},
167+
"pollingInterval": 300
168+
}`

0 commit comments

Comments
 (0)