rawlinp commented on a change in pull request #2364: Fix Traffic Ops Go to use transactions for deliveryservices, sslkeys, urisigning URL: https://github.com/apache/trafficcontrol/pull/2364#discussion_r196475489
########## File path: lib/go-tc/deliveryservices.go ########## @@ -205,6 +216,213 @@ type DeliveryServiceNullableV13 struct { TRRequestHeaders *string `json:"trRequestHeaders,omitempty"` } +// NewDeliveryServiceNullableV13FromV12 creates a new V13 DS from a V12 DS, filling new fields with appropriate defaults. +func NewDeliveryServiceNullableV13FromV12(ds DeliveryServiceNullableV12) DeliveryServiceNullableV13 { + newDS := DeliveryServiceNullableV13{DeliveryServiceNullableV12: ds} + newDS.Sanitize() + return newDS +} + +func (ds *DeliveryServiceNullableV12) Sanitize() { + if ds.GeoLimitCountries != nil { + *ds.GeoLimitCountries = strings.ToUpper(strings.Replace(*ds.GeoLimitCountries, " ", "", -1)) + } + if ds.ProfileID != nil && *ds.ProfileID == -1 { + ds.ProfileID = nil + } + if ds.EdgeHeaderRewrite != nil && strings.TrimSpace(*ds.EdgeHeaderRewrite) == "" { + ds.EdgeHeaderRewrite = nil + } + if ds.MidHeaderRewrite != nil && strings.TrimSpace(*ds.MidHeaderRewrite) == "" { + ds.MidHeaderRewrite = nil + } + if ds.RoutingName == nil || *ds.RoutingName == "" { + ds.RoutingName = util.StrPtr(DefaultRoutingName) + } +} + +func getTypeName(tx *sql.Tx, id int) (string, bool, error) { + name := "" + if err := tx.QueryRow(`SELECT name from type where id=$1`, id).Scan(&name); err != nil { + if err == sql.ErrNoRows { + return "", false, nil + } + return "", false, errors.New("querying type name: " + err.Error()) + } + return name, true, nil +} + +func requiredIfMatchesTypeName(patterns []string, typeName string) func(interface{}) error { + return func(value interface{}) error { + switch v := value.(type) { + case *int: + if v != nil { + return nil + } + case *bool: + if v != nil { + return nil + } + case *string: + if v != nil { + return nil + } + case *float64: + if v != nil { + return nil + } + default: + return fmt.Errorf("validation failure: unknown type %T", value) + } + pattern := strings.Join(patterns, "|") + var err error + var match bool + if typeName != "" { + match, err = regexp.MatchString(pattern, typeName) + if match { + return fmt.Errorf("is required if type is '%s'", typeName) + } + } + return err + } +} + +// util.JoinErrs(errs).Error() + +func (ds *DeliveryServiceNullableV12) validateTypeFields(tx *sql.Tx) error { + // Validate the TypeName related fields below + var typeName string + var err error + DNSRegexType := "^DNS.*$" + HTTPRegexType := "^HTTP.*$" + SteeringRegexType := "^STEERING.*$" + if ds.TypeID == nil { + return errors.New("missing type") + } + typeName, ok, err := getTypeName(tx, *ds.TypeID) + if err != nil { + return errors.New("getting type name: " + err.Error()) + } + if !ok { + return errors.New("type not found") + } + errs := validation.Errors{ + "initialDispersion": validation.Validate(ds.InitialDispersion, + validation.By(requiredIfMatchesTypeName([]string{HTTPRegexType}, typeName))), + "ipv6RoutingEnabled": validation.Validate(ds.IPV6RoutingEnabled, + validation.By(requiredIfMatchesTypeName([]string{SteeringRegexType, DNSRegexType, HTTPRegexType}, typeName))), + "missLat": validation.Validate(ds.MissLat, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + "missLong": validation.Validate(ds.MissLong, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + "multiSiteOrigin": validation.Validate(ds.MultiSiteOrigin, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + "orgServerFqdn": validation.Validate(ds.OrgServerFQDN, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName)), + validation.NewStringRule(validateOrgServerFQDN, "must start with http:// or https:// and be followed by a valid hostname with an optional port (no trailing slash)")), + "protocol": validation.Validate(ds.Protocol, + validation.By(requiredIfMatchesTypeName([]string{SteeringRegexType, DNSRegexType, HTTPRegexType}, typeName))), + "qstringIgnore": validation.Validate(ds.QStringIgnore, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + "rangeRequestHandling": validation.Validate(ds.RangeRequestHandling, + validation.By(requiredIfMatchesTypeName([]string{DNSRegexType, HTTPRegexType}, typeName))), + } + toErrs := tovalidate.ToErrors(errs) + if len(toErrs) > 0 { + return errors.New(util.JoinErrsStr(toErrs)) + } + return nil +} + +func validateOrgServerFQDN(orgServerFQDN string) bool { + _, fqdn, port, err := ParseOrgServerFQDN(orgServerFQDN) + if err != nil || !govalidator.IsHost(*fqdn) || (port != nil && !govalidator.IsPort(*port)) { + return false + } + return true +} + +func ParseOrgServerFQDN(orgServerFQDN string) (*string, *string, *string, error) { + originRegex := regexp.MustCompile(`^(https?)://([^:]+)(:(\d+))?$`) Review comment: Yes, that's intentional. The Perl API prohibited IPv6 hosts in the `orgServerFqdn` field but allowed IPv4 hosts, so I just went along with that (not that I think they _should_ be prohibited, but they'd need proper support everywhere first). ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services