596 lines
17 KiB
Go
596 lines
17 KiB
Go
package google
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"strconv"
|
|
|
|
"github.com/hashicorp/terraform/helper/acctest"
|
|
"github.com/hashicorp/terraform/helper/resource"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
)
|
|
|
|
func TestAccContainerCluster_basic(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_basic,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.primary"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withAdditionalZones(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withAdditionalZones,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_additional_zones"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withVersion(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withVersion,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_version"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withNodeConfig(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withNodeConfig,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_node_config"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withNodeConfigScopeAlias(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withNodeConfigScopeAlias,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_node_config_scope_alias"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_network(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_networkRef,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_net_ref_by_url"),
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_net_ref_by_name"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_backend(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_backendRef,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.primary"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withNodePoolBasic(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withNodePoolBasic,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_node_pool"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withNodePoolNamePrefix(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withNodePoolNamePrefix,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_node_pool_name_prefix"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestAccContainerCluster_withNodePoolMultiple(t *testing.T) {
|
|
resource.Test(t, resource.TestCase{
|
|
PreCheck: func() { testAccPreCheck(t) },
|
|
Providers: testAccProviders,
|
|
CheckDestroy: testAccCheckContainerClusterDestroy,
|
|
Steps: []resource.TestStep{
|
|
resource.TestStep{
|
|
Config: testAccContainerCluster_withNodePoolMultiple,
|
|
Check: resource.ComposeTestCheckFunc(
|
|
testAccCheckContainerCluster(
|
|
"google_container_cluster.with_node_pool_multiple"),
|
|
),
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func testAccCheckContainerClusterDestroy(s *terraform.State) error {
|
|
config := testAccProvider.Meta().(*Config)
|
|
|
|
for _, rs := range s.RootModule().Resources {
|
|
if rs.Type != "google_container_cluster" {
|
|
continue
|
|
}
|
|
|
|
attributes := rs.Primary.Attributes
|
|
_, err := config.clientContainer.Projects.Zones.Clusters.Get(
|
|
config.Project, attributes["zone"], attributes["name"]).Do()
|
|
if err == nil {
|
|
return fmt.Errorf("Cluster still exists")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func testAccCheckContainerCluster(n string) resource.TestCheckFunc {
|
|
return func(s *terraform.State) error {
|
|
attributes, err := getResourceAttributes(n, s)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
config := testAccProvider.Meta().(*Config)
|
|
cluster, err := config.clientContainer.Projects.Zones.Clusters.Get(
|
|
config.Project, attributes["zone"], attributes["name"]).Do()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if cluster.Name != attributes["name"] {
|
|
return fmt.Errorf("Cluster %s not found, found %s instead", attributes["name"], cluster.Name)
|
|
}
|
|
|
|
type clusterTestField struct {
|
|
tf_attr string
|
|
gcp_attr interface{}
|
|
}
|
|
|
|
var igUrls []string
|
|
if igUrls, err = getInstanceGroupUrlsFromManagerUrls(config, cluster.InstanceGroupUrls); err != nil {
|
|
return err
|
|
}
|
|
clusterTests := []clusterTestField{
|
|
{"initial_node_count", strconv.FormatInt(cluster.InitialNodeCount, 10)},
|
|
{"master_auth.0.client_certificate", cluster.MasterAuth.ClientCertificate},
|
|
{"master_auth.0.client_key", cluster.MasterAuth.ClientKey},
|
|
{"master_auth.0.cluster_ca_certificate", cluster.MasterAuth.ClusterCaCertificate},
|
|
{"master_auth.0.password", cluster.MasterAuth.Password},
|
|
{"master_auth.0.username", cluster.MasterAuth.Username},
|
|
{"zone", cluster.Zone},
|
|
{"cluster_ipv4_cidr", cluster.ClusterIpv4Cidr},
|
|
{"description", cluster.Description},
|
|
{"endpoint", cluster.Endpoint},
|
|
{"instance_group_urls", igUrls},
|
|
{"logging_service", cluster.LoggingService},
|
|
{"monitoring_service", cluster.MonitoringService},
|
|
{"subnetwork", cluster.Subnetwork},
|
|
{"node_config.0.machine_type", cluster.NodeConfig.MachineType},
|
|
{"node_config.0.disk_size_gb", strconv.FormatInt(cluster.NodeConfig.DiskSizeGb, 10)},
|
|
{"node_config.0.local_ssd_count", strconv.FormatInt(cluster.NodeConfig.LocalSsdCount, 10)},
|
|
{"node_config.0.oauth_scopes", cluster.NodeConfig.OauthScopes},
|
|
{"node_config.0.service_account", cluster.NodeConfig.ServiceAccount},
|
|
{"node_config.0.metadata", cluster.NodeConfig.Metadata},
|
|
{"node_config.0.image_type", cluster.NodeConfig.ImageType},
|
|
{"node_version", cluster.CurrentNodeVersion},
|
|
}
|
|
|
|
// Remove Zone from additional_zones since that's what the resource writes in state
|
|
additionalZones := []string{}
|
|
for _, location := range cluster.Locations {
|
|
if location != cluster.Zone {
|
|
additionalZones = append(additionalZones, location)
|
|
}
|
|
}
|
|
clusterTests = append(clusterTests, clusterTestField{"additional_zones", additionalZones})
|
|
|
|
// AddonsConfig is neither Required or Computed, so the API may return nil for it
|
|
if cluster.AddonsConfig != nil {
|
|
if cluster.AddonsConfig.HttpLoadBalancing != nil {
|
|
clusterTests = append(clusterTests, clusterTestField{"addons_config.0.http_load_balancing.0.disabled", strconv.FormatBool(cluster.AddonsConfig.HttpLoadBalancing.Disabled)})
|
|
}
|
|
if cluster.AddonsConfig.HorizontalPodAutoscaling != nil {
|
|
clusterTests = append(clusterTests, clusterTestField{"addons_config.0.horizontal_pod_autoscaling.0.disabled", strconv.FormatBool(cluster.AddonsConfig.HorizontalPodAutoscaling.Disabled)})
|
|
}
|
|
}
|
|
|
|
for i, np := range cluster.NodePools {
|
|
prefix := fmt.Sprintf("node_pool.%d.", i)
|
|
clusterTests = append(clusterTests,
|
|
clusterTestField{prefix + "name", np.Name},
|
|
clusterTestField{prefix + "initial_node_count", strconv.FormatInt(np.InitialNodeCount, 10)})
|
|
}
|
|
|
|
for _, attrs := range clusterTests {
|
|
if c := checkMatch(attributes, attrs.tf_attr, attrs.gcp_attr); c != "" {
|
|
return fmt.Errorf(c)
|
|
}
|
|
}
|
|
|
|
// Network has to be done separately in order to normalize the two values
|
|
tf, err := getNetworkNameFromSelfLink(attributes["network"])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
gcp, err := getNetworkNameFromSelfLink(cluster.Network)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if tf != gcp {
|
|
return fmt.Errorf(matchError("network", tf, gcp))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func getResourceAttributes(n string, s *terraform.State) (map[string]string, error) {
|
|
rs, ok := s.RootModule().Resources[n]
|
|
if !ok {
|
|
return nil, fmt.Errorf("Not found: %s", n)
|
|
}
|
|
|
|
if rs.Primary.ID == "" {
|
|
return nil, fmt.Errorf("No ID is set")
|
|
}
|
|
|
|
return rs.Primary.Attributes, nil
|
|
}
|
|
|
|
func checkMatch(attributes map[string]string, attr string, gcp interface{}) string {
|
|
if gcpList, ok := gcp.([]string); ok {
|
|
return checkListMatch(attributes, attr, gcpList)
|
|
}
|
|
if gcpMap, ok := gcp.(map[string]string); ok {
|
|
return checkMapMatch(attributes, attr, gcpMap)
|
|
}
|
|
tf := attributes[attr]
|
|
if tf != gcp {
|
|
return matchError(attr, tf, gcp)
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func checkListMatch(attributes map[string]string, attr string, gcpList []string) string {
|
|
num, err := strconv.Atoi(attributes[attr+".#"])
|
|
if err != nil {
|
|
return fmt.Sprintf("Error in number conversion for attribute %s: %s", attr, err)
|
|
}
|
|
if num != len(gcpList) {
|
|
return fmt.Sprintf("Cluster has mismatched %s size.\nTF Size: %d\nGCP Size: %d", attr, num, len(gcpList))
|
|
}
|
|
|
|
for i, gcp := range gcpList {
|
|
if tf := attributes[fmt.Sprintf("%s.%d", attr, i)]; tf != gcp {
|
|
return matchError(fmt.Sprintf("%s[%d]", attr, i), tf, gcp)
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func checkMapMatch(attributes map[string]string, attr string, gcpMap map[string]string) string {
|
|
num, err := strconv.Atoi(attributes[attr+".%"])
|
|
if err != nil {
|
|
return fmt.Sprintf("Error in number conversion for attribute %s: %s", attr, err)
|
|
}
|
|
if num != len(gcpMap) {
|
|
return fmt.Sprintf("Cluster has mismatched %s size.\nTF Size: %d\nGCP Size: %d", attr, num, len(gcpMap))
|
|
}
|
|
|
|
for k, gcp := range gcpMap {
|
|
if tf := attributes[fmt.Sprintf("%s.%s", attr, k)]; tf != gcp {
|
|
return matchError(fmt.Sprintf("%s[%s]", attr, k), tf, gcp)
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func matchError(attr, tf string, gcp interface{}) string {
|
|
return fmt.Sprintf("Cluster has mismatched %s.\nTF State: %+v\nGCP State: %+v", attr, tf, gcp)
|
|
}
|
|
|
|
var testAccContainerCluster_basic = fmt.Sprintf(`
|
|
resource "google_container_cluster" "primary" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-a"
|
|
initial_node_count = 3
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withAdditionalZones = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_additional_zones" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-a"
|
|
initial_node_count = 1
|
|
|
|
additional_zones = [
|
|
"us-central1-b",
|
|
"us-central1-c"
|
|
]
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withVersion = fmt.Sprintf(`
|
|
data "google_container_versions" "central1a" {
|
|
zone = "us-central1-a"
|
|
}
|
|
|
|
resource "google_container_cluster" "with_version" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-a"
|
|
node_version = "${data.google_container_versions.central1a.latest_node_version}"
|
|
initial_node_count = 1
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withNodeConfig = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_node_config" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-f"
|
|
initial_node_count = 1
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_config {
|
|
machine_type = "n1-standard-1"
|
|
disk_size_gb = 15
|
|
local_ssd_count = 1
|
|
oauth_scopes = [
|
|
"https://www.googleapis.com/auth/compute",
|
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
|
"https://www.googleapis.com/auth/logging.write",
|
|
"https://www.googleapis.com/auth/monitoring"
|
|
]
|
|
service_account = "default"
|
|
metadata {
|
|
foo = "bar"
|
|
}
|
|
image_type = "CONTAINER_VM"
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withNodeConfigScopeAlias = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_node_config_scope_alias" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-f"
|
|
initial_node_count = 1
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_config {
|
|
machine_type = "g1-small"
|
|
disk_size_gb = 15
|
|
oauth_scopes = [ "compute-rw", "storage-ro", "logging-write", "monitoring" ]
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_networkRef = fmt.Sprintf(`
|
|
resource "google_compute_network" "container_network" {
|
|
name = "container-net-%s"
|
|
auto_create_subnetworks = true
|
|
}
|
|
|
|
resource "google_container_cluster" "with_net_ref_by_url" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-a"
|
|
initial_node_count = 1
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
network = "${google_compute_network.container_network.self_link}"
|
|
}
|
|
|
|
resource "google_container_cluster" "with_net_ref_by_name" {
|
|
name = "cluster-test-%s"
|
|
zone = "us-central1-a"
|
|
initial_node_count = 1
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
network = "${google_compute_network.container_network.name}"
|
|
}`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_backendRef = fmt.Sprintf(`
|
|
resource "google_compute_backend_service" "my-backend-service" {
|
|
name = "terraform-test-%s"
|
|
port_name = "http"
|
|
protocol = "HTTP"
|
|
|
|
backend {
|
|
group = "${element(google_container_cluster.primary.instance_group_urls, 1)}"
|
|
}
|
|
|
|
health_checks = ["${google_compute_http_health_check.default.self_link}"]
|
|
}
|
|
|
|
resource "google_compute_http_health_check" "default" {
|
|
name = "terraform-test-%s"
|
|
request_path = "/"
|
|
check_interval_sec = 1
|
|
timeout_sec = 1
|
|
}
|
|
|
|
resource "google_container_cluster" "primary" {
|
|
name = "terraform-test-%s"
|
|
zone = "us-central1-a"
|
|
initial_node_count = 3
|
|
|
|
additional_zones = [
|
|
"us-central1-b",
|
|
"us-central1-c",
|
|
]
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_config {
|
|
oauth_scopes = [
|
|
"https://www.googleapis.com/auth/compute",
|
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
|
"https://www.googleapis.com/auth/logging.write",
|
|
"https://www.googleapis.com/auth/monitoring",
|
|
]
|
|
}
|
|
}
|
|
`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withNodePoolBasic = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_node_pool" {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
zone = "us-central1-a"
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_pool {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
initial_node_count = 2
|
|
}
|
|
}`, acctest.RandString(10), acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withNodePoolNamePrefix = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_node_pool_name_prefix" {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
zone = "us-central1-a"
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_pool {
|
|
name_prefix = "tf-np-test"
|
|
initial_node_count = 2
|
|
}
|
|
}`, acctest.RandString(10))
|
|
|
|
var testAccContainerCluster_withNodePoolMultiple = fmt.Sprintf(`
|
|
resource "google_container_cluster" "with_node_pool_multiple" {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
zone = "us-central1-a"
|
|
|
|
master_auth {
|
|
username = "mr.yoda"
|
|
password = "adoy.rm"
|
|
}
|
|
|
|
node_pool {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
initial_node_count = 2
|
|
}
|
|
|
|
node_pool {
|
|
name = "tf-cluster-nodepool-test-%s"
|
|
initial_node_count = 3
|
|
}
|
|
}`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10))
|