Skip to content

Commit b5e9830

Browse files
SUMO-192164: Setting FGP on Objects through terraform (#397)
* SUMO-192164: Setting Permissions on Objects through terraform * SUMO-192164: Adding error code * SUMO-192164: Addressing review comments * SUMO-192164: modifying documentation * SUMO-192164: indentation
1 parent 863c7ff commit b5e9830

File tree

4 files changed

+368
-3
lines changed

4 files changed

+368
-3
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ FEATURES:
33
* **New Resource:** sumologic_cse_entity_entity_group_configuration (GH-376)
44
* **New Resource:** sumologic_cse_inventory_entity_group_configuration (GH-376)
55

6+
* Add new optional `obj_permission` set to resource/sumologic_monitor for Fine Grain Permission (FGP) support (GH-397)
7+
68
## 2.16.2 (June 12, 2022)
79

810
BUG FIXES:

sumologic/resource_sumologic_monitors_library_monitor.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ func resourceSumologicMonitorsLibraryMonitor() *schema.Resource {
353353
Optional: true,
354354
ValidateFunc: validation.StringLenBetween(1, 512),
355355
},
356+
357+
"obj_permission": GetCmfFgpObjPermSetSchema(),
356358
},
357359
}
358360
}
@@ -569,6 +571,16 @@ func resourceSumologicMonitorsLibraryMonitorCreate(d *schema.ResourceData, meta
569571
return err
570572
}
571573

574+
permStmts, convErr := ResourceToCmfFgpPermStmts(d, monitorDefinitionID)
575+
if convErr != nil {
576+
return convErr
577+
}
578+
_, fgpErr := c.SetCmfFgp(fgpTargetType, CmfFgpRequest{
579+
PermissionStatements: permStmts,
580+
})
581+
if fgpErr != nil {
582+
return fgpErr
583+
}
572584
d.SetId(monitorDefinitionID)
573585
}
574586
return resourceSumologicMonitorsLibraryMonitorRead(d, meta)
@@ -588,6 +600,18 @@ func resourceSumologicMonitorsLibraryMonitorRead(d *schema.ResourceData, meta in
588600
return nil
589601
}
590602

603+
fgpResponse, fgpErr := c.GetCmfFgp(fgpTargetType, monitor.ID)
604+
if fgpErr != nil {
605+
suppressedErrorCode := HasErrorCode(fgpErr.Error(), []string{"not_implemented_yet", "api_not_enabled"})
606+
if suppressedErrorCode == "" {
607+
return fgpErr
608+
} else {
609+
log.Printf("[WARN] FGP Feature has not been enabled yet. Suppressing \"%s\" error under GetCmfFgp operation.", suppressedErrorCode)
610+
}
611+
} else {
612+
CmfFgpPermStmtsSetToResource(d, fgpResponse.PermissionStatements)
613+
}
614+
591615
d.Set("created_by", monitor.CreatedBy)
592616
d.Set("created_at", monitor.CreatedAt)
593617
d.Set("monitor_type", monitor.MonitorType)
@@ -715,6 +739,43 @@ func resourceSumologicMonitorsLibraryMonitorUpdate(d *schema.ResourceData, meta
715739
if err != nil {
716740
return err
717741
}
742+
743+
// converting Resource FGP to Struct
744+
permStmts, convErr := ResourceToCmfFgpPermStmts(d, monitor.ID)
745+
if convErr != nil {
746+
return convErr
747+
}
748+
749+
// reading FGP from Backend to reconcile
750+
fgpGetResponse, fgpGetErr := c.GetCmfFgp(fgpTargetType, monitor.ID)
751+
if fgpGetErr != nil {
752+
/*
753+
|errCode | len | logic |
754+
|--------------------------------------------------|
755+
|server_error | 0 | return err at Get |
756+
|server_error | 1 | warn; return err at Set |
757+
|not_enabled | 0 | warn |
758+
|not_enabled | 1 | warn; return err at Set |
759+
*/
760+
suppressedErrorCode := HasErrorCode(fgpGetErr.Error(), []string{"not_implemented_yet", "api_not_enabled"})
761+
if suppressedErrorCode == "" && len(permStmts) == 0 {
762+
return fgpGetErr
763+
} else {
764+
log.Printf("[WARN] FGP Feature has not been enabled yet. Suppressing \"%s\" error under GetCmfFgp operation.", suppressedErrorCode)
765+
}
766+
}
767+
768+
if len(permStmts) > 0 || fgpGetResponse != nil {
769+
_, fgpSetErr := c.SetCmfFgp(fgpTargetType, CmfFgpRequest{
770+
PermissionStatements: ReconcileFgpPermStmtsWithEmptyPerms(
771+
permStmts, fgpGetResponse.PermissionStatements,
772+
),
773+
})
774+
if fgpSetErr != nil {
775+
return fgpSetErr
776+
}
777+
}
778+
718779
updatedMonitor := resourceSumologicMonitorsLibraryMonitorRead(d, meta)
719780

720781
return updatedMonitor

sumologic/resource_sumologic_monitors_library_monitor_test.go

Lines changed: 261 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ func TestAccSumologicMonitorsLibraryMonitor_create(t *testing.T) {
212212
resource.TestCheckResourceAttr("sumologic_monitor.test", "triggers.0.time_range", testTriggers[0].TimeRange),
213213
resource.TestCheckResourceAttr("sumologic_monitor.test", "notifications.0.notification.0.connection_type", testNotifications[0].Notification.(EmailNotification).ConnectionType),
214214
resource.TestCheckResourceAttr("sumologic_monitor.test", "alert_name", testAlertName),
215+
resource.TestCheckResourceAttr("sumologic_monitor.test", "obj_permission.#", "2"),
216+
testAccCheckMonitorsLibraryMonitorFGPBackend("sumologic_monitor.test", t, genExpectedPermStmtsMonitor),
215217
),
216218
},
217219
},
@@ -390,6 +392,8 @@ func TestAccSumologicMonitorsLibraryMonitor_update(t *testing.T) {
390392
resource.TestCheckResourceAttr("sumologic_monitor.test", "notifications.0.notification.0.connection_type", testNotifications[0].Notification.(EmailNotification).ConnectionType),
391393
resource.TestCheckResourceAttr("sumologic_monitor.test", "playbook", testPlaybook),
392394
resource.TestCheckResourceAttr("sumologic_monitor.test", "alert_name", testAlertName),
395+
resource.TestCheckResourceAttr("sumologic_monitor.test", "obj_permission.#", "2"),
396+
testAccCheckMonitorsLibraryMonitorFGPBackend("sumologic_monitor.test", t, genExpectedPermStmtsMonitor),
393397
),
394398
},
395399
{
@@ -408,6 +412,61 @@ func TestAccSumologicMonitorsLibraryMonitor_update(t *testing.T) {
408412
resource.TestCheckResourceAttr("sumologic_monitor.test", "notifications.0.notification.0.connection_type", testUpdatedNotifications[0].Notification.(EmailNotification).ConnectionType),
409413
resource.TestCheckResourceAttr("sumologic_monitor.test", "playbook", testUpdatedPlaybook),
410414
resource.TestCheckResourceAttr("sumologic_monitor.test", "alert_name", testUpdatedAlertName),
415+
resource.TestCheckResourceAttr("sumologic_monitor.test", "obj_permission.#", "1"),
416+
// 1, instead of 2
417+
testAccCheckMonitorsLibraryMonitorFGPBackend("sumologic_monitor.test", t, genExpectedPermStmtsForMonitorUpdate),
418+
),
419+
},
420+
},
421+
})
422+
}
423+
424+
func TestAccSumologicMonitorsLibraryMonitor_driftingCorrectionFGP(t *testing.T) {
425+
var monitorsLibraryMonitor MonitorsLibraryMonitor
426+
testNameSuffix := acctest.RandString(16)
427+
tfResourceKey := "sumologic_monitor.test"
428+
testName := "terraform_test_monitor_" + testNameSuffix
429+
430+
resource.Test(t, resource.TestCase{
431+
PreCheck: func() { testAccPreCheck(t) },
432+
Providers: testAccProviders,
433+
CheckDestroy: testAccCheckMonitorsLibraryMonitorDestroy(monitorsLibraryMonitor),
434+
Steps: []resource.TestStep{
435+
{
436+
Config: testAccSumologicMonitorsLibraryMonitor(testNameSuffix),
437+
Check: resource.ComposeTestCheckFunc(
438+
testAccCheckMonitorsLibraryMonitorExists(tfResourceKey, &monitorsLibraryMonitor, t),
439+
testAccCheckMonitorsLibraryMonitorAttributes(tfResourceKey),
440+
441+
resource.TestCheckResourceAttr("sumologic_monitor.test", "name", testName),
442+
resource.TestCheckResourceAttr("sumologic_monitor.test", "description",
443+
"terraform_test_monitor_description"),
444+
445+
resource.TestCheckResourceAttr("sumologic_monitor.test",
446+
"obj_permission.#", "2"),
447+
testAccCheckMonitorsLibraryMonitorFGPBackend(tfResourceKey, t, genExpectedPermStmtsMonitor),
448+
// Emulating Drifting at the Backend
449+
testAccEmulateFGPDriftingMonitor(t),
450+
),
451+
// "After applying this step and refreshing, the plan was not empty"
452+
// Non-Empty Plan would occur, after the above step that emulates FGP drifting
453+
ExpectNonEmptyPlan: true,
454+
},
455+
// the following Test Step emulates running "terraform apply" again.
456+
// This step would detect and correct Drifting
457+
{
458+
Config: testAccSumologicMonitorsLibraryMonitor(testNameSuffix),
459+
Check: resource.ComposeTestCheckFunc(
460+
testAccCheckMonitorsLibraryMonitorExists(tfResourceKey, &monitorsLibraryMonitor, t),
461+
testAccCheckMonitorsLibraryMonitorAttributes(tfResourceKey),
462+
463+
resource.TestCheckResourceAttr("sumologic_monitor.test", "name", testName),
464+
resource.TestCheckResourceAttr("sumologic_monitor.test", "description",
465+
"terraform_test_monitor_description"),
466+
467+
resource.TestCheckResourceAttr("sumologic_monitor.test",
468+
"obj_permission.#", "2"),
469+
testAccCheckMonitorsLibraryFolderFGPBackend(tfResourceKey, t, genExpectedPermStmtsMonitor),
411470
),
412471
},
413472
},
@@ -523,7 +582,44 @@ resource "sumologic_monitor" "test" {
523582
}
524583
playbook = "This is a test playbook"
525584
alert_name = "Alert from {{Name}}"
526-
}`, testName)
585+
obj_permission {
586+
subject_type = "role"
587+
subject_id = sumologic_role.tf_test_role_01.id
588+
permissions = ["Read","Update","Delete"]
589+
}
590+
obj_permission {
591+
subject_type = "role"
592+
subject_id = sumologic_role.tf_test_role_02.id
593+
permissions = ["Read"]
594+
}
595+
}
596+
resource "sumologic_role" "tf_test_role_01" {
597+
name = "tf_test_role_01_%s"
598+
description = "Testing resource sumologic_role"
599+
capabilities = [
600+
"viewAlerts",
601+
"viewMonitorsV2",
602+
"manageMonitorsV2"
603+
]
604+
}
605+
resource "sumologic_role" "tf_test_role_02" {
606+
name = "tf_test_role_02_%s"
607+
description = "Testing resource sumologic_role"
608+
capabilities = [
609+
"viewAlerts",
610+
"viewMonitorsV2",
611+
"manageMonitorsV2"
612+
]
613+
}
614+
resource "sumologic_role" "tf_test_role_03" {
615+
name = "tf_test_role_03_%s"
616+
description = "Testing resource sumologic_role"
617+
capabilities = [
618+
"viewAlerts",
619+
"viewMonitorsV2",
620+
"manageMonitorsV2"
621+
]
622+
}`, testName, testName, testName, testName)
527623
}
528624

529625
func testAccSumologicMonitorsLibraryMonitorUpdate(testName string) string {
@@ -570,7 +666,92 @@ resource "sumologic_monitor" "test" {
570666
}
571667
playbook = "This is an updated test playbook"
572668
alert_name = "Updated Alert from {{Name}}"
573-
}`, testName)
669+
obj_permission {
670+
subject_type = "role"
671+
subject_id = sumologic_role.tf_test_role_01.id
672+
permissions = ["Read","Update"]
673+
}
674+
}
675+
resource "sumologic_role" "tf_test_role_01" {
676+
name = "tf_test_role_01_%s"
677+
description = "Testing resource sumologic_role"
678+
capabilities = [
679+
"viewAlerts",
680+
"viewMonitorsV2",
681+
"manageMonitorsV2"
682+
]
683+
}`, testName, testName)
684+
}
685+
686+
func testAccEmulateFGPDriftingMonitor(
687+
t *testing.T,
688+
// expectedFGPFunc func(*terraform.State, string) ([]CmfFgpPermStatement, error),
689+
) resource.TestCheckFunc {
690+
691+
return func(s *terraform.State) error {
692+
693+
monitorTargetId, resIdErr := getResourceID(s, "sumologic_monitor.test")
694+
if resIdErr != nil {
695+
return resIdErr
696+
}
697+
role01Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_01")
698+
if resIdErr != nil {
699+
return resIdErr
700+
}
701+
role02Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_02")
702+
if resIdErr != nil {
703+
return resIdErr
704+
}
705+
role03Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_03")
706+
if resIdErr != nil {
707+
return resIdErr
708+
}
709+
710+
client := testAccProvider.Meta().(*Client)
711+
expectedReadPermStmts := []CmfFgpPermStatement{
712+
{SubjectType: "role", SubjectId: role01Id, TargetId: monitorTargetId,
713+
Permissions: []string{"Read", "Update"}},
714+
{SubjectType: "role", SubjectId: role03Id, TargetId: monitorTargetId,
715+
Permissions: []string{"Read"}},
716+
}
717+
// using an empty Permissions array to achieve the effect of FGP Revocation
718+
setFGPPermStmts := append(expectedReadPermStmts,
719+
CmfFgpPermStatement{SubjectType: "role", SubjectId: role02Id, TargetId: monitorTargetId,
720+
Permissions: []string{}})
721+
722+
_, setFgpErr := client.SetCmfFgp("monitors", CmfFgpRequest{
723+
PermissionStatements: setFGPPermStmts})
724+
if setFgpErr != nil {
725+
return setFgpErr
726+
}
727+
728+
readfgpResult, readFgpErr := client.GetCmfFgp("monitors", monitorTargetId)
729+
if readFgpErr != nil {
730+
return readFgpErr
731+
}
732+
733+
var expectedPermStmts []CmfFgpPermStatement
734+
expectedPermStmts = append(expectedPermStmts,
735+
CmfFgpPermStatement{
736+
SubjectId: role01Id,
737+
SubjectType: "role",
738+
TargetId: monitorTargetId,
739+
Permissions: []string{"Read", "Update"},
740+
},
741+
CmfFgpPermStatement{
742+
SubjectId: role03Id,
743+
SubjectType: "role",
744+
TargetId: monitorTargetId,
745+
Permissions: []string{"Read"},
746+
},
747+
)
748+
749+
if !CmfFgpPermStmtSetEqual(readfgpResult.PermissionStatements, expectedPermStmts) {
750+
return fmt.Errorf("Permission Statements are different:\n %+v\n %+v\n",
751+
readfgpResult.PermissionStatements, expectedPermStmts)
752+
}
753+
return nil
754+
}
574755
}
575756

576757
func exampleMonitorWithTriggerCondition(
@@ -800,3 +981,81 @@ func exampleMetricsMissingDataTriggerCondition(triggerType string) TriggerCondit
800981
DetectionMethod: "MetricsMissingDataCondition",
801982
}
802983
}
984+
985+
func genExpectedPermStmtsMonitor(s *terraform.State, targetId string) ([]CmfFgpPermStatement, error) {
986+
role01Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_01")
987+
if resIdErr != nil {
988+
return nil, resIdErr
989+
}
990+
role02Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_02")
991+
if resIdErr != nil {
992+
return nil, resIdErr
993+
}
994+
995+
var expectedPermStmts []CmfFgpPermStatement
996+
expectedPermStmts = append(expectedPermStmts,
997+
CmfFgpPermStatement{
998+
SubjectId: role01Id,
999+
SubjectType: "role",
1000+
TargetId: targetId,
1001+
Permissions: []string{"Read", "Update", "Delete"},
1002+
},
1003+
CmfFgpPermStatement{
1004+
SubjectId: role02Id,
1005+
SubjectType: "role",
1006+
TargetId: targetId,
1007+
Permissions: []string{"Read"},
1008+
},
1009+
)
1010+
return expectedPermStmts, nil
1011+
}
1012+
1013+
func genExpectedPermStmtsForMonitorUpdate(s *terraform.State, targetId string) ([]CmfFgpPermStatement, error) {
1014+
role01Id, resIdErr := getResourceID(s, "sumologic_role.tf_test_role_01")
1015+
if resIdErr != nil {
1016+
return nil, resIdErr
1017+
}
1018+
1019+
var expectedPermStmts []CmfFgpPermStatement
1020+
expectedPermStmts = append(expectedPermStmts,
1021+
CmfFgpPermStatement{
1022+
SubjectId: role01Id,
1023+
SubjectType: "role",
1024+
TargetId: targetId,
1025+
Permissions: []string{"Read", "Update"},
1026+
},
1027+
)
1028+
return expectedPermStmts, nil
1029+
}
1030+
1031+
func testAccCheckMonitorsLibraryMonitorFGPBackend(
1032+
name string,
1033+
t *testing.T,
1034+
expectedFGPFunc func(*terraform.State, string) ([]CmfFgpPermStatement, error),
1035+
) resource.TestCheckFunc {
1036+
1037+
return func(s *terraform.State) error {
1038+
targetId, resIdErr := getResourceID(s, name)
1039+
if resIdErr != nil {
1040+
return resIdErr
1041+
}
1042+
1043+
expectedPermStmts, resIdErr := expectedFGPFunc(s, targetId)
1044+
if resIdErr != nil {
1045+
return resIdErr
1046+
}
1047+
1048+
client := testAccProvider.Meta().(*Client)
1049+
1050+
fgpResult, fgpErr := client.GetCmfFgp("monitors", targetId)
1051+
if fgpErr != nil {
1052+
return fgpErr
1053+
}
1054+
1055+
if !CmfFgpPermStmtSetEqual(fgpResult.PermissionStatements, expectedPermStmts) {
1056+
return fmt.Errorf("Permission Statements are different:\n %+v\n %+v\n",
1057+
fgpResult.PermissionStatements, expectedPermStmts)
1058+
}
1059+
return nil
1060+
}
1061+
}

0 commit comments

Comments
 (0)