From f9529f4c8c6bf8876f3b0287f94ecd58dc90f2d8 Mon Sep 17 00:00:00 2001 From: John Love Date: Wed, 4 Jan 2023 17:16:07 -0800 Subject: [PATCH 1/4] SNOW-710421: Adding more functionality to resource_monitor update --- pkg/resources/resource_monitor.go | 102 ++++++++++++++++-- .../resource_monitor_acceptance_test.go | 8 +- pkg/snowflake/resource_monitor.go | 93 ++++++++++++++++ 3 files changed, 194 insertions(+), 9 deletions(-) diff --git a/pkg/resources/resource_monitor.go b/pkg/resources/resource_monitor.go index 09ab7b545c..d7d04105d1 100644 --- a/pkg/resources/resource_monitor.go +++ b/pkg/resources/resource_monitor.go @@ -25,7 +25,6 @@ var resourceMonitorSchema = map[string]*schema.Schema{ "notify_users": { Type: schema.TypeSet, Optional: true, - ForceNew: true, Description: "Specifies the list of users to receive email notifications on resource monitors.", Elem: &schema.Schema{ Type: schema.TypeString, @@ -60,35 +59,30 @@ var resourceMonitorSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeInt}, Optional: true, Description: "A list of percentage thresholds at which to suspend all warehouses.", - ForceNew: true, }, "suspend_immediate_triggers": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeInt}, Optional: true, Description: "A list of percentage thresholds at which to immediately suspend all warehouses.", - ForceNew: true, }, "notify_triggers": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeInt}, Optional: true, Description: "A list of percentage thresholds at which to send an alert to subscribed users.", - ForceNew: true, }, "set_for_account": { Type: schema.TypeBool, Optional: true, Description: "Specifies whether the resource monitor should be applied globally to your Snowflake account.", Default: false, - ForceNew: true, }, "warehouses": { Type: schema.TypeSet, Optional: true, Description: "A list of warehouses to apply the resource monitor to.", Elem: &schema.Schema{Type: schema.TypeString}, - ForceNew: true, }, } @@ -107,7 +101,7 @@ func ResourceMonitor() *schema.Resource { } } -// CreateResourceMonitor implents schema.CreateFunc. +// CreateResourceMonitor implements schema.CreateFunc. func CreateResourceMonitor(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) name := d.Get("name").(string) @@ -283,6 +277,42 @@ func extractTriggerInts(s sql.NullString) ([]int, error) { return out, nil } +// inSlice returns true if n is in string slice h otherwise false. +func inSlice(n string, h []string) bool { + for _, v := range h { + if v == n { + return true + } + } + return false +} + +// convertTerraformSetToStringSlice turns a terraform set into a string slice +func convertTerraformSetToStringSlice(i interface{}) []string { + var s []string + for _, w := range i.(*schema.Set).List() { + s = append(s, w.(string)) + } + return s +} + +// compareTerraformSets compares two terraform sets and returns a string slice of all values in the first set that is +// not in the second set. +func compareTerraformSets(firstSet interface{}, SecondSet interface{}) []string { + res := make([]string, 0) + sliceOne := convertTerraformSetToStringSlice(firstSet) + + sliceTwo := convertTerraformSetToStringSlice(SecondSet) + + for _, s := range sliceOne { + if !inSlice(s, sliceTwo) { + res = append(res, s) + } + } + return res +} + +// UpdateResourceMonitor implements schema.UpdateFunc. func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) id := d.Id() @@ -290,6 +320,11 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { stmt := snowflake.NewResourceMonitorBuilder(id).Alter() var runSetStatement bool + if d.HasChange("notify_users") { + runSetStatement = true + stmt.SetStringList(`NOTIFY_USERS`, expandStringList(d.Get("notify_users").(*schema.Set).List())) + } + if d.HasChange("credit_quota") { runSetStatement = true stmt.SetInt(`CREDIT_QUOTA`, d.Get("credit_quota").(int)) @@ -310,12 +345,65 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { stmt.SetString(`END_TIMESTAMP`, d.Get("end_timestamp").(string)) } + // Set triggers + sTrigs := expandIntList(d.Get("suspend_triggers").(*schema.Set).List()) + for _, t := range sTrigs { + runSetStatement = true + stmt.SuspendAt(t) + } + siTrigs := expandIntList(d.Get("suspend_immediate_triggers").(*schema.Set).List()) + for _, t := range siTrigs { + runSetStatement = true + stmt.SuspendImmediatelyAt(t) + } + nTrigs := expandIntList(d.Get("notify_triggers").(*schema.Set).List()) + for _, t := range nTrigs { + runSetStatement = true + stmt.NotifyAt(t) + } + if runSetStatement { if err := snowflake.Exec(db, stmt.Statement()); err != nil { return fmt.Errorf("error updating resource monitor %v\n%w", id, err) } } + // Remove from account + if d.HasChange("set_for_account") && d.Get("set_for_account").(bool) == false { + if err := snowflake.Exec(db, stmt.UnsetOnAccount()); err != nil { + return fmt.Errorf("error unsetting resource monitor %v on account err = %w", id, err) + } + } + + // Remove from all old warehouses + if d.HasChange("warehouses") { + oldV, v := d.GetChange("warehouses") + res := compareTerraformSets(oldV, v) + for _, w := range res { + if err := snowflake.Exec(db, stmt.UnsetOnWarehouse(w)); err != nil { + return fmt.Errorf("error setting resource monitor %v on warehouse %v err = %w", id, w, err) + } + } + } + + // Add to account + if d.HasChange("set_for_account") && d.Get("set_for_account").(bool) { + if err := snowflake.Exec(db, stmt.SetOnAccount()); err != nil { + return fmt.Errorf("error setting resource monitor %v on account err = %w", id, err) + } + } + + // Add to all new warehouses + if d.HasChange("warehouses") { + oldV, v := d.GetChange("warehouses") + res := compareTerraformSets(v, oldV) + for _, w := range res { + if err := snowflake.Exec(db, stmt.SetOnWarehouse(w)); err != nil { + return fmt.Errorf("error setting resource monitor %v on warehouse %v err = %w", id, w, err) + } + } + } + return ReadResourceMonitor(d, meta) } diff --git a/pkg/resources/resource_monitor_acceptance_test.go b/pkg/resources/resource_monitor_acceptance_test.go index 54b34e30b3..b491b7adfb 100644 --- a/pkg/resources/resource_monitor_acceptance_test.go +++ b/pkg/resources/resource_monitor_acceptance_test.go @@ -25,6 +25,7 @@ func TestAcc_ResourceMonitor(t *testing.T) { resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", name), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "credit_quota", "100"), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "false"), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "notify_triggers.0", "40"), ), }, // CHANGE PROPERTIES @@ -33,7 +34,8 @@ func TestAcc_ResourceMonitor(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "name", name), resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "credit_quota", "150"), - resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "false"), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "set_for_account", "true"), + resource.TestCheckResourceAttr("snowflake_resource_monitor.test", "notify_triggers.0", "50"), ), }, // IMPORT @@ -52,6 +54,7 @@ resource "snowflake_resource_monitor" "test" { name = "%v" credit_quota = 100 set_for_account = false + notify_triggers = [40] } `, accName) } @@ -61,7 +64,8 @@ func resourceMonitorConfig2(accName string) string { resource "snowflake_resource_monitor" "test" { name = "%v" credit_quota = 150 - set_for_account = false + set_for_account = true + notify_triggers = [50] } `, accName) } diff --git a/pkg/snowflake/resource_monitor.go b/pkg/snowflake/resource_monitor.go index fb0643743a..daa0042e6c 100644 --- a/pkg/snowflake/resource_monitor.go +++ b/pkg/snowflake/resource_monitor.go @@ -44,6 +44,14 @@ type ResourceMonitorCreateBuilder struct { triggers []trigger } +type ResourceMonitorAlterBuilder struct { + AlterPropertiesBuilder + + // triggers consist of the type (DO SUSPEND | SUSPEND_IMMEDIATE | NOTIFY) and + // the threshold (a percentage value) + triggers []trigger +} + type trigger struct { action string threshold int @@ -134,6 +142,91 @@ func (rcb *ResourceMonitorCreateBuilder) SetOnWarehouse(warehouse string) string return fmt.Sprintf(`ALTER WAREHOUSE "%v" SET RESOURCE_MONITOR = "%v"`, warehouse, rcb.name) } +// Alter returns a pointer to a ResourceMonitorAlterBuilder. +func (rb *ResourceMonitorBuilder) Alter() *ResourceMonitorAlterBuilder { + return &ResourceMonitorAlterBuilder{ + AlterPropertiesBuilder{ + name: rb.name, + entityType: rb.entityType, + stringProperties: make(map[string]string), + boolProperties: make(map[string]bool), + intProperties: make(map[string]int), + floatProperties: make(map[string]float64), + stringListProperties: make(map[string][]string), + }, + make([]trigger, 0), + } +} + +// NotifyAt adds a notify trigger at the specified percentage threshold. +func (rcb *ResourceMonitorAlterBuilder) NotifyAt(pct int) *ResourceMonitorAlterBuilder { + rcb.triggers = append(rcb.triggers, trigger{NotifyTrigger, pct}) + return rcb +} + +// SuspendAt adds a suspend trigger at the specified percentage threshold. +func (rcb *ResourceMonitorAlterBuilder) SuspendAt(pct int) *ResourceMonitorAlterBuilder { + rcb.triggers = append(rcb.triggers, trigger{SuspendTrigger, pct}) + return rcb +} + +// SuspendImmediatelyAt adds a suspend immediately trigger at the specified percentage threshold. +func (rcb *ResourceMonitorAlterBuilder) SuspendImmediatelyAt(pct int) *ResourceMonitorAlterBuilder { + rcb.triggers = append(rcb.triggers, trigger{SuspendImmediatelyTrigger, pct}) + return rcb +} + +// Statement returns the SQL statement needed to actually alter the resource. +func (rcb *ResourceMonitorAlterBuilder) Statement() string { + var sb strings.Builder + sb.WriteString(fmt.Sprintf(`ALTER %v "%v" SET`, rcb.entityType, rcb.name)) + + for k, v := range rcb.stringProperties { + sb.WriteString(fmt.Sprintf(` %v='%v'`, strings.ToUpper(k), EscapeString(v))) + } + + for k, v := range rcb.intProperties { + sb.WriteString(fmt.Sprintf(` %v=%d`, strings.ToUpper(k), v)) + } + + for k, v := range rcb.floatProperties { + sb.WriteString(fmt.Sprintf(` %v=%.2f`, strings.ToUpper(k), v)) + } + + for k, v := range rcb.stringListProperties { + sb.WriteString(fmt.Sprintf(" %s=%s", strings.ToUpper(k), formatStringList(v))) + } + + if len(rcb.triggers) > 0 { + sb.WriteString(" TRIGGERS") + } + + for _, trig := range rcb.triggers { + sb.WriteString(fmt.Sprintf(` ON %d PERCENT DO %v`, trig.threshold, trig.action)) + } + + return sb.String() +} + +// SetOnAccount returns the SQL query that will set the resource monitor globally on your Snowflake account. +func (rcb *ResourceMonitorAlterBuilder) SetOnAccount() string { + return fmt.Sprintf(`ALTER ACCOUNT SET RESOURCE_MONITOR = "%v"`, rcb.name) +} + +func (rcb *ResourceMonitorAlterBuilder) UnsetOnAccount() string { + return fmt.Sprintf(`ALTER ACCOUNT SET RESOURCE_MONITOR = NULL`) +} + +// SetOnWarehouse returns the SQL query that will set the resource monitor on the specified warehouse. +func (rcb *ResourceMonitorAlterBuilder) SetOnWarehouse(warehouse string) string { + return fmt.Sprintf(`ALTER WAREHOUSE "%v" SET RESOURCE_MONITOR = "%v"`, warehouse, rcb.name) +} + +// UnsetOnWarehouse returns the SQL query that will unset the resource monitor on the specified warehouse. +func (rcb *ResourceMonitorAlterBuilder) UnsetOnWarehouse(warehouse string) string { + return fmt.Sprintf(`ALTER WAREHOUSE "%v" SET RESOURCE_MONITOR = NULL`, warehouse) +} + type ResourceMonitor struct { Name sql.NullString `db:"name"` CreditQuota sql.NullString `db:"credit_quota"` From 284080a19c3c728f63f30cb4110b3c85398a38bc Mon Sep 17 00:00:00 2001 From: John Love Date: Wed, 4 Jan 2023 17:34:14 -0800 Subject: [PATCH 2/4] =?UTF-8?q?SNOW-710421:=20reviewdog=20=F0=9F=90=B6=20f?= =?UTF-8?q?ixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/resources/resource_monitor.go | 14 +++++++------- pkg/snowflake/resource_monitor.go | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/resources/resource_monitor.go b/pkg/resources/resource_monitor.go index d7d04105d1..48bb803574 100644 --- a/pkg/resources/resource_monitor.go +++ b/pkg/resources/resource_monitor.go @@ -287,22 +287,22 @@ func inSlice(n string, h []string) bool { return false } -// convertTerraformSetToStringSlice turns a terraform set into a string slice +// convertTerraformSetToStringSlice turns a terraform set into a string slice. func convertTerraformSetToStringSlice(i interface{}) []string { - var s []string - for _, w := range i.(*schema.Set).List() { - s = append(s, w.(string)) + s := make([]string, len(i.(*schema.Set).List())) + for x, w := range i.(*schema.Set).List() { + s[x] = w.(string) } return s } // compareTerraformSets compares two terraform sets and returns a string slice of all values in the first set that is // not in the second set. -func compareTerraformSets(firstSet interface{}, SecondSet interface{}) []string { +func compareTerraformSets(firstSet interface{}, secondSet interface{}) []string { res := make([]string, 0) sliceOne := convertTerraformSetToStringSlice(firstSet) - sliceTwo := convertTerraformSetToStringSlice(SecondSet) + sliceTwo := convertTerraformSetToStringSlice(secondSet) for _, s := range sliceOne { if !inSlice(s, sliceTwo) { @@ -369,7 +369,7 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { } // Remove from account - if d.HasChange("set_for_account") && d.Get("set_for_account").(bool) == false { + if d.HasChange("set_for_account") && !d.Get("set_for_account").(bool) { if err := snowflake.Exec(db, stmt.UnsetOnAccount()); err != nil { return fmt.Errorf("error unsetting resource monitor %v on account err = %w", id, err) } diff --git a/pkg/snowflake/resource_monitor.go b/pkg/snowflake/resource_monitor.go index daa0042e6c..a9adaa1b41 100644 --- a/pkg/snowflake/resource_monitor.go +++ b/pkg/snowflake/resource_monitor.go @@ -214,7 +214,7 @@ func (rcb *ResourceMonitorAlterBuilder) SetOnAccount() string { } func (rcb *ResourceMonitorAlterBuilder) UnsetOnAccount() string { - return fmt.Sprintf(`ALTER ACCOUNT SET RESOURCE_MONITOR = NULL`) + return `ALTER ACCOUNT SET RESOURCE_MONITOR = NULL` } // SetOnWarehouse returns the SQL query that will set the resource monitor on the specified warehouse. From eea37e6d8a40c945aaa570f461b4a137ccf32e4b Mon Sep 17 00:00:00 2001 From: John Love Date: Thu, 5 Jan 2023 17:09:49 -0800 Subject: [PATCH 3/4] SNOW-710421: Cleaning up code --- pkg/resources/helper_expansion.go | 15 +++++++ pkg/resources/resource_monitor.go | 67 ++++++++----------------------- pkg/snowflake/resource_monitor.go | 10 +++-- 3 files changed, 37 insertions(+), 55 deletions(-) diff --git a/pkg/resources/helper_expansion.go b/pkg/resources/helper_expansion.go index 188b96fed4..c95a55ee08 100644 --- a/pkg/resources/helper_expansion.go +++ b/pkg/resources/helper_expansion.go @@ -1,5 +1,7 @@ package resources +import "golang.org/x/exp/slices" + // borrowed from https://github.com/terraform-providers/terraform-provider-aws/blob/master/aws/structure.go#L924:6 func expandIntList(configured []interface{}) []int { @@ -36,3 +38,16 @@ func expandObjectIdentifier(objectIdentifier interface{}) (string, string, strin } return objectDatabase, objectSchema, objectName } + +// intersectionAAndNotB takes the intersection of set A and the intersection of not set B. A∩B′ in set notation. +func intersectionAAndNotB(setA []interface{}, setB []interface{}) []string { + res := make([]string, 0) + sliceA := expandStringList(setA) + sliceB := expandStringList(setB) + for _, s := range sliceA { + if !slices.Contains(sliceB, s) { + res = append(res, s) + } + } + return res +} diff --git a/pkg/resources/resource_monitor.go b/pkg/resources/resource_monitor.go index 48bb803574..64b56b802c 100644 --- a/pkg/resources/resource_monitor.go +++ b/pkg/resources/resource_monitor.go @@ -277,100 +277,65 @@ func extractTriggerInts(s sql.NullString) ([]int, error) { return out, nil } -// inSlice returns true if n is in string slice h otherwise false. -func inSlice(n string, h []string) bool { - for _, v := range h { - if v == n { - return true - } - } - return false -} - -// convertTerraformSetToStringSlice turns a terraform set into a string slice. -func convertTerraformSetToStringSlice(i interface{}) []string { - s := make([]string, len(i.(*schema.Set).List())) - for x, w := range i.(*schema.Set).List() { - s[x] = w.(string) - } - return s -} - -// compareTerraformSets compares two terraform sets and returns a string slice of all values in the first set that is -// not in the second set. -func compareTerraformSets(firstSet interface{}, secondSet interface{}) []string { - res := make([]string, 0) - sliceOne := convertTerraformSetToStringSlice(firstSet) - - sliceTwo := convertTerraformSetToStringSlice(secondSet) - - for _, s := range sliceOne { - if !inSlice(s, sliceTwo) { - res = append(res, s) - } - } - return res -} - // UpdateResourceMonitor implements schema.UpdateFunc. func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { db := meta.(*sql.DB) id := d.Id() - stmt := snowflake.NewResourceMonitorBuilder(id).Alter() + ub := snowflake.NewResourceMonitorBuilder(id).Alter() var runSetStatement bool if d.HasChange("notify_users") { runSetStatement = true - stmt.SetStringList(`NOTIFY_USERS`, expandStringList(d.Get("notify_users").(*schema.Set).List())) + ub.SetStringList(`NOTIFY_USERS`, expandStringList(d.Get("notify_users").(*schema.Set).List())) } if d.HasChange("credit_quota") { runSetStatement = true - stmt.SetInt(`CREDIT_QUOTA`, d.Get("credit_quota").(int)) + ub.SetInt(`CREDIT_QUOTA`, d.Get("credit_quota").(int)) } if d.HasChange("frequency") { runSetStatement = true - stmt.SetString(`FREQUENCY`, d.Get("frequency").(string)) + ub.SetString(`FREQUENCY`, d.Get("frequency").(string)) } if d.HasChange("start_timestamp") { runSetStatement = true - stmt.SetString(`START_TIMESTAMP`, d.Get("start_timestamp").(string)) + ub.SetString(`START_TIMESTAMP`, d.Get("start_timestamp").(string)) } if d.HasChange("end_timestamp") { runSetStatement = true - stmt.SetString(`END_TIMESTAMP`, d.Get("end_timestamp").(string)) + ub.SetString(`END_TIMESTAMP`, d.Get("end_timestamp").(string)) } // Set triggers sTrigs := expandIntList(d.Get("suspend_triggers").(*schema.Set).List()) for _, t := range sTrigs { runSetStatement = true - stmt.SuspendAt(t) + ub.SuspendAt(t) } siTrigs := expandIntList(d.Get("suspend_immediate_triggers").(*schema.Set).List()) for _, t := range siTrigs { runSetStatement = true - stmt.SuspendImmediatelyAt(t) + ub.SuspendImmediatelyAt(t) } nTrigs := expandIntList(d.Get("notify_triggers").(*schema.Set).List()) for _, t := range nTrigs { runSetStatement = true - stmt.NotifyAt(t) + ub.NotifyAt(t) } if runSetStatement { - if err := snowflake.Exec(db, stmt.Statement()); err != nil { + if err := snowflake.Exec(db, ub.Statement()); err != nil { return fmt.Errorf("error updating resource monitor %v\n%w", id, err) } } // Remove from account if d.HasChange("set_for_account") && !d.Get("set_for_account").(bool) { - if err := snowflake.Exec(db, stmt.UnsetOnAccount()); err != nil { + if err := snowflake.Exec(db, ub.UnsetOnAccount()); err != nil { return fmt.Errorf("error unsetting resource monitor %v on account err = %w", id, err) } } @@ -378,9 +343,9 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { // Remove from all old warehouses if d.HasChange("warehouses") { oldV, v := d.GetChange("warehouses") - res := compareTerraformSets(oldV, v) + res := intersectionAAndNotB(oldV.(*schema.Set).List(), v.(*schema.Set).List()) for _, w := range res { - if err := snowflake.Exec(db, stmt.UnsetOnWarehouse(w)); err != nil { + if err := snowflake.Exec(db, ub.UnsetOnWarehouse(w)); err != nil { return fmt.Errorf("error setting resource monitor %v on warehouse %v err = %w", id, w, err) } } @@ -388,7 +353,7 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { // Add to account if d.HasChange("set_for_account") && d.Get("set_for_account").(bool) { - if err := snowflake.Exec(db, stmt.SetOnAccount()); err != nil { + if err := snowflake.Exec(db, ub.SetOnAccount()); err != nil { return fmt.Errorf("error setting resource monitor %v on account err = %w", id, err) } } @@ -396,9 +361,9 @@ func UpdateResourceMonitor(d *schema.ResourceData, meta interface{}) error { // Add to all new warehouses if d.HasChange("warehouses") { oldV, v := d.GetChange("warehouses") - res := compareTerraformSets(v, oldV) + res := intersectionAAndNotB(v.(*schema.Set).List(), oldV.(*schema.Set).List()) for _, w := range res { - if err := snowflake.Exec(db, stmt.SetOnWarehouse(w)); err != nil { + if err := snowflake.Exec(db, ub.SetOnWarehouse(w)); err != nil { return fmt.Errorf("error setting resource monitor %v on warehouse %v err = %w", id, w, err) } } diff --git a/pkg/snowflake/resource_monitor.go b/pkg/snowflake/resource_monitor.go index a9adaa1b41..87ac98545c 100644 --- a/pkg/snowflake/resource_monitor.go +++ b/pkg/snowflake/resource_monitor.go @@ -52,18 +52,20 @@ type ResourceMonitorAlterBuilder struct { triggers []trigger } +type action string + type trigger struct { - action string + action action threshold int } const ( // SuspendTrigger suspends all assigned warehouses while allowing currently running queries to complete. - SuspendTrigger = "SUSPEND" + SuspendTrigger action = "SUSPEND" // SuspendImmediatelyTrigger suspends all assigned warehouses immediately and cancel any currently running queries or statements using the warehouses. - SuspendImmediatelyTrigger = "SUSPEND_IMMEDIATE" + SuspendImmediatelyTrigger action = "SUSPEND_IMMEDIATE" // NotifyTrigger sends an alert (to all users who have enabled notifications for themselves), but do not take any other action. - NotifyTrigger = "NOTIFY" + NotifyTrigger action = "NOTIFY" ) // Create returns a pointer to a ResourceMonitorCreateBuilder. From f63d1b5c94095f93a7624a5d30a157511061d3ce Mon Sep 17 00:00:00 2001 From: John Love Date: Tue, 10 Jan 2023 11:15:58 -0800 Subject: [PATCH 4/4] SNOW-710421: Adds ConflictsWith for warehouses and set_for_account --- pkg/resources/resource_monitor.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/pkg/resources/resource_monitor.go b/pkg/resources/resource_monitor.go index 64b56b802c..b48d7b4b55 100644 --- a/pkg/resources/resource_monitor.go +++ b/pkg/resources/resource_monitor.go @@ -73,16 +73,18 @@ var resourceMonitorSchema = map[string]*schema.Schema{ Description: "A list of percentage thresholds at which to send an alert to subscribed users.", }, "set_for_account": { - Type: schema.TypeBool, - Optional: true, - Description: "Specifies whether the resource monitor should be applied globally to your Snowflake account.", - Default: false, + Type: schema.TypeBool, + Optional: true, + ConflictsWith: []string{"warehouses"}, + Description: "Specifies whether the resource monitor should be applied globally to your Snowflake account.", + Default: false, }, "warehouses": { - Type: schema.TypeSet, - Optional: true, - Description: "A list of warehouses to apply the resource monitor to.", - Elem: &schema.Schema{Type: schema.TypeString}, + Type: schema.TypeSet, + Optional: true, + ConflictsWith: []string{"set_for_account"}, + Description: "A list of warehouses to apply the resource monitor to.", + Elem: &schema.Schema{Type: schema.TypeString}, }, }