@@ -433,6 +433,286 @@ func TestAccComputeRegionBackendService_withLogConfig(t *testing.T) {
433433 })
434434}
435435
436+ func TestAccComputeRegionBackendService_zonalILB(t *testing.T) {
437+ t.Parallel()
438+
439+ serviceName := fmt.Sprintf("tf-test-ilb-bs-%s", acctest.RandString(t, 10))
440+ checkName := fmt.Sprintf("tf-test-ilb-hc-%s", acctest.RandString(t, 10))
441+ checkName2 := fmt.Sprintf("tf-test-ilb-hc2-%s", acctest.RandString(t, 10))
442+ negName := fmt.Sprintf("tf-test-ilb-neg-%s", acctest.RandString(t, 10))
443+ negName2 := fmt.Sprintf("tf-test-ilb-neg2-%s", acctest.RandString(t, 10))
444+ instanceName := fmt.Sprintf("tf-test-ilb-vm-%s", acctest.RandString(t, 10))
445+ instanceName2 := fmt.Sprintf("tf-test-ilb-vm2-%s", acctest.RandString(t, 10))
446+
447+ // subnetwork with random suffix
448+ subnetName := fmt.Sprintf("tf-test-subnet-%s", acctest.RandString(t, 8))
449+
450+ acctest.VcrTest(t, resource.TestCase{
451+ PreCheck: func() { acctest.AccTestPreCheck(t) },
452+ ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
453+ CheckDestroy: testAccCheckComputeRegionBackendServiceDestroyProducer(t),
454+ Steps: []resource.TestStep{
455+ // STEP 1: base (self-link v1)
456+ {
457+ Config: testAccComputeRegionBackendService_zonalILB_withGroup(
458+ testAccComputeRegionBackendService_common(checkName, negName, instanceName, subnetName),
459+ serviceName,
460+ "google_compute_network_endpoint_group.neg.id",
461+ ),
462+ },
463+ {
464+ ResourceName: "google_compute_region_backend_service.default",
465+ ImportState: true,
466+ ImportStateVerify: true,
467+ },
468+
469+ // STEP 2: same NEG with /compute/beta/ (apply OK)
470+ {
471+ Config: fmt.Sprintf(`
472+ %s
473+
474+ locals {
475+ neg_beta = replace(google_compute_network_endpoint_group.neg.id, "/compute/v1/", "/compute/beta/")
476+ }
477+
478+ %s
479+ `, testAccComputeRegionBackendService_common(checkName, negName, instanceName, subnetName),
480+ testAccComputeRegionBackendService_zonalILB_withGroup("", serviceName, "local.neg_beta"),
481+ ),
482+ },
483+ {
484+ ResourceName: "google_compute_region_backend_service.default",
485+ ImportState: true,
486+ ImportStateVerify: true,
487+ },
488+
489+ // STEP 3: Invalid variation for API (UPPERCASE + "/") — tested only in PLAN
490+ {
491+ PlanOnly: true, // does not call the API; only exercises diff/canonicalization
492+ Config: fmt.Sprintf(`
493+ %s
494+
495+ locals {
496+ neg_slash_upper = "${google_compute_network_endpoint_group.neg.id}"
497+ }
498+
499+ %s
500+ `, testAccComputeRegionBackendService_common(checkName, negName, instanceName, subnetName),
501+ testAccComputeRegionBackendService_zonalILB_withGroup("", serviceName, "local.neg_slash_upper"),
502+ ),
503+ },
504+
505+ // STEP 4: Modified scenario (changes NEG/HC/VM) — continues validating real updates
506+ {
507+ Config: testAccComputeRegionBackendService_zonalILBModified(serviceName, checkName, negName, instanceName, checkName2, negName2, instanceName2, subnetName),
508+ },
509+ {
510+ ResourceName: "google_compute_region_backend_service.default",
511+ ImportState: true,
512+ ImportStateVerify: true,
513+ },
514+ },
515+ })
516+ }
517+
518+ func testAccComputeRegionBackendService_common(checkName, negName, instanceName, subnetworkName string) string {
519+ return fmt.Sprintf(`
520+ resource "google_compute_network" "default" {
521+ name = "tf-test-net"
522+ auto_create_subnetworks = false
523+ }
524+
525+ resource "google_compute_subnetwork" "default" {
526+ name = "%s"
527+ ip_cidr_range = "10.10.0.0/16"
528+ region = "us-central1"
529+ network = google_compute_network.default.id
530+ }
531+
532+ resource "google_compute_region_health_check" "hc1" {
533+ name = "%s"
534+ region = "us-central1"
535+ http_health_check {
536+ port = 8080
537+ request_path = "/status"
538+ }
539+ }
540+
541+ resource "google_compute_instance" "default" {
542+ name = "%s"
543+ zone = "us-central1-a"
544+ machine_type = "e2-micro"
545+
546+ boot_disk {
547+ initialize_params {
548+ image = "debian-cloud/debian-11"
549+ }
550+ }
551+
552+ network_interface {
553+ network = google_compute_network.default.id
554+ subnetwork = google_compute_subnetwork.default.id
555+ access_config {}
556+ }
557+ }
558+
559+ resource "google_compute_network_endpoint_group" "neg" {
560+ name = "%s"
561+ network = google_compute_network.default.id
562+ subnetwork = google_compute_subnetwork.default.id
563+ zone = "us-central1-a"
564+ network_endpoint_type = "GCE_VM_IP_PORT"
565+ }
566+
567+ resource "google_compute_network_endpoint" "endpoint" {
568+ network_endpoint_group = google_compute_network_endpoint_group.neg.name
569+ zone = "us-central1-a"
570+ instance = google_compute_instance.default.name
571+ ip_address = google_compute_instance.default.network_interface[0].network_ip
572+ port = 8080
573+ }
574+ `, subnetworkName, checkName, instanceName, negName)
575+ }
576+
577+ func testAccComputeRegionBackendService_zonalILB_withGroup(commonHCL string, serviceName string, groupExpr string) string {
578+ header := commonHCL
579+ return fmt.Sprintf(`
580+ %s
581+ resource "google_compute_region_backend_service" "default" {
582+ name = "%s"
583+ region = "us-central1"
584+ protocol = "HTTP"
585+ load_balancing_scheme = "INTERNAL_MANAGED"
586+ health_checks = [google_compute_region_health_check.hc1.id]
587+
588+ backend {
589+ group = %s
590+ balancing_mode = "RATE"
591+ max_rate_per_endpoint = 100
592+ capacity_scaler = 1.0
593+ }
594+
595+ session_affinity = "CLIENT_IP"
596+ locality_lb_policy = "ROUND_ROBIN"
597+ }
598+ `, header, serviceName, groupExpr)
599+ }
600+
601+ func testAccComputeRegionBackendService_zonalILBModified(serviceName, checkName, negName, instanceName, checkName2, negName2, instanceName2, subnetworkName string) string {
602+ return fmt.Sprintf(`
603+ resource "google_compute_network" "default" {
604+ name = "tf-test-net"
605+ auto_create_subnetworks = false
606+ }
607+
608+ resource "google_compute_subnetwork" "default" {
609+ name = "%s"
610+ ip_cidr_range = "10.10.0.0/16"
611+ region = "us-central1"
612+ network = google_compute_network.default.id
613+ }
614+
615+ resource "google_compute_region_health_check" "hc1" {
616+ name = "%s"
617+ region = "us-central1"
618+ http_health_check {
619+ port = 8080
620+ request_path = "/status"
621+ }
622+ }
623+
624+ resource "google_compute_instance" "default" {
625+ name = "%s"
626+ zone = "us-central1-a"
627+ machine_type = "e2-micro"
628+
629+ boot_disk {
630+ initialize_params {
631+ image = "debian-cloud/debian-11"
632+ }
633+ }
634+
635+ network_interface {
636+ network = google_compute_network.default.id
637+ subnetwork = google_compute_subnetwork.default.id
638+ access_config {}
639+ }
640+ }
641+
642+ resource "google_compute_network_endpoint_group" "neg" {
643+ name = "%s"
644+ network = google_compute_network.default.id
645+ subnetwork = google_compute_subnetwork.default.id
646+ zone = "us-central1-a"
647+ network_endpoint_type = "GCE_VM_IP_PORT"
648+ }
649+
650+ resource "google_compute_network_endpoint" "endpoint" {
651+ network_endpoint_group = google_compute_network_endpoint_group.neg.name
652+ zone = "us-central1-a"
653+ instance = google_compute_instance.default.name
654+ ip_address = google_compute_instance.default.network_interface[0].network_ip
655+ port = 8080
656+ }
657+
658+ resource "google_compute_instance" "instance2" {
659+ name = "%s"
660+ zone = "us-central1-a"
661+ machine_type = "e2-micro"
662+
663+ boot_disk {
664+ initialize_params {
665+ image = "debian-cloud/debian-11"
666+ }
667+ }
668+
669+ network_interface {
670+ network = google_compute_network.default.id
671+ subnetwork = google_compute_subnetwork.default.id
672+ access_config {}
673+ }
674+ }
675+
676+ resource "google_compute_region_health_check" "hc2" {
677+ name = "%s"
678+ region = "us-central1"
679+ http_health_check {
680+ port = 80
681+ }
682+ }
683+
684+ resource "google_compute_network_endpoint_group" "neg2" {
685+ name = "%s"
686+ network = google_compute_network.default.id
687+ subnetwork = google_compute_subnetwork.default.id
688+ zone = "us-central1-a"
689+ network_endpoint_type = "GCE_VM_IP_PORT"
690+ }
691+
692+ resource "google_compute_network_endpoint" "endpoint2" {
693+ network_endpoint_group = google_compute_network_endpoint_group.neg2.name
694+ zone = "us-central1-a"
695+ instance = google_compute_instance.instance2.name
696+ ip_address = google_compute_instance.instance2.network_interface[0].network_ip
697+ port = 8080
698+ }
699+
700+ resource "google_compute_region_backend_service" "default" {
701+ name = "%s"
702+ region = "us-central1"
703+ load_balancing_scheme = "INTERNAL_MANAGED"
704+ health_checks = [google_compute_region_health_check.hc2.id]
705+
706+ backend {
707+ group = google_compute_network_endpoint_group.neg2.id
708+ balancing_mode = "RATE"
709+ max_rate_per_endpoint = 200
710+ capacity_scaler = 0.5
711+ }
712+ }
713+ `, subnetworkName, checkName, instanceName, negName, instanceName2, checkName2, negName2, serviceName)
714+ }
715+
436716func TestAccComputeRegionBackendService_withDynamicBackendCount(t *testing.T) {
437717 t.Parallel()
438718
0 commit comments