alicloud/data_source_alicloud_zones.go (541 lines of code) (raw):

package alicloud import ( "fmt" "reflect" "regexp" "sort" "strings" "github.com/aliyun/alibaba-cloud-sdk-go/services/hbase" "github.com/denverdino/aliyungo/common" "github.com/aliyun/alibaba-cloud-sdk-go/services/adb" "github.com/aliyun/alibaba-cloud-sdk-go/services/dds" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/elasticsearch" "github.com/aliyun/alibaba-cloud-sdk-go/services/gpdb" "github.com/aliyun/alibaba-cloud-sdk-go/services/polardb" r_kvstore "github.com/aliyun/alibaba-cloud-sdk-go/services/r-kvstore" "github.com/aliyun/alibaba-cloud-sdk-go/services/slb" "github.com/aliyun/fc-go-sdk" "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func dataSourceAlicloudZones() *schema.Resource { return &schema.Resource{ Read: dataSourceAlicloudZonesRead, Schema: map[string]*schema.Schema{ "available_instance_type": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`^ecs\..*`), "prefix must be 'ecs.'"), }, "available_resource_creation": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ string(ResourceTypeInstance), string(ResourceTypeRds), string(ResourceTypePolarDB), string(ResourceTypeRkv), string(ResourceTypeVSwitch), string(ResourceTypeDisk), string(IoOptimized), string(ResourceTypeFC), string(ResourceTypeElasticsearch), string(ResourceTypeSlb), string(ResourceTypeMongoDB), string(ResourceTypeGpdb), string(ResourceTypeHBase), string(ResourceTypeAdb), }, false), }, "available_slb_address_type": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ string(Vpc), string(ClassicIntranet), string(ClassicInternet), }, false), }, "available_slb_address_ip_version": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ string(IPV4), string(IPV6), }, false), }, "available_disk_category": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{ "all", "cloud", "ephemeral_ssd", "cloud_essd", "cloud_efficiency", "cloud_ssd", "local_disk", }, false), }, "multi": { Type: schema.TypeBool, Optional: true, Default: false, }, "instance_charge_type": { Type: schema.TypeString, Optional: true, ForceNew: true, Default: PostPaid, // %q must contain a valid InstanceChargeType, expected common.PrePaid, common.PostPaid ValidateFunc: validation.StringInSlice([]string{string(common.PrePaid), string(common.PostPaid)}, false), }, "network_type": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.StringInSlice([]string{"Vpc", "Classic"}, false), }, "spot_strategy": { Type: schema.TypeString, Optional: true, ForceNew: true, Default: NoSpot, ValidateFunc: validation.StringInSlice([]string{"NoSpot", "SpotAsPriceGo", "SpotWithPriceLimit"}, false), }, "enable_details": { Type: schema.TypeBool, Optional: true, Default: false, }, "output_file": { Type: schema.TypeString, Optional: true, }, "ids": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, // Computed values. "zones": { Type: schema.TypeList, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "id": { Type: schema.TypeString, Computed: true, }, "local_name": { Type: schema.TypeString, Computed: true, }, "available_instance_types": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "available_resource_creation": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "available_disk_categories": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "multi_zone_ids": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "slb_slave_zone_ids": { Type: schema.TypeList, Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, }, }, } } func dataSourceAlicloudZonesRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AliyunClient) ecsService := EcsService{client} resType := d.Get("available_resource_creation").(string) multi := d.Get("multi").(bool) var zoneIds []string rdsZones := make(map[string]string) polarDBZones := make(map[string]string) rkvZones := make(map[string]string) mongoDBZones := make(map[string]string) gpdbZones := make(map[string]string) hbaseZones := make(map[string]string) adbZones := make(map[string]string) instanceChargeType := d.Get("instance_charge_type").(string) if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypePolarDB)) { request := polardb.CreateDescribeRegionsRequest() request.RegionId = client.RegionId raw, err := client.WithPolarDBClient(func(polarDBClient *polardb.Client) (interface{}, error) { return polarDBClient.DescribeRegions(request) }) if err != nil { return WrapError(fmt.Errorf("[ERROR] DescribeRegions got an error: %#v", err)) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) regions, _ := raw.(*polardb.DescribeRegionsResponse) if len(regions.Regions.Region) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available region for PolarDB.")) } for _, r := range regions.Regions.Region { for _, zone := range r.Zones.Zone { if multi && strings.Contains(zone.ZoneId, MULTI_IZ_SYMBOL) && r.RegionId == string(client.Region) { zoneIds = append(zoneIds, zone.ZoneId) continue } polarDBZones[zone.ZoneId] = r.RegionId } } } if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeRkv)) { request := r_kvstore.CreateDescribeAvailableResourceRequest() request.RegionId = client.RegionId request.InstanceChargeType = instanceChargeType raw, err := client.WithRKvstoreClient(func(rkvClient *r_kvstore.Client) (interface{}, error) { return rkvClient.DescribeAvailableResource(request) }) if err != nil { return WrapError(fmt.Errorf("[ERROR] DescribeAvailableResource got an error: %#v", err)) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) zones, _ := raw.(*r_kvstore.DescribeAvailableResourceResponse) if len(zones.AvailableZones.AvailableZone) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available zones for KVStore")) } for _, zone := range zones.AvailableZones.AvailableZone { if multi && strings.Contains(zone.ZoneId, MULTI_IZ_SYMBOL) { zoneIds = append(zoneIds, zone.ZoneId) continue } rkvZones[zone.ZoneId] = zone.RegionId } } if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeMongoDB)) { request := dds.CreateDescribeRegionsRequest() request.RegionId = client.RegionId raw, err := client.WithDdsClient(func(ddsClient *dds.Client) (interface{}, error) { return ddsClient.DescribeRegions(request) }) if err != nil { return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_zones", request.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) regions, _ := raw.(*dds.DescribeRegionsResponse) if len(regions.Regions.DdsRegion) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available region for MongoDB.")) } for _, r := range regions.Regions.DdsRegion { for _, zonid := range r.Zones.Zone { if multi && strings.Contains(zonid.ZoneId, MULTI_IZ_SYMBOL) && r.RegionId == string(client.Region) { zoneIds = append(zoneIds, zonid.ZoneId) continue } mongoDBZones[zonid.ZoneId] = r.RegionId } } } if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeHBase)) { request := hbase.CreateDescribeRegionsRequest() request.RegionId = client.RegionId raw, err := client.WithHbaseClient(func(hbaseClient *hbase.Client) (interface{}, error) { return hbaseClient.DescribeRegions(request) }) if err != nil { return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_zones", request.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) regions, _ := raw.(*hbase.DescribeRegionsResponse) if len(regions.Regions.Region) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available region for HBase.")) } for _, r := range regions.Regions.Region { for _, zonid := range r.Zones.Zone { if r.RegionId == string(client.Region) { hbaseZones[zonid.Id] = r.RegionId } } } } if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeAdb)) { request := adb.CreateDescribeRegionsRequest() request.RegionId = client.RegionId raw, err := client.WithAdbClient(func(adbClient *adb.Client) (interface{}, error) { return adbClient.DescribeRegions(request) }) if err != nil { return WrapError(fmt.Errorf("[ERROR] DescribeRegions got an error: %#v", err)) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) regions, _ := raw.(*adb.DescribeRegionsResponse) if len(regions.Regions.Region) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available region for adb.")) } for _, r := range regions.Regions.Region { for _, zone := range r.Zones.Zone { if multi && strings.Contains(zone.ZoneId, MULTI_IZ_SYMBOL) && r.RegionId == string(client.Region) { zoneIds = append(zoneIds, zone.ZoneId) continue } adbZones[zone.ZoneId] = r.RegionId } } } if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeGpdb)) { request := gpdb.CreateDescribeRegionsRequest() request.RegionId = client.RegionId raw, err := client.WithGpdbClient(func(gpdbClient *gpdb.Client) (interface{}, error) { return gpdbClient.DescribeRegions(request) }) if err != nil { return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_zones", request.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) response, _ := raw.(*gpdb.DescribeRegionsResponse) if len(response.Regions.Region) <= 0 { return WrapError(fmt.Errorf("[ERROR] There is no available region for gpdb.")) } for _, r := range response.Regions.Region { for _, zoneId := range r.Zones.Zone { if multi && strings.Contains(zoneId.ZoneId, MULTI_IZ_SYMBOL) && r.RegionId == string(client.Region) { zoneIds = append(zoneIds, zoneId.ZoneId) continue } gpdbZones[zoneId.ZoneId] = r.RegionId } } } elasticsearchZones := make(map[string]string) if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeElasticsearch)) { request := elasticsearch.CreateGetRegionConfigurationRequest() request.RegionId = client.RegionId raw, err := client.WithElasticsearchClient(func(elasticsearchClient *elasticsearch.Client) (interface{}, error) { return elasticsearchClient.GetRegionConfiguration(request) }) if err != nil { return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_zones", request.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(request.GetActionName(), raw, request.GetActionName(), request) zones, _ := raw.(*elasticsearch.GetRegionConfigurationResponse) for _, zoneID := range zones.Result.Zones { if multi && strings.Contains(zoneID, MULTI_IZ_SYMBOL) { zoneIds = append(zoneIds, zoneID) continue } elasticsearchZones[zoneID] = string(client.Region) } } if len(zoneIds) > 0 { sort.Strings(zoneIds) return zoneIdsDescriptionAttributes(d, zoneIds) } // Retrieving available zones for VPC-FC if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeFC)) { var clientInfo *fc.Client raw, err := client.WithFcClient(func(fcClient *fc.Client) (interface{}, error) { clientInfo = fcClient return fcClient.GetAccountSettings(fc.NewGetAccountSettingsInput()) }) if err != nil { return fmt.Errorf("[API ERROR] FC GetAccountSettings: %#v", err) } addDebug("GetAccountSettings", raw, clientInfo) out, _ := raw.(*fc.GetAccountSettingsOutput) if out != nil && len(out.AvailableAZs) > 0 { sort.Strings(out.AvailableAZs) return zoneIdsDescriptionAttributes(d, out.AvailableAZs) } } // Retrieving available zones for SLB slaveZones := make(map[string][]string) if strings.ToLower(Trim(resType)) == strings.ToLower(string(ResourceTypeSlb)) { request := slb.CreateDescribeAvailableResourceRequest() request.RegionId = client.RegionId if ipVersion, ok := d.GetOk("available_slb_address_ip_version"); ok { request.AddressIPVersion = ipVersion.(string) } if addressType, ok := d.GetOk("available_slb_address_type"); ok { request.AddressType = addressType.(string) } raw, err := client.WithSlbClient(func(slbClient *slb.Client) (interface{}, error) { return slbClient.DescribeAvailableResource(request) }) if err != nil { return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_zones", request.GetActionName(), AlibabaCloudSdkGoERROR) } addDebug(request.GetActionName(), raw, request.RpcRequest, request) response, _ := raw.(*slb.DescribeAvailableResourceResponse) for _, resource := range response.AvailableResources.AvailableResource { slaveIds := slaveZones[resource.MasterZoneId] slaveIds = append(slaveIds, resource.SlaveZoneId) if len(slaveIds) > 0 { sort.Strings(slaveIds) } slaveZones[resource.MasterZoneId] = slaveIds } } _, validZones, _, err := ecsService.DescribeAvailableResources(d, meta, ZoneResource) if err != nil { return err } req := ecs.CreateDescribeZonesRequest() req.RegionId = client.RegionId req.InstanceChargeType = instanceChargeType if v, ok := d.GetOk("spot_strategy"); ok && v.(string) != "" { req.SpotStrategy = v.(string) } raw, err := client.WithEcsClient(func(ecsClient *ecs.Client) (interface{}, error) { return ecsClient.DescribeZones(req) }) if err != nil { return fmt.Errorf("DescribeZones got an error: %#v", err) } addDebug(req.GetActionName(), raw, req.RpcRequest, req) resp, _ := raw.(*ecs.DescribeZonesResponse) if resp == nil || len(resp.Zones.Zone) < 1 { return fmt.Errorf("There are no availability zones in the region: %#v.", client.Region) } mapZones := make(map[string]ecs.Zone) insType, _ := d.Get("available_instance_type").(string) diskType, _ := d.Get("available_disk_category").(string) for _, zone := range resp.Zones.Zone { for _, v := range validZones { if zone.ZoneId != v.ZoneId { continue } if len(zone.AvailableInstanceTypes.InstanceTypes) <= 0 || (insType != "" && !constraints(zone.AvailableInstanceTypes.InstanceTypes, insType)) { continue } if len(zone.AvailableDiskCategories.DiskCategories) <= 0 || (diskType != "" && !constraints(zone.AvailableDiskCategories.DiskCategories, diskType)) { continue } if len(rdsZones) > 0 { if _, ok := rdsZones[zone.ZoneId]; !ok { continue } } if len(polarDBZones) > 0 { if _, ok := polarDBZones[zone.ZoneId]; !ok { continue } } if len(rkvZones) > 0 { if _, ok := rkvZones[zone.ZoneId]; !ok { continue } } if len(mongoDBZones) > 0 { if _, ok := mongoDBZones[zone.ZoneId]; !ok { continue } } if len(hbaseZones) > 0 { if _, ok := hbaseZones[zone.ZoneId]; !ok { continue } } if len(gpdbZones) > 0 { if _, ok := gpdbZones[zone.ZoneId]; !ok { continue } } if len(elasticsearchZones) > 0 { if _, ok := elasticsearchZones[zone.ZoneId]; !ok { continue } } if len(slaveZones) > 0 { if _, ok := slaveZones[zone.ZoneId]; !ok { continue } } if len(adbZones) > 0 { if _, ok := adbZones[zone.ZoneId]; !ok { continue } } zoneIds = append(zoneIds, zone.ZoneId) mapZones[zone.ZoneId] = zone } } if len(zoneIds) > 0 { // Sort zones before reading sort.Strings(zoneIds) } var s []map[string]interface{} for _, zoneId := range zoneIds { mapping := map[string]interface{}{"id": zoneId} if len(slaveZones) > 0 { mapping["slb_slave_zone_ids"] = slaveZones[zoneId] } if !d.Get("enable_details").(bool) { s = append(s, mapping) continue } mapping["local_name"] = mapZones[zoneId].LocalName mapping["available_instance_types"] = mapZones[zoneId].AvailableInstanceTypes.InstanceTypes mapping["available_resource_creation"] = mapZones[zoneId].AvailableResourceCreation.ResourceTypes mapping["available_disk_categories"] = mapZones[zoneId].AvailableDiskCategories.DiskCategories s = append(s, mapping) } d.SetId(dataResourceIdHash(zoneIds)) if err := d.Set("zones", s); err != nil { return err } if err := d.Set("ids", zoneIds); err != nil { return err } // create a json file in current directory and write data source to it. if output, ok := d.GetOk("output_file"); ok && output.(string) != "" { writeToFile(output.(string), s) } return nil } // check array constraints str func constraints(arr interface{}, v string) bool { arrs := reflect.ValueOf(arr) len := arrs.Len() for i := 0; i < len; i++ { if arrs.Index(i).String() == v { return true } } return false } func zoneIdsDescriptionAttributes(d *schema.ResourceData, zones []string) error { var s []map[string]interface{} var zoneIds []string for _, t := range zones { mapping := map[string]interface{}{ "id": t, "multi_zone_ids": splitMultiZoneId(t), } s = append(s, mapping) zoneIds = append(zoneIds, t) } d.SetId(dataResourceIdHash(zones)) if err := d.Set("zones", s); err != nil { return WrapError(err) } if err := d.Set("ids", zoneIds); err != nil { return WrapError(err) } // create a json file in current directory and write data source to it. if output, ok := d.GetOk("output_file"); ok && output.(string) != "" { writeToFile(output.(string), s) } return nil }