diff --git a/builtin/providers/alicloud/validators.go b/builtin/providers/alicloud/validators.go index 7eb85ed43..9c7fec01a 100644 --- a/builtin/providers/alicloud/validators.go +++ b/builtin/providers/alicloud/validators.go @@ -2,26 +2,17 @@ package alicloud import ( "fmt" - "net" - "strconv" + "regexp" "strings" "github.com/denverdino/aliyungo/common" "github.com/denverdino/aliyungo/ecs" - "github.com/denverdino/aliyungo/slb" - "regexp" + "github.com/hashicorp/terraform/helper/validation" ) // common func validateInstancePort(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 1 || value > 65535 { - errors = append(errors, fmt.Errorf( - "%q must be a valid instance port between 1 and 65535", - k)) - return - } - return + return validation.IntBetween(1, 65535)(v, k) } func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []error) { @@ -37,12 +28,11 @@ func validateInstanceProtocol(v interface{}, k string) (ws []string, errors []er // ecs func validateDiskCategory(v interface{}, k string) (ws []string, errors []error) { - category := ecs.DiskCategory(v.(string)) - if category != ecs.DiskCategoryCloud && category != ecs.DiskCategoryCloudEfficiency && category != ecs.DiskCategoryCloudSSD { - errors = append(errors, fmt.Errorf("%s must be one of %s %s %s", k, ecs.DiskCategoryCloud, ecs.DiskCategoryCloudEfficiency, ecs.DiskCategoryCloudSSD)) - } - - return + return validation.StringInSlice([]string{ + string(ecs.DiskCategoryCloud), + string(ecs.DiskCategoryCloudEfficiency), + string(ecs.DiskCategoryCloudSSD), + }, false)(v, k) } func validateInstanceName(v interface{}, k string) (ws []string, errors []error) { @@ -59,12 +49,7 @@ func validateInstanceName(v interface{}, k string) (ws []string, errors []error) } func validateInstanceDescription(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if len(value) < 2 || len(value) > 256 { - errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k)) - - } - return + return validation.StringLenBetween(2, 256)(v, k) } func validateDiskName(v interface{}, k string) (ws []string, errors []error) { @@ -86,12 +71,7 @@ func validateDiskName(v interface{}, k string) (ws []string, errors []error) { } func validateDiskDescription(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if len(value) < 2 || len(value) > 256 { - errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k)) - - } - return + return validation.StringLenBetween(2, 128)(v, k) } //security group @@ -109,225 +89,114 @@ func validateSecurityGroupName(v interface{}, k string) (ws []string, errors []e } func validateSecurityGroupDescription(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - if len(value) < 2 || len(value) > 256 { - errors = append(errors, fmt.Errorf("%q cannot be longer than 256 characters", k)) - - } - return + return validation.StringLenBetween(2, 256)(v, k) } func validateSecurityRuleType(v interface{}, k string) (ws []string, errors []error) { - rt := GroupRuleDirection(v.(string)) - if rt != GroupRuleIngress && rt != GroupRuleEgress { - errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRuleIngress, GroupRuleEgress)) - } - - return + return validation.StringInSlice([]string{ + string(GroupRuleIngress), + string(GroupRuleEgress), + }, false)(v, k) } func validateSecurityRuleIpProtocol(v interface{}, k string) (ws []string, errors []error) { - pt := GroupRuleIpProtocol(v.(string)) - if pt != GroupRuleTcp && pt != GroupRuleUdp && pt != GroupRuleIcmp && pt != GroupRuleGre && pt != GroupRuleAll { - errors = append(errors, fmt.Errorf("%s must be one of %s %s %s %s %s", k, - GroupRuleTcp, GroupRuleUdp, GroupRuleIcmp, GroupRuleGre, GroupRuleAll)) - } - - return + return validation.StringInSlice([]string{ + string(GroupRuleTcp), + string(GroupRuleUdp), + string(GroupRuleIcmp), + string(GroupRuleGre), + string(GroupRuleAll), + }, false)(v, k) } func validateSecurityRuleNicType(v interface{}, k string) (ws []string, errors []error) { - pt := GroupRuleNicType(v.(string)) - if pt != GroupRuleInternet && pt != GroupRuleIntranet { - errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRuleInternet, GroupRuleIntranet)) - } - - return + return validation.StringInSlice([]string{ + string(GroupRuleInternet), + string(GroupRuleIntranet), + }, false)(v, k) } func validateSecurityRulePolicy(v interface{}, k string) (ws []string, errors []error) { - pt := GroupRulePolicy(v.(string)) - if pt != GroupRulePolicyAccept && pt != GroupRulePolicyDrop { - errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, GroupRulePolicyAccept, GroupRulePolicyDrop)) - } - - return + return validation.StringInSlice([]string{ + string(GroupRulePolicyAccept), + string(GroupRulePolicyDrop), + }, false)(v, k) } func validateSecurityPriority(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 1 || value > 100 { - errors = append(errors, fmt.Errorf( - "%q must be a valid authorization policy priority between 1 and 100", - k)) - return - } - return + return validation.IntBetween(1, 100)(v, k) } // validateCIDRNetworkAddress ensures that the string value is a valid CIDR that // represents a network address - it adds an error otherwise func validateCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - _, ipnet, err := net.ParseCIDR(value) - if err != nil { - errors = append(errors, fmt.Errorf( - "%q must contain a valid CIDR, got error parsing: %s", k, err)) - return - } - - if ipnet == nil || value != ipnet.String() { - errors = append(errors, fmt.Errorf( - "%q must contain a valid network CIDR, expected %q, got %q", - k, ipnet, value)) - } - - return + return validation.CIDRNetwork(0, 32)(v, k) } func validateRouteEntryNextHopType(v interface{}, k string) (ws []string, errors []error) { - nht := ecs.NextHopType(v.(string)) - if nht != ecs.NextHopIntance && nht != ecs.NextHopTunnel { - errors = append(errors, fmt.Errorf("%s must be one of %s %s", k, - ecs.NextHopIntance, ecs.NextHopTunnel)) - } - - return + return validation.StringInSlice([]string{ + string(ecs.NextHopIntance), + string(ecs.NextHopTunnel), + }, false)(v, k) } func validateSwitchCIDRNetworkAddress(v interface{}, k string) (ws []string, errors []error) { - value := v.(string) - _, ipnet, err := net.ParseCIDR(value) - if err != nil { - errors = append(errors, fmt.Errorf( - "%q must contain a valid CIDR, got error parsing: %s", k, err)) - return - } - - if ipnet == nil || value != ipnet.String() { - errors = append(errors, fmt.Errorf( - "%q must contain a valid network CIDR, expected %q, got %q", - k, ipnet, value)) - return - } - - mark, _ := strconv.Atoi(strings.Split(ipnet.String(), "/")[1]) - if mark < 16 || mark > 29 { - errors = append(errors, fmt.Errorf( - "%q must contain a network CIDR which mark between 16 and 29", - k)) - } - - return + return validation.CIDRNetwork(16, 29)(v, k) } // validateIoOptimized ensures that the string value is a valid IoOptimized that // represents a IoOptimized - it adds an error otherwise func validateIoOptimized(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - ioOptimized := ecs.IoOptimized(value) - if ioOptimized != ecs.IoOptimizedNone && - ioOptimized != ecs.IoOptimizedOptimized { - errors = append(errors, fmt.Errorf( - "%q must contain a valid IoOptimized, expected %s or %s, got %q", - k, ecs.IoOptimizedNone, ecs.IoOptimizedOptimized, ioOptimized)) - } - } - - return + return validation.StringInSlice([]string{ + "", + string(ecs.IoOptimizedNone), + string(ecs.IoOptimizedOptimized), + }, false)(v, k) } // validateInstanceNetworkType ensures that the string value is a classic or vpc func validateInstanceNetworkType(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - network := InstanceNetWork(value) - if network != ClassicNet && - network != VpcNet { - errors = append(errors, fmt.Errorf( - "%q must contain a valid InstanceNetworkType, expected %s or %s, go %q", - k, ClassicNet, VpcNet, network)) - } - } - return + return validation.StringInSlice([]string{ + "", + string(ClassicNet), + string(VpcNet), + }, false)(v, k) } func validateInstanceChargeType(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - chargeType := common.InstanceChargeType(value) - if chargeType != common.PrePaid && - chargeType != common.PostPaid { - errors = append(errors, fmt.Errorf( - "%q must contain a valid InstanceChargeType, expected %s or %s, got %q", - k, common.PrePaid, common.PostPaid, chargeType)) - } - } - - return + return validation.StringInSlice([]string{ + "", + string(common.PrePaid), + string(common.PostPaid), + }, false)(v, k) } func validateInternetChargeType(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - chargeType := common.InternetChargeType(value) - if chargeType != common.PayByBandwidth && - chargeType != common.PayByTraffic { - errors = append(errors, fmt.Errorf( - "%q must contain a valid InstanceChargeType, expected %s or %s, got %q", - k, common.PayByBandwidth, common.PayByTraffic, chargeType)) - } - } - - return + return validation.StringInSlice([]string{ + "", + string(common.PayByBandwidth), + string(common.PayByTraffic), + }, false)(v, k) } func validateInternetMaxBandWidthOut(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 1 || value > 100 { - errors = append(errors, fmt.Errorf( - "%q must be a valid internet bandwidth out between 1 and 1000", - k)) - return - } - return + return validation.IntBetween(1, 100)(v, k) } // SLB func validateSlbName(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - if len(value) < 1 || len(value) > 80 { - errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer name characters between 1 and 80", - k)) - return - } - } - - return + return validation.StringLenBetween(0, 80)(v, k) } func validateSlbInternetChargeType(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - chargeType := common.InternetChargeType(value) - - if chargeType != "paybybandwidth" && - chargeType != "paybytraffic" { - errors = append(errors, fmt.Errorf( - "%q must contain a valid InstanceChargeType, expected %s or %s, got %q", - k, "paybybandwidth", "paybytraffic", value)) - } - } - - return + return validation.StringInSlice([]string{ + "paybybandwidth", + "paybytraffic", + }, false)(v, k) } func validateSlbBandwidth(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 1 || value > 1000 { - errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer bandwidth between 1 and 1000", - k)) - return - } - return + return validation.IntBetween(1, 1000)(v, k) } func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors []error) { @@ -342,67 +211,23 @@ func validateSlbListenerBandwidth(v interface{}, k string) (ws []string, errors } func validateSlbListenerScheduler(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - scheduler := slb.SchedulerType(value) - - if scheduler != "wrr" && scheduler != "wlc" { - errors = append(errors, fmt.Errorf( - "%q must contain a valid SchedulerType, expected %s or %s, got %q", - k, "wrr", "wlc", value)) - } - } - - return + return validation.StringInSlice([]string{"wrr", "wlc"}, false)(v, k) } func validateSlbListenerStickySession(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - flag := slb.FlagType(value) - - if flag != "on" && flag != "off" { - errors = append(errors, fmt.Errorf( - "%q must contain a valid StickySession, expected %s or %s, got %q", - k, "on", "off", value)) - } - } - return + return validation.StringInSlice([]string{"", "on", "off"}, false)(v, k) } func validateSlbListenerStickySessionType(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - flag := slb.StickySessionType(value) - - if flag != "insert" && flag != "server" { - errors = append(errors, fmt.Errorf( - "%q must contain a valid StickySessionType, expected %s or %s, got %q", - k, "insert", "server", value)) - } - } - return + return validation.StringInSlice([]string{"", "insert", "server"}, false)(v, k) } func validateSlbListenerCookie(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - flag := slb.StickySessionType(value) - - if flag != "insert" && flag != "server" { - errors = append(errors, fmt.Errorf( - "%q must contain a valid StickySessionType, expected %s or %s, got %q", - k, "insert", "server", value)) - } - } - return + return validation.StringInSlice([]string{"", "insert", "server"}, false)(v, k) } func validateSlbListenerPersistenceTimeout(v interface{}, k string) (ws []string, errors []error) { - value := v.(int) - if value < 0 || value > 86400 { - errors = append(errors, fmt.Errorf( - "%q must be a valid load balancer persistence timeout between 0 and 86400", - k)) - return - } - return + return validation.IntBetween(0, 86400)(v, k) } //data source validate func @@ -419,19 +244,14 @@ func validateNameRegex(v interface{}, k string) (ws []string, errors []error) { } func validateImageOwners(v interface{}, k string) (ws []string, errors []error) { - if value := v.(string); value != "" { - owners := ecs.ImageOwnerAlias(value) - if owners != ecs.ImageOwnerSystem && - owners != ecs.ImageOwnerSelf && - owners != ecs.ImageOwnerOthers && - owners != ecs.ImageOwnerMarketplace && - owners != ecs.ImageOwnerDefault { - errors = append(errors, fmt.Errorf( - "%q must contain a valid Image owner , expected %s, %s, %s, %s or %s, got %q", - k, ecs.ImageOwnerSystem, ecs.ImageOwnerSelf, ecs.ImageOwnerOthers, ecs.ImageOwnerMarketplace, ecs.ImageOwnerDefault, owners)) - } - } - return + return validation.StringInSlice([]string{ + "", + string(ecs.ImageOwnerSystem), + string(ecs.ImageOwnerSelf), + string(ecs.ImageOwnerOthers), + string(ecs.ImageOwnerMarketplace), + string(ecs.ImageOwnerDefault), + }, false)(v, k) } func validateRegion(v interface{}, k string) (ws []string, errors []error) { diff --git a/helper/validation/validation.go b/helper/validation/validation.go index 484f7d7da..82a9dec72 100644 --- a/helper/validation/validation.go +++ b/helper/validation/validation.go @@ -2,6 +2,7 @@ package validation import ( "fmt" + "net" "strings" "github.com/hashicorp/terraform/helper/schema" @@ -47,3 +48,53 @@ func StringInSlice(valid []string, ignoreCase bool) schema.SchemaValidateFunc { return } } + +// StringLenBetween returns a SchemaValidateFunc which tests if the provided value +// is of type string and has length between min and max (inclusive) +func StringLenBetween(min, max int) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + if len(v) < min || len(v) > max { + es = append(es, fmt.Errorf("expected length of %s to be in the range (%d - %d), got %s", k, min, max, v)) + } + return + } +} + +// CIDRNetwork returns a SchemaValidateFunc which tests if the provided value +// is of type string, is in valid CIDR network notation, and has significant bits between min and max (inclusive) +func CIDRNetwork(min, max int) schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + _, ipnet, err := net.ParseCIDR(v) + if err != nil { + es = append(es, fmt.Errorf( + "expected %s to contain a valid CIDR, got: %s with err: %s", k, v, err)) + return + } + + if ipnet == nil || v != ipnet.String() { + es = append(es, fmt.Errorf( + "expected %s to contain a valid network CIDR, expected %s, got %s", + k, ipnet, v)) + } + + sigbits, _ := ipnet.Mask.Size() + if sigbits < min || sigbits > max { + es = append(es, fmt.Errorf( + "expected %q to contain a network CIDR with between %d and %d significant bits, got: %d", + k, min, max, sigbits)) + } + + return + } +}