github.com/GoogleCloudPlatform/terraformer@v0.8.18/providers/gcp/gke.go (about) 1 // Copyright 2018 The Terraformer Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gcp 16 17 import ( 18 "context" 19 "fmt" 20 "log" 21 "strconv" 22 23 "github.com/GoogleCloudPlatform/terraformer/terraformutils" 24 25 container "google.golang.org/api/container/v1beta1" 26 ) 27 28 var GkeAllowEmptyValues = []string{"labels."} 29 30 var GkeAdditionalFields = map[string]interface{}{} 31 32 type GkeGenerator struct { 33 GCPService 34 } 35 36 func (g *GkeGenerator) initClusters(clusters *container.ListClustersResponse) []terraformutils.Resource { 37 resources := []terraformutils.Resource{} 38 for _, cluster := range clusters.Clusters { 39 if _, exist := cluster.ResourceLabels["goog-composer-environment"]; exist { // don't manage composer clusters 40 continue 41 } 42 resource := terraformutils.NewResource( 43 cluster.Name, 44 cluster.Name, 45 "google_container_cluster", 46 g.ProviderName, 47 map[string]string{ 48 "name": cluster.Name, // provider need cluster name as Required 49 "project": g.GetArgs()["project"].(string), 50 "location": cluster.Location, 51 "zone": cluster.Zone, 52 }, 53 GkeAllowEmptyValues, 54 GkeAdditionalFields, 55 ) 56 resource.IgnoreKeys = append(resource.IgnoreKeys, 57 "^region$", 58 "^additional_zones\\.(.*)", 59 "^zone$", 60 "^node_pool\\.(.*)", // delete node_pool config from google_container_cluster 61 "^node_config\\.(.*)", // delete node_config config from google_container_cluster 62 "^ip_allocation_policy\\.[0-9]\\.cluster_secondary_range_name$", // conflict with cluster_ipv4_cidr_block 63 "^ip_allocation_policy\\.[0-9]\\.services_secondary_range_name$", // conflict with services_ipv4_cidr_block 64 "^ip_allocation_policy\\.[0-9]\\.create_subnetwork") // only for create new cluster conflict with others ip_allocation_policy fields 65 resources = append(resources, resource) 66 resources = append(resources, g.initNodePools(cluster.NodePools, cluster.Name, cluster.Location)...) 67 } 68 return resources 69 } 70 71 func (g *GkeGenerator) initNodePools(nodePools []*container.NodePool, clusterName, location string) []terraformutils.Resource { 72 resources := []terraformutils.Resource{} 73 for _, nodePool := range nodePools { 74 resources = append(resources, terraformutils.NewResource( 75 fmt.Sprintf("%s/%s/%s", location, clusterName, nodePool.Name), 76 clusterName+"_"+nodePool.Name, 77 "google_container_node_pool", 78 g.ProviderName, 79 map[string]string{ 80 "location": location, 81 "zone": location, 82 "project": g.GetArgs()["project"].(string), 83 "cluster": clusterName, // provider need cluster name as Required 84 "name": nodePool.Name, 85 }, 86 GkeAllowEmptyValues, 87 GkeAdditionalFields, 88 )) 89 } 90 return resources 91 } 92 93 // Generate TerraformResources from GCP API, 94 func (g *GkeGenerator) InitResources() error { 95 ctx := context.Background() 96 service, err := container.NewService(ctx) 97 if err != nil { 98 log.Print(err) 99 return err 100 } 101 // GKE support zone and regional cluster, api use location, it's can be region or zone, for all "-" 102 location := fmt.Sprintf("projects/%s/locations/%s", g.GetArgs()["project"].(string), "-") 103 clusters, err := service.Projects.Locations.Clusters.List(location).Do() 104 if err != nil { 105 log.Print(err) 106 return err 107 } 108 109 g.Resources = g.initClusters(clusters) 110 return nil 111 } 112 113 func (g *GkeGenerator) PostConvertHook() error { 114 for i, r := range g.Resources { 115 if r.InstanceInfo.Type != "google_container_node_pool" { 116 continue 117 } 118 if _, existNodeConfig := g.Resources[i].Item["node_config"]; existNodeConfig { 119 if _, existMetadata := g.Resources[i].Item["node_config"].([]interface{})[0].(map[string]interface{})["metadata"]; existMetadata { 120 for k, v := range g.Resources[i].Item["node_config"].([]interface{})[0].(map[string]interface{})["metadata"].(map[string]interface{}) { 121 switch x := v.(type) { 122 case bool: 123 g.Resources[i].Item["node_config"].([]interface{})[0].(map[string]interface{})["metadata"].(map[string]interface{})[k] = strconv.FormatBool(x) 124 default: 125 } 126 } 127 } 128 } 129 for _, cluster := range g.Resources { 130 if cluster.InstanceState.Attributes["name"] == r.InstanceState.Attributes["cluster"] { 131 g.Resources[i].Item["cluster"] = "${google_container_cluster." + cluster.ResourceName + ".name}" 132 } 133 } 134 } 135 136 // hacks for fix GCP API<=>provider<=>parser inconsistency 137 for i, r := range g.Resources { 138 if r.InstanceInfo.Type != "google_container_cluster" { 139 continue 140 } 141 if r.Item["master_authorized_networks_config"] != nil { 142 if len(r.Item["master_authorized_networks_config"].([]interface{})) == 0 { 143 g.Resources[i].Item["master_authorized_networks_config"] = map[string]interface{}{} 144 } 145 } 146 if r.Item["ip_allocation_policy"] != nil { 147 if len(r.Item["ip_allocation_policy"].([]interface{})) == 0 { 148 g.Resources[i].Item["ip_allocation_policy"] = map[string]interface{}{} 149 } 150 } 151 } 152 return nil 153 }