Skip to content

Commit 385115d

Browse files
authored
Add individual AWS sources for all content_types supported by polling source (#64)
* Add docs for various AWS sources * Split polling_source into multiple sources and add to provider * add deprecation message to sumologic_polling_source resource and its docs * duplicate sumologic_polling_source to sumologic_generic_polling_source as per the deprecation process to be used for the new resources. * add to changelog * Update cloudwatch_source.html.markdown
1 parent 45206bb commit 385115d

11 files changed

+897
-0
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11
## 2.2.0 (Unreleased)
2+
DEPRECATIONS:
3+
4+
* resource/sumologic_polling_source: Deprecated in faovur of having individul sources for each content type currently supported. (GH-64)
5+
6+
FEATURES:
7+
8+
* **New Resource:** sumologic_s3_source (GH-64)
9+
* **New Resource:** sumologic_s3_audit_source (GH-64)
10+
* **New Resource:** sumologic_cloudwatch_source (GH-64)
11+
* **New Resource:** sumologic_cloudtrail_source (GH-64)
12+
* **New Resource:** sumologic_elb_source (GH-64)
13+
* **New Resource:** sumologic_cloudfront_source (GH-64)
14+
* **New Resource:** sumologic_metadata_source (GH-61)
215

316
## 2.1.3 (July 30, 2020)
417
ENHANCEMENTS:

sumologic/provider.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ func Provider() terraform.ResourceProvider {
4141
"sumologic_collector": resourceSumologicCollector(),
4242
"sumologic_http_source": resourceSumologicHTTPSource(),
4343
"sumologic_polling_source": resourceSumologicPollingSource(),
44+
"sumologic_s3_source": resourceSumologicGenericPollingSource(),
45+
"sumologic_s3_audit_source": resourceSumologicGenericPollingSource(),
46+
"sumologic_cloudwatch_source": resourceSumologicGenericPollingSource(),
47+
"sumologic_cloudtrail_source": resourceSumologicGenericPollingSource(),
48+
"sumologic_elb_source": resourceSumologicGenericPollingSource(),
49+
"sumologic_cloudfront_source": resourceSumologicGenericPollingSource(),
4450
"sumologic_metadata_source": resourceSumologicMetadataSource(),
4551
"sumologic_cloudsyslog_source": resourceSumologicCloudsyslogSource(),
4652
"sumologic_role": resourceSumologicRole(),
Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"strconv"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
10+
)
11+
12+
func resourceSumologicGenericPollingSource() *schema.Resource {
13+
pollingSource := resourceSumologicSource()
14+
pollingSource.Create = resourceSumologicGenericPollingSourceCreate
15+
pollingSource.Read = resourceSumologicGenericPollingSourceRead
16+
pollingSource.Update = resourceSumologicGenericPollingSourceUpdate
17+
pollingSource.Importer = &schema.ResourceImporter{
18+
State: resourceSumologicSourceImport,
19+
}
20+
21+
pollingSource.Schema["content_type"] = &schema.Schema{
22+
Type: schema.TypeString,
23+
Required: true,
24+
ForceNew: true,
25+
ValidateFunc: validation.StringInSlice([]string{"AwsS3Bucket", "AwsElbBucket", "AwsCloudFrontBucket", "AwsCloudTrailBucket", "AwsS3AuditBucket", "AwsCloudWatch"}, false),
26+
}
27+
pollingSource.Schema["scan_interval"] = &schema.Schema{
28+
Type: schema.TypeInt,
29+
Required: true,
30+
}
31+
pollingSource.Schema["paused"] = &schema.Schema{
32+
Type: schema.TypeBool,
33+
Required: true,
34+
}
35+
pollingSource.Schema["url"] = &schema.Schema{
36+
Type: schema.TypeString,
37+
Computed: true,
38+
}
39+
pollingSource.Schema["authentication"] = &schema.Schema{
40+
Type: schema.TypeList,
41+
Required: true,
42+
ForceNew: true,
43+
MinItems: 1,
44+
MaxItems: 1,
45+
Elem: &schema.Resource{
46+
Schema: map[string]*schema.Schema{
47+
"type": {
48+
Type: schema.TypeString,
49+
Required: true,
50+
ValidateFunc: validation.StringInSlice([]string{"S3BucketAuthentication", "AWSRoleBasedAuthentication"}, false),
51+
},
52+
"access_key": {
53+
Type: schema.TypeString,
54+
Optional: true,
55+
},
56+
"secret_key": {
57+
Type: schema.TypeString,
58+
Optional: true,
59+
},
60+
"role_arn": {
61+
Type: schema.TypeString,
62+
Optional: true,
63+
},
64+
},
65+
},
66+
}
67+
pollingSource.Schema["path"] = &schema.Schema{
68+
Type: schema.TypeList,
69+
Required: true,
70+
ForceNew: true,
71+
MinItems: 1,
72+
MaxItems: 1,
73+
Elem: &schema.Resource{
74+
Schema: map[string]*schema.Schema{
75+
"type": {
76+
Type: schema.TypeString,
77+
Required: true,
78+
ValidateFunc: validation.StringInSlice([]string{"S3BucketPathExpression", "CloudWatchPath"}, false),
79+
},
80+
"bucket_name": {
81+
Type: schema.TypeString,
82+
Optional: true,
83+
},
84+
"path_expression": {
85+
Type: schema.TypeString,
86+
Optional: true,
87+
},
88+
"limit_to_regions": {
89+
Type: schema.TypeList,
90+
Optional: true,
91+
Elem: &schema.Schema{
92+
Type: schema.TypeString,
93+
},
94+
},
95+
"limit_to_namespaces": {
96+
Type: schema.TypeList,
97+
Optional: true,
98+
Elem: &schema.Schema{
99+
Type: schema.TypeString,
100+
},
101+
},
102+
103+
"tag_filters": {
104+
Type: schema.TypeList,
105+
Optional: true,
106+
Elem: &schema.Resource{
107+
Schema: map[string]*schema.Schema{
108+
"type": {
109+
Type: schema.TypeString,
110+
Optional: true,
111+
},
112+
"namespace": {
113+
Type: schema.TypeString,
114+
Optional: true,
115+
},
116+
"tags": {
117+
Type: schema.TypeList,
118+
Optional: true,
119+
Elem: &schema.Schema{
120+
Type: schema.TypeString,
121+
},
122+
},
123+
},
124+
},
125+
},
126+
},
127+
},
128+
}
129+
130+
return pollingSource
131+
}
132+
133+
func resourceSumologicGenericPollingSourceCreate(d *schema.ResourceData, meta interface{}) error {
134+
135+
c := meta.(*Client)
136+
137+
if d.Id() == "" {
138+
source := resourceToGenericPollingSource(d)
139+
sourceID, err := c.CreatePollingSource(source, d.Get("collector_id").(int))
140+
141+
if err != nil {
142+
return err
143+
}
144+
145+
id := strconv.Itoa(sourceID)
146+
147+
d.SetId(id)
148+
}
149+
150+
return resourceSumologicGenericPollingSourceRead(d, meta)
151+
}
152+
153+
func resourceSumologicGenericPollingSourceUpdate(d *schema.ResourceData, meta interface{}) error {
154+
c := meta.(*Client)
155+
156+
source := resourceToGenericPollingSource(d)
157+
158+
err := c.UpdatePollingSource(source, d.Get("collector_id").(int))
159+
160+
if err != nil {
161+
return err
162+
}
163+
164+
return resourceSumologicGenericPollingSourceRead(d, meta)
165+
}
166+
167+
func resourceSumologicGenericPollingSourceRead(d *schema.ResourceData, meta interface{}) error {
168+
c := meta.(*Client)
169+
170+
id, _ := strconv.Atoi(d.Id())
171+
source, err := c.GetPollingSource(d.Get("collector_id").(int), id)
172+
173+
if err != nil {
174+
return err
175+
}
176+
177+
if source == nil {
178+
log.Printf("[WARN] Polling source not found, removing from state: %v - %v", id, err)
179+
d.SetId("")
180+
181+
return nil
182+
}
183+
184+
pollingResources := source.ThirdPartyRef.Resources
185+
path := getPollingThirdPartyPathAttributes(pollingResources)
186+
187+
if err := d.Set("path", path); err != nil {
188+
return err
189+
}
190+
191+
if err := resourceSumologicSourceRead(d, source.Source); err != nil {
192+
return fmt.Errorf("%s", err)
193+
}
194+
d.Set("content_type", source.ContentType)
195+
d.Set("scan_interval", source.ScanInterval)
196+
d.Set("paused", source.Paused)
197+
d.Set("url", source.URL)
198+
199+
return nil
200+
}
201+
202+
func resourceToGenericPollingSource(d *schema.ResourceData) PollingSource {
203+
source := resourceToSource(d)
204+
source.Type = "Polling"
205+
206+
pollingSource := PollingSource{
207+
Source: source,
208+
Paused: d.Get("paused").(bool),
209+
ScanInterval: d.Get("scan_interval").(int),
210+
ContentType: d.Get("content_type").(string),
211+
URL: d.Get("url").(string),
212+
}
213+
214+
pollingResource := PollingResource{
215+
ServiceType: d.Get("content_type").(string),
216+
Authentication: getPollingAuthentication(d),
217+
Path: getPollingPathSettings(d),
218+
}
219+
220+
pollingSource.ThirdPartyRef.Resources = append(pollingSource.ThirdPartyRef.Resources, pollingResource)
221+
222+
return pollingSource
223+
}
224+
225+
func getPollingThirdPartyPathAttributes(pollingResource []PollingResource) []map[string]interface{} {
226+
227+
var s []map[string]interface{}
228+
229+
for _, t := range pollingResource {
230+
mapping := map[string]interface{}{
231+
"type": t.Path.Type,
232+
"bucket_name": t.Path.BucketName,
233+
"path_expression": t.Path.PathExpression,
234+
"limit_to_regions": t.Path.LimitToRegions,
235+
"limit_to_namespaces": t.Path.LimitToNamespaces,
236+
"tag_filters": flattenPollingTagFilters(t.Path.TagFilters),
237+
}
238+
s = append(s, mapping)
239+
}
240+
return s
241+
}
242+
243+
func flattenPollingTagFilters(v []TagFilter) []map[string]interface{} {
244+
var filters []map[string]interface{}
245+
for _, d := range v {
246+
filter := map[string]interface{}{
247+
"type": d.Type,
248+
"namespace": d.Namespace,
249+
"tags": d.Tags,
250+
}
251+
filters = append(filters, filter)
252+
}
253+
254+
return filters
255+
}
256+
257+
func getPollingTagFilters(d *schema.ResourceData) []TagFilter {
258+
paths := d.Get("path").([]interface{})
259+
path := paths[0].(map[string]interface{})
260+
rawTagFilterConfig := path["tag_filters"].([]interface{})
261+
var filters []TagFilter
262+
263+
for _, rawConfig := range rawTagFilterConfig {
264+
config := rawConfig.(map[string]interface{})
265+
filter := TagFilter{}
266+
filter.Type = config["type"].(string)
267+
filter.Namespace = config["namespace"].(string)
268+
269+
rawTags := config["tags"].([]interface{})
270+
Tags := make([]string, len(rawTags))
271+
for i, v := range rawTags {
272+
Tags[i] = v.(string)
273+
}
274+
filter.Tags = Tags
275+
filters = append(filters, filter)
276+
}
277+
278+
return filters
279+
}
280+
281+
func getPollingAuthentication(d *schema.ResourceData) PollingAuthentication {
282+
auths := d.Get("authentication").([]interface{})
283+
authSettings := PollingAuthentication{}
284+
285+
if len(auths) > 0 {
286+
auth := auths[0].(map[string]interface{})
287+
switch authType := auth["type"].(string); authType {
288+
case "S3BucketAuthentication":
289+
authSettings.Type = "S3BucketAuthentication"
290+
authSettings.AwsID = auth["access_key"].(string)
291+
authSettings.AwsKey = auth["secret_key"].(string)
292+
case "AWSRoleBasedAuthentication":
293+
authSettings.Type = "AWSRoleBasedAuthentication"
294+
authSettings.RoleARN = auth["role_arn"].(string)
295+
default:
296+
log.Printf("[ERROR] Unknown authType: %v", authType)
297+
}
298+
}
299+
300+
return authSettings
301+
}
302+
303+
func getPollingPathSettings(d *schema.ResourceData) PollingPath {
304+
pathSettings := PollingPath{}
305+
paths := d.Get("path").([]interface{})
306+
307+
if len(paths) > 0 {
308+
path := paths[0].(map[string]interface{})
309+
switch pathType := path["type"].(string); pathType {
310+
case "S3BucketPathExpression":
311+
pathSettings.Type = "S3BucketPathExpression"
312+
pathSettings.BucketName = path["bucket_name"].(string)
313+
pathSettings.PathExpression = path["path_expression"].(string)
314+
case "CloudWatchPath":
315+
pathSettings.Type = "CloudWatchPath"
316+
rawLimitToRegions := path["limit_to_regions"].([]interface{})
317+
LimitToRegions := make([]string, len(rawLimitToRegions))
318+
for i, v := range rawLimitToRegions {
319+
LimitToRegions[i] = v.(string)
320+
}
321+
322+
rawLimitToNamespaces := path["limit_to_namespaces"].([]interface{})
323+
LimitToNamespaces := make([]string, len(rawLimitToNamespaces))
324+
for i, v := range rawLimitToNamespaces {
325+
LimitToNamespaces[i] = v.(string)
326+
}
327+
pathSettings.LimitToRegions = LimitToRegions
328+
pathSettings.LimitToNamespaces = LimitToNamespaces
329+
pathSettings.TagFilters = getPollingTagFilters(d)
330+
default:
331+
log.Printf("[ERROR] Unknown resourceType in path: %v", pathType)
332+
}
333+
}
334+
335+
return pathSettings
336+
}

sumologic/resource_sumologic_polling_source.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ func resourceSumologicPollingSource() *schema.Resource {
1717
pollingSource.Importer = &schema.ResourceImporter{
1818
State: resourceSumologicSourceImport,
1919
}
20+
pollingSource.DeprecationMessage =
21+
"We are deprecating the generic sumologic polling source and in turn creating individual sources for each of the content_type currently supported."
2022

2123
pollingSource.Schema["content_type"] = &schema.Schema{
2224
Type: schema.TypeString,

0 commit comments

Comments
 (0)