Skip to content

Commit d26844d

Browse files
authored
Merge pull request #569 from SumoLogic/SUMO-226102-add-create-muting-schedular
SUMO-226102:added TF support for muting schedule
2 parents fac0c8a + 4551017 commit d26844d

6 files changed

+970
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
## 2.25.1 (Unreleased)
2+
FEATURES:
3+
* **New Resource:** sumologic_muting_schedule (GH-569)
24
* resource/sumologic_monitor: Added support for associating tags with a Monitor.
35

46
## 2.25.0 (August 8, 2023)

sumologic/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ func Provider() terraform.ResourceProvider {
9494
"sumologic_connection": resourceSumologicConnection(),
9595
"sumologic_monitor": resourceSumologicMonitorsLibraryMonitor(),
9696
"sumologic_monitor_folder": resourceSumologicMonitorsLibraryFolder(),
97+
"sumologic_muting_schedule": resourceSumologicMutingSchedulesLibraryMutingSchedule(),
9798
"sumologic_slo": resourceSumologicSLO(),
9899
"sumologic_slo_folder": resourceSumologicSLOLibraryFolder(),
99100
"sumologic_ingest_budget_v2": resourceSumologicIngestBudgetV2(),
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
package sumologic
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"regexp"
7+
"time"
8+
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
10+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
11+
)
12+
13+
func resourceSumologicMutingSchedulesLibraryMutingSchedule() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceSumologicMutingSchedulesLibraryMutingScheduleCreate,
16+
Read: resourceSumologicMutingSchedulesLibraryMutingScheduleRead,
17+
Update: resourceSumologicMutingSchedulesLibraryMutingScheduleUpdate,
18+
Delete: resourceSumologicMutingSchedulesLibraryMutingScheduleDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: schema.ImportStatePassthrough,
21+
},
22+
23+
Schema: getMutingScheduleSchema(),
24+
}
25+
}
26+
27+
func getMutingScheduleBaseSchema() map[string]*schema.Schema {
28+
return map[string]*schema.Schema{
29+
30+
"name": {
31+
Type: schema.TypeString,
32+
Required: true,
33+
ValidateFunc: validation.All(
34+
validation.StringDoesNotContainAny("/"),
35+
validation.StringLenBetween(1, 255),
36+
validation.StringMatch(regexp.MustCompile(`(?s)^[^\ ].*[^\ ]$`),
37+
"name must not contain leading or trailing spaces"),
38+
),
39+
},
40+
41+
"description": {
42+
Type: schema.TypeString,
43+
Optional: true,
44+
ValidateFunc: validation.All(
45+
validation.StringLenBetween(0, 4096),
46+
validation.StringMatch(regexp.MustCompile(`(?s)^[^\ ].*[^\ ]$`),
47+
"description must not contain leading or trailing spaces"),
48+
),
49+
},
50+
51+
"parent_id": {
52+
Type: schema.TypeString,
53+
Optional: true,
54+
Computed: true,
55+
},
56+
57+
"monitor": {
58+
Type: schema.TypeList,
59+
Optional: true,
60+
MaxItems: 1,
61+
Elem: &schema.Resource{
62+
Schema: getMonitorScopeSchema(),
63+
},
64+
AtLeastOneOf: monitorAtleastOneKey,
65+
},
66+
67+
"schedule": {
68+
Type: schema.TypeList,
69+
Required: true,
70+
MaxItems: 1,
71+
Elem: &schema.Resource{
72+
Schema: getScheduleDefinitionSchemma(),
73+
},
74+
},
75+
76+
"version": {
77+
Type: schema.TypeInt,
78+
Optional: true,
79+
Computed: true,
80+
},
81+
}
82+
}
83+
84+
func getMonitorScopeSchema() map[string]*schema.Schema {
85+
return map[string]*schema.Schema{
86+
"ids": {
87+
Type: schema.TypeList,
88+
Optional: true,
89+
Elem: &schema.Schema{
90+
Type: schema.TypeString,
91+
ValidateFunc: validation.StringIsNotEmpty,
92+
},
93+
},
94+
"all": {
95+
Type: schema.TypeBool,
96+
Optional: true,
97+
},
98+
}
99+
}
100+
101+
func getScheduleDefinitionSchemma() map[string]*schema.Schema {
102+
return map[string]*schema.Schema{
103+
"timezone": {
104+
Type: schema.TypeString,
105+
Required: true,
106+
ForceNew: false,
107+
},
108+
"start_date": {
109+
Type: schema.TypeString,
110+
ForceNew: false,
111+
Required: true,
112+
ValidateFunc: validation.All(
113+
validation.StringMatch(regexp.MustCompile(`^\d{4}-\d{2}-\d{2}$`),
114+
"start date in format of yyyy-mm-dd"),
115+
StartDateIsAfterYesterday(),
116+
),
117+
},
118+
"start_time": {
119+
Type: schema.TypeString,
120+
Required: true,
121+
ForceNew: false,
122+
ValidateFunc: validation.All(
123+
validation.StringMatch(regexp.MustCompile(`^(?:[01]\d|2[0-3]):[0-5]\d$`),
124+
"start time in format of 00:00"),
125+
),
126+
},
127+
"duration": {
128+
Type: schema.TypeInt,
129+
Required: true,
130+
ForceNew: false,
131+
ValidateFunc: validation.IntAtLeast(15),
132+
},
133+
"rrule": {
134+
Type: schema.TypeString,
135+
Optional: true,
136+
},
137+
}
138+
}
139+
140+
func getMutingScheduleSchema() map[string]*schema.Schema {
141+
tfSchema := getMutingScheduleBaseSchema()
142+
143+
additionalAttributes := map[string]*schema.Schema{
144+
145+
"type": {
146+
Type: schema.TypeString,
147+
Optional: true,
148+
Default: "MutingSchedulesLibraryMutingSchedule",
149+
ValidateFunc: validation.StringInSlice([]string{"MutingSchedulesLibraryMutingSchedule", "MutingSchedulesLibraryFolder"}, false),
150+
},
151+
152+
"content_type": {
153+
Type: schema.TypeString,
154+
Optional: true,
155+
Default: "MutingSchedule",
156+
},
157+
158+
"is_system": {
159+
Type: schema.TypeBool,
160+
Optional: true,
161+
Computed: true,
162+
},
163+
164+
"is_mutable": {
165+
Type: schema.TypeBool,
166+
Optional: true,
167+
Computed: true,
168+
},
169+
170+
"created_by": {
171+
Type: schema.TypeString,
172+
Optional: true,
173+
Computed: true,
174+
},
175+
176+
"created_at": {
177+
Type: schema.TypeString,
178+
Optional: true,
179+
Computed: true,
180+
},
181+
182+
"modified_by": {
183+
Type: schema.TypeString,
184+
Optional: true,
185+
Computed: true,
186+
},
187+
188+
"modified_at": {
189+
Type: schema.TypeString,
190+
Optional: true,
191+
Computed: true,
192+
},
193+
}
194+
195+
for k, v := range additionalAttributes {
196+
tfSchema[k] = v
197+
}
198+
199+
return tfSchema
200+
}
201+
202+
func resourceSumologicMutingSchedulesLibraryMutingScheduleCreate(d *schema.ResourceData, meta interface{}) error {
203+
c := meta.(*Client)
204+
205+
if d.Id() == "" {
206+
mutingSchedule := resourceToMutingSchedulesLibraryMutingSchedule(d)
207+
if mutingSchedule.ParentID == "" {
208+
rootFolder, err := c.GetMutingSchedulesLibraryFolder("root")
209+
if err != nil {
210+
return err
211+
}
212+
213+
mutingSchedule.ParentID = rootFolder.ID
214+
}
215+
paramMap := map[string]string{
216+
"parentId": mutingSchedule.ParentID,
217+
}
218+
mutingScheduleDefinitionID, err := c.CreateMutingSchedulesLibraryMutingSchedule(mutingSchedule, paramMap)
219+
if err != nil {
220+
return err
221+
}
222+
d.SetId(mutingScheduleDefinitionID)
223+
}
224+
return resourceSumologicMutingSchedulesLibraryMutingScheduleRead(d, meta)
225+
}
226+
227+
func resourceSumologicMutingSchedulesLibraryMutingScheduleRead(d *schema.ResourceData, meta interface{}) error {
228+
c := meta.(*Client)
229+
230+
mutingSchedule, err := c.MutingSchedulesRead(d.Id())
231+
if err != nil {
232+
return err
233+
}
234+
235+
if mutingSchedule == nil {
236+
log.Printf("[WARN] MutingSchedule not found, removing from state: %v - %v", d.Id(), err)
237+
d.SetId("")
238+
return nil
239+
}
240+
241+
monitorScope := make([]interface{}, 1)
242+
monitorScope[0] = map[string]interface{}{
243+
"all": mutingSchedule.Monitor.All,
244+
"ids": mutingSchedule.Monitor.Ids,
245+
}
246+
schedule := make([]interface{}, 1)
247+
schedule[0] = map[string]interface{}{
248+
"timezone": mutingSchedule.Schedule.TimeZone,
249+
"start_date": mutingSchedule.Schedule.StartDate,
250+
"start_time": mutingSchedule.Schedule.StartTime,
251+
"duration": mutingSchedule.Schedule.Duration,
252+
"rrule": mutingSchedule.Schedule.RRule,
253+
}
254+
255+
d.Set("created_by", mutingSchedule.CreatedBy)
256+
d.Set("created_at", mutingSchedule.CreatedAt)
257+
d.Set("modified_by", mutingSchedule.ModifiedBy)
258+
d.Set("is_mutable", mutingSchedule.IsMutable)
259+
d.Set("version", mutingSchedule.Version)
260+
d.Set("description", mutingSchedule.Description)
261+
d.Set("name", mutingSchedule.Name)
262+
d.Set("parent_id", mutingSchedule.ParentID)
263+
d.Set("modified_at", mutingSchedule.ModifiedAt)
264+
d.Set("content_type", mutingSchedule.ContentType)
265+
d.Set("is_system", mutingSchedule.IsSystem)
266+
d.Set("monitor", monitorScope)
267+
d.Set("schedule", schedule)
268+
269+
return nil
270+
}
271+
272+
func resourceSumologicMutingSchedulesLibraryMutingScheduleUpdate(d *schema.ResourceData, meta interface{}) error {
273+
c := meta.(*Client)
274+
mutingSchedule := resourceToMutingSchedulesLibraryMutingSchedule(d)
275+
276+
mutingSchedule.Type = "MutingSchedulesLibraryMutingScheduleUpdate"
277+
err := c.UpdateMutingSchedulesLibraryMutingSchedule(mutingSchedule)
278+
if err != nil {
279+
return err
280+
}
281+
updatedMutingSchedule := resourceSumologicMutingSchedulesLibraryMutingScheduleRead(d, meta)
282+
return updatedMutingSchedule
283+
}
284+
285+
func resourceSumologicMutingSchedulesLibraryMutingScheduleDelete(d *schema.ResourceData, meta interface{}) error {
286+
c := meta.(*Client)
287+
mutingSchedule := resourceToMutingSchedulesLibraryMutingSchedule(d)
288+
err := c.DeleteMutingSchedulesLibraryMutingSchedule(mutingSchedule.ID)
289+
if err != nil {
290+
return err
291+
}
292+
return nil
293+
}
294+
295+
func getMonitorScope(d *schema.ResourceData) *MonitorScope {
296+
monitorMap := d.Get("monitor").([]interface{})
297+
if len(monitorMap) == 0 {
298+
return nil
299+
} else {
300+
monitorScopeDict := monitorMap[0].(map[string]interface{})
301+
monitorScope := MonitorScope{
302+
Ids: fieldsToStringArray(monitorScopeDict["ids"].([]interface{})),
303+
All: monitorScopeDict["all"].(bool),
304+
}
305+
return &monitorScope
306+
}
307+
}
308+
309+
func getScheduleDefinition(d *schema.ResourceData) ScheduleDefinition {
310+
scheduleDefinitionMap := d.Get("schedule").([]interface{})
311+
scheduleDefinitionDict := scheduleDefinitionMap[0].(map[string]interface{})
312+
scheduleDefinition := ScheduleDefinition{
313+
TimeZone: scheduleDefinitionDict["timezone"].(string),
314+
StartDate: scheduleDefinitionDict["start_date"].(string),
315+
StartTime: scheduleDefinitionDict["start_time"].(string),
316+
Duration: scheduleDefinitionDict["duration"].(int),
317+
RRule: scheduleDefinitionDict["rrule"].(string),
318+
}
319+
return scheduleDefinition
320+
}
321+
322+
func StartDateIsAfterYesterday() schema.SchemaValidateFunc {
323+
return func(i interface{}, k string) (warnings []string, errors []error) {
324+
v, ok := i.(string)
325+
if !ok {
326+
return warnings, []error{fmt.Errorf("expected type of %q to be string", k)}
327+
}
328+
329+
date, err := time.Parse("2006-01-02", v)
330+
331+
if err != nil {
332+
return warnings, []error{fmt.Errorf("expected %q to be an valid start date yyyy-mm-dd : got %v", k, v)}
333+
}
334+
335+
yesterday := time.Now().AddDate(0, 0, -1).Truncate(24 * time.Hour)
336+
337+
if date.Before(yesterday) {
338+
return warnings, []error{fmt.Errorf("expected %q to be an valid start date : got %v", k, v)}
339+
}
340+
return warnings, errors
341+
}
342+
}
343+
344+
var monitorAtleastOneKey = []string{
345+
"monitor.0.ids",
346+
"monitor.0.all",
347+
}
348+
349+
func resourceToMutingSchedulesLibraryMutingSchedule(d *schema.ResourceData) MutingSchedulesLibraryMutingSchedule {
350+
monitorScope := getMonitorScope(d)
351+
scheduleDefinition := getScheduleDefinition(d)
352+
353+
return MutingSchedulesLibraryMutingSchedule{
354+
CreatedBy: d.Get("created_by").(string),
355+
Name: d.Get("name").(string),
356+
ID: d.Id(),
357+
CreatedAt: d.Get("created_at").(string),
358+
Description: d.Get("description").(string),
359+
ModifiedBy: d.Get("modified_by").(string),
360+
IsMutable: d.Get("is_mutable").(bool),
361+
Version: d.Get("version").(int),
362+
Type: d.Get("type").(string),
363+
ParentID: d.Get("parent_id").(string),
364+
ModifiedAt: d.Get("modified_at").(string),
365+
ContentType: d.Get("content_type").(string),
366+
IsSystem: d.Get("is_system").(bool),
367+
Schedule: scheduleDefinition,
368+
Monitor: monitorScope,
369+
}
370+
}

0 commit comments

Comments
 (0)