providers/ibm/satellite_data_plane.go (295 lines of code) (raw):

// Copyright 2019 The Terraformer Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package ibm import ( "fmt" "log" "os" "reflect" "strings" "github.com/GoogleCloudPlatform/terraformer/terraformutils" bluemix "github.com/IBM-Cloud/bluemix-go" "github.com/IBM-Cloud/bluemix-go/session" "github.com/IBM/go-sdk-core/v3/core" "github.com/IBM/vpc-go-sdk/vpcv1" ) type SatelliteDataPlaneGenerator struct { IBMService } func (g SatelliteDataPlaneGenerator) loadVPCResources(vpcID, vpcName string) terraformutils.Resource { resource := terraformutils.NewResource( vpcID, vpcName, "ibm_is_vpc", "ibm", map[string]string{ "address_prefix_management": "auto", }, []string{}, map[string]interface{}{}) return resource } func (g SatelliteDataPlaneGenerator) loadInstanceResources(instance vpcv1.Instance, dependsOn []string) terraformutils.Resource { resource := terraformutils.NewResource( *instance.ID, *instance.Name, "ibm_is_instance", "ibm", map[string]string{ "vpc": *instance.VPC.ID, "wait_before_delete": "true", }, []string{}, map[string]interface{}{ "depends_on": dependsOn, "keys": []string{}, }) resource.IgnoreKeys = append(resource.IgnoreKeys, "^port_speed$", "^primary_network_interface.[0-9].primary_ip.[0-9].address$", "^primary_network_interface.[0-9].primary_ip.[0-9].reserved_ip$", ) return resource } func (g SatelliteDataPlaneGenerator) loadFloatingIPResources(floatingIPId, floatingIPName string) terraformutils.Resource { resource := terraformutils.NewResource( floatingIPId, floatingIPName, "ibm_is_floating_ip", "ibm", map[string]string{}, []string{}, map[string]interface{}{}) // Conflicts with proxied attribute resource.IgnoreKeys = append(resource.IgnoreKeys, "^zone$", ) return resource } func (g SatelliteDataPlaneGenerator) loadSecurityGroupResources(sgID, sgName string) terraformutils.Resource { resource := terraformutils.NewResource( sgID, sgName, "ibm_is_security_group", "ibm", map[string]string{}, []string{}, map[string]interface{}{}) return resource } func (g SatelliteDataPlaneGenerator) loadSecurityGroupRuleResources(sgID, sgRuleID string, dependsOn []string) terraformutils.Resource { resources := terraformutils.NewResource( fmt.Sprintf("%s.%s", sgID, sgRuleID), sgRuleID, "ibm_is_security_group_rule", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) return resources } func (g SatelliteDataPlaneGenerator) loadSubnetResources(subnetID, subnetName string, dependsOn []string) terraformutils.Resource { resource := terraformutils.NewResource( subnetID, subnetName, "ibm_is_subnet", "ibm", map[string]string{}, []string{}, map[string]interface{}{ "depends_on": dependsOn, }) // Conflicts with proxied attribute resource.IgnoreKeys = append(resource.IgnoreKeys, "^total_ipv4_address_count$", ) return resource } func contructEndpoint(subdomain, domain string) string { endpoint := fmt.Sprintf("https://%s.%s", subdomain, domain) return endpoint } func vpcClient(region string, sess *session.Session) (*vpcv1.VpcV1, error) { var cloudEndpoint = "cloud.ibm.com" bluemixToken := "" if strings.HasPrefix(sess.Config.IAMAccessToken, "Bearer") { bluemixToken = sess.Config.IAMAccessToken[7:len(sess.Config.IAMAccessToken)] } else { bluemixToken = sess.Config.IAMAccessToken } vpcurl := contructEndpoint(fmt.Sprintf("%s.iaas", region), fmt.Sprintf("%s/v1", cloudEndpoint)) // if sess.Config.Visibility == "private" { // if region == "us-south" || region == "us-east" { // vpcurl = contructEndpoint(fmt.Sprintf("%s.private.iaas", region), fmt.Sprintf("%s/v1", cloudEndpoint)) // } else { // return nil, fmt.Errorf("VPC supports private endpoints only in us-south and us-east") // } // } // if sess.Config.Visibility == "public-and-private" { // if region == "us-south" || region == "us-east" { // vpcurl = contructEndpoint(fmt.Sprintf("%s.private.iaas", region), fmt.Sprintf("%s/v1", cloudEndpoint)) // } // vpcurl = contructEndpoint(fmt.Sprintf("%s.iaas", region), fmt.Sprintf("%s/v1", cloudEndpoint)) // } vpcoptions := &vpcv1.VpcV1Options{ URL: envFallBack([]string{"IBMCLOUD_IS_NG_API_ENDPOINT"}, vpcurl), Authenticator: &core.BearerTokenAuthenticator{ BearerToken: bluemixToken, }, } vpcclient, err := vpcv1.NewVpcV1(vpcoptions) if err != nil { return nil, fmt.Errorf("Error occured while configuring vpc service: %v ", err) } return vpcclient, nil } func (g *SatelliteDataPlaneGenerator) InitResources() error { vpcName := g.Args["vpc"].(string) if len(vpcName) == 0 { return fmt.Errorf("required VPC name missing, '-vpc=<vpcName>' flag not set") } region := g.Args["region"].(string) bmxConfig := &bluemix.Config{ BluemixAPIKey: os.Getenv("IC_API_KEY"), } sess, err := session.New(bmxConfig) if err != nil { return err } err = authenticateAPIKey(sess) if err != nil { return err } // VPC vpcObj, err := vpcClient(region, sess) if err != nil { log.Println("Error building VPC object: ", err) return err } start := "" allVPCrecs := []vpcv1.VPC{} for { listVpcsOptions := &vpcv1.ListVpcsOptions{} if start != "" { listVpcsOptions.Start = &start } vpcs, response, err := vpcObj.ListVpcs(listVpcsOptions) if err != nil { return fmt.Errorf("Error Fetching vpcs %s\n%s", err, response) } start = GetNext(vpcs.Next) allVPCrecs = append(allVPCrecs, vpcs.Vpcs...) if start == "" { break } } // VPC & Instances for _, vpc := range allVPCrecs { if *vpc.Name == vpcName { var vpcDependsOn []string vpcDependsOn = append(vpcDependsOn, "ibm_is_vpc."+terraformutils.TfSanitize(*vpc.Name)) g.Resources = append(g.Resources, g.loadVPCResources(*vpc.ID, *vpc.Name)) start = "" var allrecs []vpcv1.Instance for { options := &vpcv1.ListInstancesOptions{} if start != "" { options.Start = &start } instances, response, err := vpcObj.ListInstances(options) if err != nil { return fmt.Errorf("Error Fetching Instances %s\n%s", err, response) } start = GetNext(instances.Next) allrecs = append(allrecs, instances.Instances...) if start == "" { break } } // Floating IP start := "" allFloatingIPs := []vpcv1.FloatingIP{} for { floatingIPOptions := &vpcv1.ListFloatingIpsOptions{} if start != "" { floatingIPOptions.Start = &start } floatingIPs, response, err := vpcObj.ListFloatingIps(floatingIPOptions) if err != nil { return fmt.Errorf("Error Fetching floating IPs %s\n%s", err, response) } start = GetNext(floatingIPs.Next) allFloatingIPs = append(allFloatingIPs, floatingIPs.FloatingIps...) if start == "" { break } } for _, instance := range allrecs { g.Resources = append(g.Resources, g.loadInstanceResources(instance, vpcDependsOn)) for _, ip := range allFloatingIPs { target, _ := ip.Target.(*vpcv1.FloatingIPTarget) if *target.ID == *instance.PrimaryNetworkInterface.ID { g.Resources = append(g.Resources, g.loadFloatingIPResources(*ip.ID, *ip.Name)) } } } // Security group start = "" var allSgRecs []vpcv1.SecurityGroup for { options := &vpcv1.ListSecurityGroupsOptions{ VPCID: vpc.ID, } if start != "" { options.Start = &start } sgs, response, err := vpcObj.ListSecurityGroups(options) if err != nil { return fmt.Errorf("Error Fetching security Groups %s\n%s", err, response) } start = GetNext(sgs.Next) allSgRecs = append(allSgRecs, sgs.SecurityGroups...) if start == "" { break } } for _, group := range allSgRecs { var sgDependsOn []string sgDependsOn = append(sgDependsOn, "ibm_is_security_group."+terraformutils.TfSanitize(*group.Name)) g.Resources = append(g.Resources, g.loadSecurityGroupResources(*group.ID, *group.Name)) listSecurityGroupRulesOptions := &vpcv1.ListSecurityGroupRulesOptions{ SecurityGroupID: group.ID, } rules, response, err := vpcObj.ListSecurityGroupRules(listSecurityGroupRulesOptions) if err != nil { return fmt.Errorf("Error Fetching security group rules %s\n%s", err, response) } for _, sgrule := range rules.Rules { switch reflect.TypeOf(sgrule).String() { case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp": { rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolIcmp) g.Resources = append(g.Resources, g.loadSecurityGroupRuleResources(*group.ID, *rule.ID, sgDependsOn)) } case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll": { rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolAll) g.Resources = append(g.Resources, g.loadSecurityGroupRuleResources(*group.ID, *rule.ID, sgDependsOn)) } case "*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp": { rule := sgrule.(*vpcv1.SecurityGroupRuleSecurityGroupRuleProtocolTcpudp) g.Resources = append(g.Resources, g.loadSecurityGroupRuleResources(*group.ID, *rule.ID, sgDependsOn)) } } } } // Subnet start = "" var allSubNetRecs []vpcv1.Subnet for { options := &vpcv1.ListSubnetsOptions{} if start != "" { options.Start = &start } subnets, response, err := vpcObj.ListSubnets(options) if err != nil { return fmt.Errorf("Error Fetching subnets %s\n%s", err, response) } start = GetNext(subnets.Next) allSubNetRecs = append(allSubNetRecs, subnets.Subnets...) if start == "" { break } } for _, subnet := range allSubNetRecs { if *subnet.VPC.Name == vpcName { g.Resources = append(g.Resources, g.loadSubnetResources(*subnet.ID, *subnet.Name, vpcDependsOn)) } } } } return nil }