From a948669c59bfdfaec3d2fddc5cdddcab9362c005 Mon Sep 17 00:00:00 2001 From: The Magician Date: Thu, 24 Aug 2023 19:06:41 -0400 Subject: [PATCH] Adds the synthetic monitor target type as an option for uptime checks. (#8709) (#15623) * Adds synthetic_monitor type that lives alongside resource_group and monitored_resource * removes requirement for either tcp_check or http_check to be provided, as neither is required when synthetic_monitor is provided * Adds acceptance test, and example. A new test fixutre w/ zip file is provided for these flows. Signed-off-by: Modular Magician --- .changelog/8709.txt | 3 + ...resource_monitoring_uptime_check_config.go | 117 +++++++++++++++++- ...ring_uptime_check_config_generated_test.go | 75 +++++++++++ .../test-fixtures/synthetic-fn-source.zip | Bin 0 -> 2124 bytes ...nitoring_uptime_check_config.html.markdown | 68 ++++++++++ 5 files changed, 259 insertions(+), 4 deletions(-) create mode 100644 .changelog/8709.txt create mode 100644 google/services/monitoring/test-fixtures/synthetic-fn-source.zip diff --git a/.changelog/8709.txt b/.changelog/8709.txt new file mode 100644 index 00000000000..ef7f3ed6f1b --- /dev/null +++ b/.changelog/8709.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +monitoring: added `synthetic_monitor` to `google_monitoring_uptime_check_config` resource +``` diff --git a/google/services/monitoring/resource_monitoring_uptime_check_config.go b/google/services/monitoring/resource_monitoring_uptime_check_config.go index 854b32fe6b1..5f3dbf0a121 100644 --- a/google/services/monitoring/resource_monitoring_uptime_check_config.go +++ b/google/services/monitoring/resource_monitoring_uptime_check_config.go @@ -224,7 +224,6 @@ func ResourceMonitoringUptimeCheckConfig() *schema.Resource { }, }, }, - ExactlyOneOf: []string{"http_check", "tcp_check"}, }, "monitored_resource": { Type: schema.TypeList, @@ -249,7 +248,7 @@ func ResourceMonitoringUptimeCheckConfig() *schema.Resource { }, }, }, - ExactlyOneOf: []string{"monitored_resource", "resource_group"}, + ExactlyOneOf: []string{"monitored_resource", "resource_group", "synthetic_monitor"}, }, "period": { Type: schema.TypeString, @@ -283,7 +282,7 @@ func ResourceMonitoringUptimeCheckConfig() *schema.Resource { }, }, }, - ExactlyOneOf: []string{"monitored_resource", "resource_group"}, + ExactlyOneOf: []string{"monitored_resource", "resource_group", "synthetic_monitor"}, }, "selected_regions": { Type: schema.TypeList, @@ -293,6 +292,36 @@ func ResourceMonitoringUptimeCheckConfig() *schema.Resource { Type: schema.TypeString, }, }, + "synthetic_monitor": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `A Synthetic Monitor deployed to a Cloud Functions V2 instance.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloud_function_v2": { + Type: schema.TypeList, + Required: true, + ForceNew: true, + Description: `Target a Synthetic Monitor GCFv2 Instance`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The fully qualified name of the cloud function resource.`, + }, + }, + }, + ExactlyOneOf: []string{}, + }, + }, + }, + ExactlyOneOf: []string{"monitored_resource", "resource_group", "synthetic_monitor"}, + }, "tcp_check": { Type: schema.TypeList, Optional: true, @@ -307,7 +336,6 @@ func ResourceMonitoringUptimeCheckConfig() *schema.Resource { }, }, }, - ExactlyOneOf: []string{"http_check", "tcp_check"}, }, "name": { Type: schema.TypeString, @@ -398,6 +426,12 @@ func resourceMonitoringUptimeCheckConfigCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("monitored_resource"); !tpgresource.IsEmptyValue(reflect.ValueOf(monitoredResourceProp)) && (ok || !reflect.DeepEqual(v, monitoredResourceProp)) { obj["monitoredResource"] = monitoredResourceProp } + syntheticMonitorProp, err := expandMonitoringUptimeCheckConfigSyntheticMonitor(d.Get("synthetic_monitor"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("synthetic_monitor"); !tpgresource.IsEmptyValue(reflect.ValueOf(syntheticMonitorProp)) && (ok || !reflect.DeepEqual(v, syntheticMonitorProp)) { + obj["syntheticMonitor"] = syntheticMonitorProp + } lockName, err := tpgresource.ReplaceVars(d, config, "stackdriver/groups/{{project}}") if err != nil { @@ -549,6 +583,9 @@ func resourceMonitoringUptimeCheckConfigRead(d *schema.ResourceData, meta interf if err := d.Set("monitored_resource", flattenMonitoringUptimeCheckConfigMonitoredResource(res["monitoredResource"], d, config)); err != nil { return fmt.Errorf("Error reading UptimeCheckConfig: %s", err) } + if err := d.Set("synthetic_monitor", flattenMonitoringUptimeCheckConfigSyntheticMonitor(res["syntheticMonitor"], d, config)); err != nil { + return fmt.Errorf("Error reading UptimeCheckConfig: %s", err) + } return nil } @@ -1053,6 +1090,36 @@ func flattenMonitoringUptimeCheckConfigMonitoredResourceLabels(v interface{}, d return v } +func flattenMonitoringUptimeCheckConfigSyntheticMonitor(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["cloud_function_v2"] = + flattenMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2(original["cloudFunctionV2"], d, config) + return []interface{}{transformed} +} +func flattenMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["name"] = + flattenMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2Name(original["name"], d, config) + return []interface{}{transformed} +} +func flattenMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2Name(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandMonitoringUptimeCheckConfigDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -1451,3 +1518,45 @@ func expandMonitoringUptimeCheckConfigMonitoredResourceLabels(v interface{}, d t } return m, nil } + +func expandMonitoringUptimeCheckConfigSyntheticMonitor(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedCloudFunctionV2, err := expandMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2(original["cloud_function_v2"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCloudFunctionV2); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["cloudFunctionV2"] = transformedCloudFunctionV2 + } + + return transformed, nil +} + +func expandMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedName, err := expandMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2Name(original["name"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["name"] = transformedName + } + + return transformed, nil +} + +func expandMonitoringUptimeCheckConfigSyntheticMonitorCloudFunctionV2Name(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} diff --git a/google/services/monitoring/resource_monitoring_uptime_check_config_generated_test.go b/google/services/monitoring/resource_monitoring_uptime_check_config_generated_test.go index f78bace2912..641501eb250 100644 --- a/google/services/monitoring/resource_monitoring_uptime_check_config_generated_test.go +++ b/google/services/monitoring/resource_monitoring_uptime_check_config_generated_test.go @@ -268,6 +268,81 @@ resource "google_monitoring_group" "check" { `, context) } +func TestAccMonitoringUptimeCheckConfig_uptimeCheckConfigSyntheticMonitorExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "zip_path": "./test-fixtures/synthetic-fn-source.zip", + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckMonitoringUptimeCheckConfigDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccMonitoringUptimeCheckConfig_uptimeCheckConfigSyntheticMonitorExample(context), + }, + { + ResourceName: "google_monitoring_uptime_check_config.synthetic_monitor", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccMonitoringUptimeCheckConfig_uptimeCheckConfigSyntheticMonitorExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_storage_bucket" "bucket" { + name = "%{project_id}-tf-test-gcf-source%{random_suffix}" # Every bucket name must be globally unique + location = "US" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "object" { + name = "function-source.zip" + bucket = google_storage_bucket.bucket.name + source = "%{zip_path}" # Add path to the zipped function source code +} + +resource "google_cloudfunctions2_function" "function" { + name = "tf_test_synthetic_function%{random_suffix}" + location = "us-central1" + + build_config { + runtime = "nodejs16" + entry_point = "SyntheticFunction" # Set the entry point + source { + storage_source { + bucket = google_storage_bucket.bucket.name + object = google_storage_bucket_object.object.name + } + } + } + + service_config { + max_instance_count = 1 + available_memory = "256M" + timeout_seconds = 60 + } +} + +resource "google_monitoring_uptime_check_config" "synthetic_monitor" { + display_name = "tf_test_synthetic_monitor%{random_suffix}" + timeout = "60s" + + synthetic_monitor { + cloud_function_v2 { + name = google_cloudfunctions2_function.function.id + } + } +} +`, context) +} + func testAccCheckMonitoringUptimeCheckConfigDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/google/services/monitoring/test-fixtures/synthetic-fn-source.zip b/google/services/monitoring/test-fixtures/synthetic-fn-source.zip new file mode 100644 index 0000000000000000000000000000000000000000..fd79909197ab000a61bb0d6eb283a8b136ff9ccd GIT binary patch literal 2124 zcmai#c{tQ-AI5)UtO;X{Q0P$BEQRc*QPzXTj6*rLnZ_~O7Bw^@~CEJWGxhlJJ zgpe>~!dS=2da^HNiHYHz&iluybKd28{&=46Klk-q_w~K+kBtSGRR{n8PN0u8hBSwG z%=9oP1PB050uq3qtGl-=2Cd?C2j`2h;{w2pqfFFg>?|rMlp6rC7POrJSmDkfz$ZQ%G#CC}DA14bOl*)b+4{u2A8q8F%`!vX-9y%F6anNJ$1ILkPt};~Fb&~~ROj3^& zE65Wglo4ff4=3Csgte-=1JXdQSvOkDzr5bDA|Szv?r!ejikG98(jsda?NKk>$qO<; z7%Gy#BHq;EwM1P#zH{08bAAFlny%}(NA!={;k{pQmMfztVU5S;J2zDG9ZU0B0HBNw z0JxZL+%PeQS(&K#p#GN?DR!IIld2HL#;dvEs0o|=8wOUUnR048L?66MWUkyB?X1qU z@$_h$CeLGC%u61jw5F#wR#xd#Eg_rg@eera_)gd-Gq9Q9^IwQpIe8`bMTm#Li&6u7 z&=~0D5N|8n7bWx0n-<+{WJAG2q>r2|Kf=}XI#K(l>vnoQ6n@Y%CC+Lhp1YJrzI=S} z+T%kCqA6yTzt{z<6R)w}yrjc#p@w`U`xxqD#WyO-SH}JzHmBXk#)&P1Gd69HWZbrY(k z?jj80N|5iqf`{aNm>Itp)iyxSg1QH_cZp4%GpKwoW~TfcP6!W`i12T2Aa!$c=0&)Q z@ATOgJZsLO9oPu-<~wYXY#UP~jI?v@b5}I>?iI@*yo2X`;T)IDf)+zp8ExGbd0I~h zOUBL3EB-mPB86_8;^q$Q-LhUdlg6SVjdt@}B0C!FW09)nudXTuG(7bjkn4QA9p5@# zjJ>$VGUnXcZl)NRr~lGFY~URUrZ`^Z3RAFoB_DfxQAWZ+{)}^2vsR7pO>4AbV~JC) zSWhyt&3HJPqpe;pO`3dn6!WTUj$E5rbAi0>?L}z~aA#5eg)9-{=HE6>!drCQBe$aS zY`9^`QbeRArH$1v4mF?`sa5Wfj*vZjaa&KN!QZ*?$-^CYj#OT?F2%r~m+S8J-Tkm& ziHuNN3@cfCf`0(oMWSeW#Tdv|O)FaLePSKS@iyrAs)&FT%n%z#Rw+yl5^5r=9ioj2 zNf(ChM31;lBRK=79{cKMkClrW-beKscuV$+Synkx%MgH#HZ;TvmxKvjld=aFQJITh5pA{ zKf-_dbz#QJf&Z3%OE^0&U(q{m#7oT_9_50*M8mVeZWeJog)F2D9i9#@`^bM+mC}LO z5|R_}Q^PvlYK0`mKB%(is7jS$N1YUO!D#bDQO6;o+_d$_v*vBh>=O4f<&GX5*oOLcwx(Zs4d`lSO!n!3fmUAlPLOzbXlnYtseFE22H?xY*BSM8oUn`qNln zdIS-Uw#H-0`#}?80cGB&9_$FIPlnZZkJ1m+BCy(olFIGcQDN;>U@BnI((OFc51O98a31FT<`MOASeDnWkU5mcEvM ztDEAMwDu9cP+YL4Z7hB*PYE{YJM-b&n<^0S3;rsHJA-t|_Ut2@zhe0EUOM8{*iQz>bs8akX? zj-jQzyAMH3)vFgI?SXk;T@e>_Q)!aYjl^Zx(=tr_>m?QL22zteRySvAE z1BEsgAeJ-W{{~V~CQ<=_$yA^y=IiTwtg`(ZtA9i4-xa@y(YK1cOyO_P^#A4lnf-6& gHkgg@R}(PRzBa)>KF7xF3;+N#&nEM}&hd5n7m=s2=l}o! literal 0 HcmV?d00001 diff --git a/website/docs/r/monitoring_uptime_check_config.html.markdown b/website/docs/r/monitoring_uptime_check_config.html.markdown index 15ae959de49..ec1d8218689 100644 --- a/website/docs/r/monitoring_uptime_check_config.html.markdown +++ b/website/docs/r/monitoring_uptime_check_config.html.markdown @@ -175,6 +175,55 @@ resource "google_monitoring_group" "check" { filter = "resource.metadata.name=has_substring(\"foo\")" } ``` +## Example Usage - Uptime Check Config Synthetic Monitor + + +```hcl +resource "google_storage_bucket" "bucket" { + name = "my-project-name-gcf-source" # Every bucket name must be globally unique + location = "US" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "object" { + name = "function-source.zip" + bucket = google_storage_bucket.bucket.name + source = "synthetic-fn-source.zip" # Add path to the zipped function source code +} + +resource "google_cloudfunctions2_function" "function" { + name = "synthetic_function" + location = "us-central1" + + build_config { + runtime = "nodejs16" + entry_point = "SyntheticFunction" # Set the entry point + source { + storage_source { + bucket = google_storage_bucket.bucket.name + object = google_storage_bucket_object.object.name + } + } + } + + service_config { + max_instance_count = 1 + available_memory = "256M" + timeout_seconds = 60 + } +} + +resource "google_monitoring_uptime_check_config" "synthetic_monitor" { + display_name = "synthetic_monitor" + timeout = "60s" + + synthetic_monitor { + cloud_function_v2 { + name = google_cloudfunctions2_function.function.id + } + } +} +``` ## Argument Reference @@ -231,6 +280,11 @@ The following arguments are supported: The monitored resource (https://cloud.google.com/monitoring/api/resources) associated with the configuration. The following monitored resource types are supported for uptime checks: uptime_url gce_instance gae_app aws_ec2_instance aws_elb_load_balancer k8s_service servicedirectory_service Structure is [documented below](#nested_monitored_resource). +* `synthetic_monitor` - + (Optional) + A Synthetic Monitor deployed to a Cloud Functions V2 instance. + Structure is [documented below](#nested_synthetic_monitor). + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. @@ -366,6 +420,20 @@ The following arguments are supported: (Required) Values for all of the labels listed in the associated monitored resource descriptor. For example, Compute Engine VM instances use the labels "project_id", "instance_id", and "zone". +The `synthetic_monitor` block supports: + +* `cloud_function_v2` - + (Required) + Target a Synthetic Monitor GCFv2 Instance + Structure is [documented below](#nested_cloud_function_v2). + + +The `cloud_function_v2` block supports: + +* `name` - + (Required) + The fully qualified name of the cloud function resource. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: