github.com/bradfeehan/terraform@v0.7.0-rc3.0.20170529055808-34b45c5ad841/builtin/providers/google/resource_container_cluster_test.go (about)

     1  package google
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"strconv"
     8  
     9  	"github.com/hashicorp/terraform/helper/acctest"
    10  	"github.com/hashicorp/terraform/helper/resource"
    11  	"github.com/hashicorp/terraform/terraform"
    12  )
    13  
    14  func TestAccContainerCluster_basic(t *testing.T) {
    15  	resource.Test(t, resource.TestCase{
    16  		PreCheck:     func() { testAccPreCheck(t) },
    17  		Providers:    testAccProviders,
    18  		CheckDestroy: testAccCheckContainerClusterDestroy,
    19  		Steps: []resource.TestStep{
    20  			resource.TestStep{
    21  				Config: testAccContainerCluster_basic,
    22  				Check: resource.ComposeTestCheckFunc(
    23  					testAccCheckContainerCluster(
    24  						"google_container_cluster.primary"),
    25  				),
    26  			},
    27  		},
    28  	})
    29  }
    30  
    31  func TestAccContainerCluster_withAdditionalZones(t *testing.T) {
    32  	resource.Test(t, resource.TestCase{
    33  		PreCheck:     func() { testAccPreCheck(t) },
    34  		Providers:    testAccProviders,
    35  		CheckDestroy: testAccCheckContainerClusterDestroy,
    36  		Steps: []resource.TestStep{
    37  			resource.TestStep{
    38  				Config: testAccContainerCluster_withAdditionalZones,
    39  				Check: resource.ComposeTestCheckFunc(
    40  					testAccCheckContainerCluster(
    41  						"google_container_cluster.with_additional_zones"),
    42  				),
    43  			},
    44  		},
    45  	})
    46  }
    47  
    48  func TestAccContainerCluster_withVersion(t *testing.T) {
    49  	resource.Test(t, resource.TestCase{
    50  		PreCheck:     func() { testAccPreCheck(t) },
    51  		Providers:    testAccProviders,
    52  		CheckDestroy: testAccCheckContainerClusterDestroy,
    53  		Steps: []resource.TestStep{
    54  			resource.TestStep{
    55  				Config: testAccContainerCluster_withVersion,
    56  				Check: resource.ComposeTestCheckFunc(
    57  					testAccCheckContainerCluster(
    58  						"google_container_cluster.with_version"),
    59  				),
    60  			},
    61  		},
    62  	})
    63  }
    64  
    65  func TestAccContainerCluster_withNodeConfig(t *testing.T) {
    66  	resource.Test(t, resource.TestCase{
    67  		PreCheck:     func() { testAccPreCheck(t) },
    68  		Providers:    testAccProviders,
    69  		CheckDestroy: testAccCheckContainerClusterDestroy,
    70  		Steps: []resource.TestStep{
    71  			resource.TestStep{
    72  				Config: testAccContainerCluster_withNodeConfig,
    73  				Check: resource.ComposeTestCheckFunc(
    74  					testAccCheckContainerCluster(
    75  						"google_container_cluster.with_node_config"),
    76  				),
    77  			},
    78  		},
    79  	})
    80  }
    81  
    82  func TestAccContainerCluster_withNodeConfigScopeAlias(t *testing.T) {
    83  	resource.Test(t, resource.TestCase{
    84  		PreCheck:     func() { testAccPreCheck(t) },
    85  		Providers:    testAccProviders,
    86  		CheckDestroy: testAccCheckContainerClusterDestroy,
    87  		Steps: []resource.TestStep{
    88  			resource.TestStep{
    89  				Config: testAccContainerCluster_withNodeConfigScopeAlias,
    90  				Check: resource.ComposeTestCheckFunc(
    91  					testAccCheckContainerCluster(
    92  						"google_container_cluster.with_node_config_scope_alias"),
    93  				),
    94  			},
    95  		},
    96  	})
    97  }
    98  
    99  func TestAccContainerCluster_network(t *testing.T) {
   100  	resource.Test(t, resource.TestCase{
   101  		PreCheck:     func() { testAccPreCheck(t) },
   102  		Providers:    testAccProviders,
   103  		CheckDestroy: testAccCheckContainerClusterDestroy,
   104  		Steps: []resource.TestStep{
   105  			resource.TestStep{
   106  				Config: testAccContainerCluster_networkRef,
   107  				Check: resource.ComposeTestCheckFunc(
   108  					testAccCheckContainerCluster(
   109  						"google_container_cluster.with_net_ref_by_url"),
   110  					testAccCheckContainerCluster(
   111  						"google_container_cluster.with_net_ref_by_name"),
   112  				),
   113  			},
   114  		},
   115  	})
   116  }
   117  
   118  func TestAccContainerCluster_backend(t *testing.T) {
   119  	resource.Test(t, resource.TestCase{
   120  		PreCheck:     func() { testAccPreCheck(t) },
   121  		Providers:    testAccProviders,
   122  		CheckDestroy: testAccCheckContainerClusterDestroy,
   123  		Steps: []resource.TestStep{
   124  			resource.TestStep{
   125  				Config: testAccContainerCluster_backendRef,
   126  				Check: resource.ComposeTestCheckFunc(
   127  					testAccCheckContainerCluster(
   128  						"google_container_cluster.primary"),
   129  				),
   130  			},
   131  		},
   132  	})
   133  }
   134  
   135  func TestAccContainerCluster_withNodePoolBasic(t *testing.T) {
   136  	resource.Test(t, resource.TestCase{
   137  		PreCheck:     func() { testAccPreCheck(t) },
   138  		Providers:    testAccProviders,
   139  		CheckDestroy: testAccCheckContainerClusterDestroy,
   140  		Steps: []resource.TestStep{
   141  			resource.TestStep{
   142  				Config: testAccContainerCluster_withNodePoolBasic,
   143  				Check: resource.ComposeTestCheckFunc(
   144  					testAccCheckContainerCluster(
   145  						"google_container_cluster.with_node_pool"),
   146  				),
   147  			},
   148  		},
   149  	})
   150  }
   151  
   152  func TestAccContainerCluster_withNodePoolNamePrefix(t *testing.T) {
   153  	resource.Test(t, resource.TestCase{
   154  		PreCheck:     func() { testAccPreCheck(t) },
   155  		Providers:    testAccProviders,
   156  		CheckDestroy: testAccCheckContainerClusterDestroy,
   157  		Steps: []resource.TestStep{
   158  			resource.TestStep{
   159  				Config: testAccContainerCluster_withNodePoolNamePrefix,
   160  				Check: resource.ComposeTestCheckFunc(
   161  					testAccCheckContainerCluster(
   162  						"google_container_cluster.with_node_pool_name_prefix"),
   163  				),
   164  			},
   165  		},
   166  	})
   167  }
   168  
   169  func TestAccContainerCluster_withNodePoolMultiple(t *testing.T) {
   170  	resource.Test(t, resource.TestCase{
   171  		PreCheck:     func() { testAccPreCheck(t) },
   172  		Providers:    testAccProviders,
   173  		CheckDestroy: testAccCheckContainerClusterDestroy,
   174  		Steps: []resource.TestStep{
   175  			resource.TestStep{
   176  				Config: testAccContainerCluster_withNodePoolMultiple,
   177  				Check: resource.ComposeTestCheckFunc(
   178  					testAccCheckContainerCluster(
   179  						"google_container_cluster.with_node_pool_multiple"),
   180  				),
   181  			},
   182  		},
   183  	})
   184  }
   185  
   186  func testAccCheckContainerClusterDestroy(s *terraform.State) error {
   187  	config := testAccProvider.Meta().(*Config)
   188  
   189  	for _, rs := range s.RootModule().Resources {
   190  		if rs.Type != "google_container_cluster" {
   191  			continue
   192  		}
   193  
   194  		attributes := rs.Primary.Attributes
   195  		_, err := config.clientContainer.Projects.Zones.Clusters.Get(
   196  			config.Project, attributes["zone"], attributes["name"]).Do()
   197  		if err == nil {
   198  			return fmt.Errorf("Cluster still exists")
   199  		}
   200  	}
   201  
   202  	return nil
   203  }
   204  
   205  func testAccCheckContainerCluster(n string) resource.TestCheckFunc {
   206  	return func(s *terraform.State) error {
   207  		attributes, err := getResourceAttributes(n, s)
   208  		if err != nil {
   209  			return err
   210  		}
   211  
   212  		config := testAccProvider.Meta().(*Config)
   213  		cluster, err := config.clientContainer.Projects.Zones.Clusters.Get(
   214  			config.Project, attributes["zone"], attributes["name"]).Do()
   215  		if err != nil {
   216  			return err
   217  		}
   218  
   219  		if cluster.Name != attributes["name"] {
   220  			return fmt.Errorf("Cluster %s not found, found %s instead", attributes["name"], cluster.Name)
   221  		}
   222  
   223  		type clusterTestField struct {
   224  			tf_attr  string
   225  			gcp_attr interface{}
   226  		}
   227  
   228  		var igUrls []string
   229  		if igUrls, err = getInstanceGroupUrlsFromManagerUrls(config, cluster.InstanceGroupUrls); err != nil {
   230  			return err
   231  		}
   232  		clusterTests := []clusterTestField{
   233  			{"initial_node_count", strconv.FormatInt(cluster.InitialNodeCount, 10)},
   234  			{"master_auth.0.client_certificate", cluster.MasterAuth.ClientCertificate},
   235  			{"master_auth.0.client_key", cluster.MasterAuth.ClientKey},
   236  			{"master_auth.0.cluster_ca_certificate", cluster.MasterAuth.ClusterCaCertificate},
   237  			{"master_auth.0.password", cluster.MasterAuth.Password},
   238  			{"master_auth.0.username", cluster.MasterAuth.Username},
   239  			{"zone", cluster.Zone},
   240  			{"cluster_ipv4_cidr", cluster.ClusterIpv4Cidr},
   241  			{"description", cluster.Description},
   242  			{"endpoint", cluster.Endpoint},
   243  			{"instance_group_urls", igUrls},
   244  			{"logging_service", cluster.LoggingService},
   245  			{"monitoring_service", cluster.MonitoringService},
   246  			{"subnetwork", cluster.Subnetwork},
   247  			{"node_config.0.machine_type", cluster.NodeConfig.MachineType},
   248  			{"node_config.0.disk_size_gb", strconv.FormatInt(cluster.NodeConfig.DiskSizeGb, 10)},
   249  			{"node_config.0.local_ssd_count", strconv.FormatInt(cluster.NodeConfig.LocalSsdCount, 10)},
   250  			{"node_config.0.oauth_scopes", cluster.NodeConfig.OauthScopes},
   251  			{"node_config.0.service_account", cluster.NodeConfig.ServiceAccount},
   252  			{"node_config.0.metadata", cluster.NodeConfig.Metadata},
   253  			{"node_config.0.image_type", cluster.NodeConfig.ImageType},
   254  			{"node_version", cluster.CurrentNodeVersion},
   255  		}
   256  
   257  		// Remove Zone from additional_zones since that's what the resource writes in state
   258  		additionalZones := []string{}
   259  		for _, location := range cluster.Locations {
   260  			if location != cluster.Zone {
   261  				additionalZones = append(additionalZones, location)
   262  			}
   263  		}
   264  		clusterTests = append(clusterTests, clusterTestField{"additional_zones", additionalZones})
   265  
   266  		// AddonsConfig is neither Required or Computed, so the API may return nil for it
   267  		if cluster.AddonsConfig != nil {
   268  			if cluster.AddonsConfig.HttpLoadBalancing != nil {
   269  				clusterTests = append(clusterTests, clusterTestField{"addons_config.0.http_load_balancing.0.disabled", strconv.FormatBool(cluster.AddonsConfig.HttpLoadBalancing.Disabled)})
   270  			}
   271  			if cluster.AddonsConfig.HorizontalPodAutoscaling != nil {
   272  				clusterTests = append(clusterTests, clusterTestField{"addons_config.0.horizontal_pod_autoscaling.0.disabled", strconv.FormatBool(cluster.AddonsConfig.HorizontalPodAutoscaling.Disabled)})
   273  			}
   274  		}
   275  
   276  		for i, np := range cluster.NodePools {
   277  			prefix := fmt.Sprintf("node_pool.%d.", i)
   278  			clusterTests = append(clusterTests,
   279  				clusterTestField{prefix + "name", np.Name},
   280  				clusterTestField{prefix + "initial_node_count", strconv.FormatInt(np.InitialNodeCount, 10)})
   281  		}
   282  
   283  		for _, attrs := range clusterTests {
   284  			if c := checkMatch(attributes, attrs.tf_attr, attrs.gcp_attr); c != "" {
   285  				return fmt.Errorf(c)
   286  			}
   287  		}
   288  
   289  		// Network has to be done separately in order to normalize the two values
   290  		tf, err := getNetworkNameFromSelfLink(attributes["network"])
   291  		if err != nil {
   292  			return err
   293  		}
   294  		gcp, err := getNetworkNameFromSelfLink(cluster.Network)
   295  		if err != nil {
   296  			return err
   297  		}
   298  		if tf != gcp {
   299  			return fmt.Errorf(matchError("network", tf, gcp))
   300  		}
   301  
   302  		return nil
   303  	}
   304  }
   305  
   306  func getResourceAttributes(n string, s *terraform.State) (map[string]string, error) {
   307  	rs, ok := s.RootModule().Resources[n]
   308  	if !ok {
   309  		return nil, fmt.Errorf("Not found: %s", n)
   310  	}
   311  
   312  	if rs.Primary.ID == "" {
   313  		return nil, fmt.Errorf("No ID is set")
   314  	}
   315  
   316  	return rs.Primary.Attributes, nil
   317  }
   318  
   319  func checkMatch(attributes map[string]string, attr string, gcp interface{}) string {
   320  	if gcpList, ok := gcp.([]string); ok {
   321  		return checkListMatch(attributes, attr, gcpList)
   322  	}
   323  	if gcpMap, ok := gcp.(map[string]string); ok {
   324  		return checkMapMatch(attributes, attr, gcpMap)
   325  	}
   326  	tf := attributes[attr]
   327  	if tf != gcp {
   328  		return matchError(attr, tf, gcp)
   329  	}
   330  	return ""
   331  }
   332  
   333  func checkListMatch(attributes map[string]string, attr string, gcpList []string) string {
   334  	num, err := strconv.Atoi(attributes[attr+".#"])
   335  	if err != nil {
   336  		return fmt.Sprintf("Error in number conversion for attribute %s: %s", attr, err)
   337  	}
   338  	if num != len(gcpList) {
   339  		return fmt.Sprintf("Cluster has mismatched %s size.\nTF Size: %d\nGCP Size: %d", attr, num, len(gcpList))
   340  	}
   341  
   342  	for i, gcp := range gcpList {
   343  		if tf := attributes[fmt.Sprintf("%s.%d", attr, i)]; tf != gcp {
   344  			return matchError(fmt.Sprintf("%s[%d]", attr, i), tf, gcp)
   345  		}
   346  	}
   347  
   348  	return ""
   349  }
   350  
   351  func checkMapMatch(attributes map[string]string, attr string, gcpMap map[string]string) string {
   352  	num, err := strconv.Atoi(attributes[attr+".%"])
   353  	if err != nil {
   354  		return fmt.Sprintf("Error in number conversion for attribute %s: %s", attr, err)
   355  	}
   356  	if num != len(gcpMap) {
   357  		return fmt.Sprintf("Cluster has mismatched %s size.\nTF Size: %d\nGCP Size: %d", attr, num, len(gcpMap))
   358  	}
   359  
   360  	for k, gcp := range gcpMap {
   361  		if tf := attributes[fmt.Sprintf("%s.%s", attr, k)]; tf != gcp {
   362  			return matchError(fmt.Sprintf("%s[%s]", attr, k), tf, gcp)
   363  		}
   364  	}
   365  
   366  	return ""
   367  }
   368  
   369  func matchError(attr, tf string, gcp interface{}) string {
   370  	return fmt.Sprintf("Cluster has mismatched %s.\nTF State: %+v\nGCP State: %+v", attr, tf, gcp)
   371  }
   372  
   373  var testAccContainerCluster_basic = fmt.Sprintf(`
   374  resource "google_container_cluster" "primary" {
   375  	name = "cluster-test-%s"
   376  	zone = "us-central1-a"
   377  	initial_node_count = 3
   378  
   379  	master_auth {
   380  		username = "mr.yoda"
   381  		password = "adoy.rm"
   382  	}
   383  }`, acctest.RandString(10))
   384  
   385  var testAccContainerCluster_withAdditionalZones = fmt.Sprintf(`
   386  resource "google_container_cluster" "with_additional_zones" {
   387  	name = "cluster-test-%s"
   388  	zone = "us-central1-a"
   389  	initial_node_count = 1
   390  
   391  	additional_zones = [
   392  		"us-central1-b",
   393  		"us-central1-c"
   394  	]
   395  
   396  	master_auth {
   397  		username = "mr.yoda"
   398  		password = "adoy.rm"
   399  	}
   400  }`, acctest.RandString(10))
   401  
   402  var testAccContainerCluster_withVersion = fmt.Sprintf(`
   403  data "google_container_engine_versions" "central1a" {
   404  	zone = "us-central1-a"
   405  }
   406  
   407  resource "google_container_cluster" "with_version" {
   408  	name = "cluster-test-%s"
   409  	zone = "us-central1-a"
   410  	node_version = "${data.google_container_engine_versions.central1a.latest_node_version}"
   411  	initial_node_count = 1
   412  
   413  	master_auth {
   414  		username = "mr.yoda"
   415  		password = "adoy.rm"
   416  	}
   417  }`, acctest.RandString(10))
   418  
   419  var testAccContainerCluster_withNodeConfig = fmt.Sprintf(`
   420  resource "google_container_cluster" "with_node_config" {
   421  	name = "cluster-test-%s"
   422  	zone = "us-central1-f"
   423  	initial_node_count = 1
   424  
   425  	master_auth {
   426  		username = "mr.yoda"
   427  		password = "adoy.rm"
   428  	}
   429  
   430  	node_config {
   431  		machine_type = "n1-standard-1"
   432  		disk_size_gb = 15
   433  		local_ssd_count = 1
   434  		oauth_scopes = [
   435  			"https://www.googleapis.com/auth/compute",
   436  			"https://www.googleapis.com/auth/devstorage.read_only",
   437  			"https://www.googleapis.com/auth/logging.write",
   438  			"https://www.googleapis.com/auth/monitoring"
   439  		]
   440  		service_account = "default"
   441  		metadata {
   442  			foo = "bar"
   443  		}
   444  		image_type = "CONTAINER_VM"
   445  	}
   446  }`, acctest.RandString(10))
   447  
   448  var testAccContainerCluster_withNodeConfigScopeAlias = fmt.Sprintf(`
   449  resource "google_container_cluster" "with_node_config_scope_alias" {
   450  	name = "cluster-test-%s"
   451  	zone = "us-central1-f"
   452  	initial_node_count = 1
   453  
   454  	master_auth {
   455  		username = "mr.yoda"
   456  		password = "adoy.rm"
   457  	}
   458  
   459  	node_config {
   460  		machine_type = "g1-small"
   461  		disk_size_gb = 15
   462  		oauth_scopes = [ "compute-rw", "storage-ro", "logging-write", "monitoring" ]
   463  	}
   464  }`, acctest.RandString(10))
   465  
   466  var testAccContainerCluster_networkRef = fmt.Sprintf(`
   467  resource "google_compute_network" "container_network" {
   468  	name = "container-net-%s"
   469  	auto_create_subnetworks = true
   470  }
   471  
   472  resource "google_container_cluster" "with_net_ref_by_url" {
   473  	name = "cluster-test-%s"
   474  	zone = "us-central1-a"
   475  	initial_node_count = 1
   476  
   477  	master_auth {
   478  		username = "mr.yoda"
   479  		password = "adoy.rm"
   480  	}
   481  
   482  	network = "${google_compute_network.container_network.self_link}"
   483  }
   484  
   485  resource "google_container_cluster" "with_net_ref_by_name" {
   486  	name = "cluster-test-%s"
   487  	zone = "us-central1-a"
   488  	initial_node_count = 1
   489  
   490  	master_auth {
   491  		username = "mr.yoda"
   492  		password = "adoy.rm"
   493  	}
   494  
   495  	network = "${google_compute_network.container_network.name}"
   496  }`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))
   497  
   498  var testAccContainerCluster_backendRef = fmt.Sprintf(`
   499  resource "google_compute_backend_service" "my-backend-service" {
   500    name      = "terraform-test-%s"
   501    port_name = "http"
   502    protocol  = "HTTP"
   503  
   504    backend {
   505      group = "${element(google_container_cluster.primary.instance_group_urls, 1)}"
   506    }
   507  
   508    health_checks = ["${google_compute_http_health_check.default.self_link}"]
   509  }
   510  
   511  resource "google_compute_http_health_check" "default" {
   512    name               = "terraform-test-%s"
   513    request_path       = "/"
   514    check_interval_sec = 1
   515    timeout_sec        = 1
   516  }
   517  
   518  resource "google_container_cluster" "primary" {
   519    name               = "terraform-test-%s"
   520    zone               = "us-central1-a"
   521    initial_node_count = 3
   522  
   523    additional_zones = [
   524      "us-central1-b",
   525      "us-central1-c",
   526    ]
   527  
   528    master_auth {
   529      username = "mr.yoda"
   530      password = "adoy.rm"
   531    }
   532  
   533    node_config {
   534      oauth_scopes = [
   535        "https://www.googleapis.com/auth/compute",
   536        "https://www.googleapis.com/auth/devstorage.read_only",
   537        "https://www.googleapis.com/auth/logging.write",
   538        "https://www.googleapis.com/auth/monitoring",
   539      ]
   540    }
   541  }
   542  `, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))
   543  
   544  var testAccContainerCluster_withNodePoolBasic = fmt.Sprintf(`
   545  resource "google_container_cluster" "with_node_pool" {
   546  	name = "tf-cluster-nodepool-test-%s"
   547  	zone = "us-central1-a"
   548  
   549  	master_auth {
   550  		username = "mr.yoda"
   551  		password = "adoy.rm"
   552  	}
   553  
   554  	node_pool {
   555  		name               = "tf-cluster-nodepool-test-%s"
   556  		initial_node_count = 2
   557  	}
   558  }`, acctest.RandString(10), acctest.RandString(10))
   559  
   560  var testAccContainerCluster_withNodePoolNamePrefix = fmt.Sprintf(`
   561  resource "google_container_cluster" "with_node_pool_name_prefix" {
   562  	name = "tf-cluster-nodepool-test-%s"
   563  	zone = "us-central1-a"
   564  
   565  	master_auth {
   566  		username = "mr.yoda"
   567  		password = "adoy.rm"
   568  	}
   569  
   570  	node_pool {
   571  		name_prefix        = "tf-np-test"
   572  		initial_node_count = 2
   573  	}
   574  }`, acctest.RandString(10))
   575  
   576  var testAccContainerCluster_withNodePoolMultiple = fmt.Sprintf(`
   577  resource "google_container_cluster" "with_node_pool_multiple" {
   578  	name = "tf-cluster-nodepool-test-%s"
   579  	zone = "us-central1-a"
   580  
   581  	master_auth {
   582  		username = "mr.yoda"
   583  		password = "adoy.rm"
   584  	}
   585  
   586  	node_pool {
   587  		name               = "tf-cluster-nodepool-test-%s"
   588  		initial_node_count = 2
   589  	}
   590  
   591  	node_pool {
   592  		name               = "tf-cluster-nodepool-test-%s"
   593  		initial_node_count = 3
   594  	}
   595  }`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))