func makeDSes()

in traffic_ops/traffic_ops_golang/crconfig/deliveryservice.go [46:454]


func makeDSes(cdn string, domain string, ttlOverride int, tx *sql.Tx) (map[string]tc.CRConfigDeliveryService, error) {
	dses := map[string]tc.CRConfigDeliveryService{}

	admin := CDNSOAAdmin
	expireSeconds := int(CDNSOAExpire / time.Second)
	minimumSeconds := int(CDNSOAMinimum / time.Second)
	refreshSeconds := int(CDNSOARefresh / time.Second)
	retrySeconds := int(CDNSOARetry / time.Second)
	if ttlOverride > 0 {
		expireSeconds = int(math.Min(float64(ttlOverride), float64(expireSeconds)))
		minimumSeconds = int(math.Min(float64(ttlOverride), float64(minimumSeconds)))
		refreshSeconds = int(math.Min(float64(ttlOverride), float64(refreshSeconds)))
		retrySeconds = int(math.Min(float64(ttlOverride), float64(retrySeconds)))
	}

	expireSecondsStr := strconv.Itoa(expireSeconds)
	minimumSecondsStr := strconv.Itoa(minimumSeconds)
	refreshSecondsStr := strconv.Itoa(refreshSeconds)
	retrySecondsStr := strconv.Itoa(retrySeconds)
	cdnSOA := &tc.SOA{
		Admin:          &admin,
		ExpireSeconds:  &expireSecondsStr,
		MinimumSeconds: &minimumSecondsStr,
		RefreshSeconds: &refreshSecondsStr,
		RetrySeconds:   &retrySecondsStr,
	}

	// Note the CRConfig omits acceptHTTP if it's true
	falsePtr := false
	protocol0 := &tc.CRConfigDeliveryServiceProtocol{AcceptHTTPS: false, RedirectOnHTTPS: false}
	protocol1 := &tc.CRConfigDeliveryServiceProtocol{AcceptHTTP: &falsePtr, AcceptHTTPS: true, RedirectOnHTTPS: false}
	protocol2 := &tc.CRConfigDeliveryServiceProtocol{AcceptHTTPS: true, RedirectOnHTTPS: false}
	protocol3 := &tc.CRConfigDeliveryServiceProtocol{AcceptHTTPS: true, RedirectOnHTTPS: true}
	protocolDefault := protocol0

	geoProvider0 := GeoProviderMaxmindStr
	geoProvider1 := GeoProviderNeustarStr
	geoProviderDefault := geoProvider0

	serverParams, err := getServerProfileParams(cdn, tx)
	if err != nil {
		return nil, errors.New("getting deliveryservice parameters: " + err.Error())
	}

	ttlOverrideDuration := time.Duration(ttlOverride) * time.Second

	dsParams, err := getDSParams(serverParams)
	if err != nil {
		return nil, errors.New("getting deliveryservice server parameters: " + err.Error())
	}

	dsmatchsets, dsdomains, err := getDSRegexesDomains(cdn, domain, tx)
	if err != nil {
		return nil, errors.New("getting regex matchsets: " + err.Error())
	}

	staticDNSEntries, err := getStaticDNSEntries(cdn, tx)
	if err != nil {
		return nil, errors.New("getting static DNS entries: " + err.Error())
	}

	q := `
SELECT d.anonymous_blocking_enabled,
       d.consistent_hash_regex,
       d.deep_caching_type,
       d.initial_dispersion,
       d.dns_bypass_cname,
       d.dns_bypass_ip,
       d.dns_bypass_ip6,
       d.dns_bypass_ttl,
       (SELECT ARRAY_AGG(name ORDER BY name)
                         FROM deliveryservice_consistent_hash_query_param
                         WHERE deliveryservice_id = d.id) AS query_keys,
       d.routing_name,
       d.ccr_dns_ttl AS ttl,
       d.ecs_enabled,
       d.regional_geo_blocking,
       d.geo_limit,
       d.geo_limit_countries,
       d.geolimit_redirect_url,
       d.geo_provider,
       d.http_bypass_fqdn,
       d.ipv6_routing_enabled,
       d.max_dns_answers,
       d.miss_lat,
       d.miss_long,
       p.name AS profile,
       d.protocol,
       d.required_capabilities,
       d.topology,
       d.tr_request_headers,
       d.tr_response_headers,
       d.tr_response_headers,
       t.name AS type,
       d.xml_id
FROM deliveryservice AS d
INNER JOIN type AS t ON t.id = d.type
LEFT OUTER JOIN profile AS p ON p.id = d.profile
WHERE d.cdn_id = (select id FROM cdn WHERE name = $1)
AND d.active = $2
AND t.name != $3
`
	rows, err := tx.Query(q, cdn, tc.DSActiveStateActive, tc.DSTypeAnyMap)
	if err != nil {
		return nil, errors.New("querying deliveryservices: " + err.Error())
	}
	defer rows.Close()

	for rows.Next() {
		ds := tc.CRConfigDeliveryService{
			ConsistentHashQueryParams: []string{},
			Protocol:                  &tc.CRConfigDeliveryServiceProtocol{},
			ResponseHeaders:           map[string]string{},
			Soa:                       cdnSOA,
			TTLs:                      &tc.CRConfigTTL{},
		}

		missLat := sql.NullFloat64{}
		missLon := sql.NullFloat64{}
		protocol := sql.NullInt64{}
		ttl := sql.NullInt64{}
		geoProvider := sql.NullInt64{}
		ttype := ""
		geoLimit := sql.NullInt64{}
		geoLimitCountries := sql.NullString{}
		geoLimitRedirectURL := sql.NullString{}
		dispersion := sql.NullInt64{}
		geoBlocking := false
		trRespHdrsStr := sql.NullString{}
		xmlID := ""
		maxDNSAnswers := sql.NullInt64{}
		profile := sql.NullString{}
		dnsBypassIP := sql.NullString{}
		dnsBypassIP6 := sql.NullString{}
		dnsBypassTTL := sql.NullInt64{}
		dnsBypassCName := sql.NullString{}
		httpBypassFQDN := sql.NullString{}
		ip6RoutingEnabled := sql.NullBool{}
		ecsEnabled := sql.NullBool{}
		deepCachingType := sql.NullString{}
		trRequestHeaders := sql.NullString{}
		trResponseHeaders := sql.NullString{}
		anonymousBlocking := false
		consistentHashRegex := sql.NullString{}
		err := rows.Scan(
			&anonymousBlocking,
			&consistentHashRegex,
			&deepCachingType,
			&dispersion,
			&dnsBypassCName,
			&dnsBypassIP,
			&dnsBypassIP6,
			&dnsBypassTTL,
			pq.Array(&ds.ConsistentHashQueryParams),
			&ds.RoutingName,
			&ds.TTL,
			&ecsEnabled,
			&geoBlocking,
			&geoLimit,
			&geoLimitCountries,
			&geoLimitRedirectURL,
			&geoProvider,
			&httpBypassFQDN,
			&ip6RoutingEnabled,
			&maxDNSAnswers,
			&missLat,
			&missLon,
			&profile,
			&protocol,
			pq.Array(&ds.RequiredCapabilities),
			&ds.Topology,
			&trRequestHeaders,
			&trRespHdrsStr,
			&trResponseHeaders,
			&ttype,
			&xmlID,
		)
		if err != nil {
			return nil, errors.New("scanning deliveryservice: " + err.Error())
		}

		if ttlOverride > 0 && ds.TTL != nil {
			*ds.TTL = int(math.Min(float64(ttlOverride), float64(*ds.TTL)))
		}

		// TODO prevent (lat XOR lon) in the Tx and UI
		if missLat.Valid && missLon.Valid {
			ds.MissLocation = &tc.CRConfigLatitudeLongitudeShort{Lat: missLat.Float64, Lon: missLon.Float64}
		} else if missLat.Valid {
			log.Warnln("delivery service " + xmlID + " has miss latitude but not longitude: omitting miss lat-lon from CRConfig")
		} else if missLon.Valid {
			log.Warnln("delivery service " + xmlID + " has miss longitude but not latitude: omitting miss lat-lon from CRConfig")
		}
		if ttl.Valid {
			ttl := int(ttl.Int64)
			ds.TTL = &ttl
		}

		protocolStr := tc.GetDSTypeCategory(ttype)

		ds.Protocol = protocolDefault
		if protocol.Valid {
			switch protocol.Int64 {
			case 0:
				ds.Protocol = protocol0
			case 1:
				ds.Protocol = protocol1
			case 2:
				ds.Protocol = protocol2
			case 3:
				ds.Protocol = protocol3
			}
		}

		ds.GeoLocationProvider = &geoProviderDefault
		if geoProvider.Valid {
			switch geoProvider.Int64 {
			case 0:
				ds.GeoLocationProvider = &geoProvider0
			case 1:
				ds.GeoLocationProvider = &geoProvider1
			}
		}

		if ds.Protocol.AcceptHTTPS {
			ds.SSLEnabled = true
		}

		if deepCachingType.Valid {
			// TODO change to omit Valid check, default to the default DeepCachingType (NEVER). I'm pretty sure that's what should happen, but the Valid check emulates the old Perl CRConfig generation
			t := tc.DeepCachingTypeFromString(deepCachingType.String)
			ds.DeepCachingType = &t
		}

		ds.GeoLocationProvider = &geoProviderDefault

		if matchsets, ok := dsmatchsets[xmlID]; ok {
			ds.MatchSets = matchsets
		} else {
			log.Warnln("no regex matchsets for delivery service: " + xmlID)
		}
		if domains, ok := dsdomains[xmlID]; ok {
			ds.Domains = domains
		} else {
			log.Warnln("no host regex for delivery service: " + xmlID)
		}

		switch geoLimit.Int64 { // No Valid check - default false and set countries, if null
		case 0:
			ds.CoverageZoneOnly = false
		case 1:
			ds.CoverageZoneOnly = true
			if protocolStr == "HTTP" {
				ds.GeoLimitRedirectURL = &geoLimitRedirectURL.String // No Valid check - empty string, if null
			}
		default:
			ds.CoverageZoneOnly = false
			if protocolStr == "HTTP" {
				ds.GeoLimitRedirectURL = &geoLimitRedirectURL.String // No Valid check - empty string, if null
			}
			if geoLimitCountries.Valid {
				for _, code := range strings.Split(geoLimitCountries.String, ",") {
					ds.GeoEnabled = append(ds.GeoEnabled, tc.CRConfigGeoEnabled{CountryCode: strings.TrimSpace(code)})
				}
			}
		}

		nsSeconds := DefaultTLDTTLNS
		soaSeconds := DefaultTLDTTLSOA
		if profile.Valid {
			if sval, ok := dsParams["tld.ttls.SOA"]; ok {
				if val, err := strconv.Atoi(sval); err == nil {
					soaSeconds = time.Duration(val) * time.Second
				} else {
					log.Errorln("delivery service " + xmlID + " profile " + profile.String + " param tld.ttls.SOA '" + sval + "' not a number - skipping")
				}
			}
			if sval, ok := dsParams["tld.ttls.NS"]; ok {
				if val, err := strconv.Atoi(sval); err == nil {
					nsSeconds = time.Duration(val) * time.Second
				} else {
					log.Errorln("delivery service " + xmlID + " profile " + profile.String + " param tld.ttls.NS '" + sval + "' not a number - skipping")
				}
			}
		}
		if ttlOverride > 0 && ttlOverrideDuration < nsSeconds {
			nsSeconds = ttlOverrideDuration
		}
		nsSecondsStr := strconv.Itoa(int(nsSeconds / time.Second))
		if ttlOverride > 0 && ttlOverrideDuration < soaSeconds {
			soaSeconds = ttlOverrideDuration
		}
		soaSecondsStr := strconv.Itoa(int(soaSeconds / time.Second))
		ttlStr := ""
		if ds.TTL != nil {
			ttlStr = strconv.Itoa(*ds.TTL)
		}
		ds.TTLs = &tc.CRConfigTTL{
			ASeconds:    &ttlStr,
			AAAASeconds: &ttlStr,
			NSSeconds:   &nsSecondsStr,
			SOASeconds:  &soaSecondsStr,
		}

		if protocolStr == "DNS" {
			bypassDest := &tc.CRConfigBypassDestination{}
			if dnsBypassIP.String != "" {
				bypassDest.IP = &dnsBypassIP.String
			}
			if dnsBypassIP6.String != "" {
				bypassDest.IP6 = &dnsBypassIP6.String
			}
			if dnsBypassTTL.Valid {
				i := int(dnsBypassTTL.Int64)
				if ttlOverride > 0 {
					i = int(math.Min(float64(ttlOverride), float64(i)))
				}
				bypassDest.TTL = &i
			}
			if dnsBypassCName.Valid && dnsBypassCName.String != "" {
				bypassDest.CName = &dnsBypassCName.String
			}
			if *bypassDest != (tc.CRConfigBypassDestination{}) {
				if ds.BypassDestination == nil {
					ds.BypassDestination = map[string]*tc.CRConfigBypassDestination{}
				}
				ds.BypassDestination["DNS"] = bypassDest
			}
			if maxDNSAnswers.Valid {
				i := int(maxDNSAnswers.Int64)
				ds.MaxDNSIPsForLocation = &i
			}
		} else if protocolStr == "HTTP" {
			if httpBypassFQDN.String != "" {
				if ds.BypassDestination == nil {
					ds.BypassDestination = map[string]*tc.CRConfigBypassDestination{}
				}
				hostPort := strings.Split(httpBypassFQDN.String, ":")
				bypass := &tc.CRConfigBypassDestination{FQDN: &hostPort[0]}
				if len(hostPort) > 1 {
					bypass.Port = &hostPort[1]
				}
				ds.BypassDestination["HTTP"] = bypass
			}
			geoBlockingStr := "false"
			if geoBlocking {
				geoBlockingStr = "true"
			}
			ds.RegionalGeoBlocking = &geoBlockingStr

			anonymousBlockingStr := "false"
			if anonymousBlocking {
				anonymousBlockingStr = "true"
			}
			ds.AnonymousBlockingEnabled = &anonymousBlockingStr
			if dispersion.Valid {
				ds.Dispersion = &tc.CRConfigDispersion{Limit: int(dispersion.Int64), Shuffled: true}
			}
		}

		if consistentHashRegex.Valid && consistentHashRegex.String != "" {
			ds.ConsistentHashRegex = &consistentHashRegex.String
		}

		ds.IP6RoutingEnabled = &ip6RoutingEnabled.Bool // No Valid check, false if null
		ds.EcsEnabled = &ecsEnabled.Bool               // No Valid check, false if null

		if trResponseHeaders.Valid && trResponseHeaders.String != "" {
			trResponseHeaders.String = strings.Replace(trResponseHeaders.String, "__RETURN__", "\n", -1)
			hdrs := strings.Split(trResponseHeaders.String, "\n")
			for _, hdr := range hdrs {
				nameVal := strings.Split(hdr, `:`)
				name := strings.TrimSpace(nameVal[0])
				val := ""
				if len(nameVal) > 1 {
					val = strings.Trim(nameVal[1], " \n\"")
				}
				ds.ResponseHeaders[name] = val
			}
		}

		if trRequestHeaders.Valid && trRequestHeaders.String != "" {
			trRequestHeaders.String = strings.Replace(trRequestHeaders.String, "__RETURN__", "\n", -1)
			hdrs := strings.Split(trRequestHeaders.String, "\n")
			for _, hdr := range hdrs {
				nameVal := strings.Split(hdr, `:`)
				name := strings.TrimSpace(nameVal[0])
				ds.RequestHeaders = append(ds.RequestHeaders, name)
			}
		}

		ds.StaticDNSEntries = staticDNSEntries[tc.DeliveryServiceName(xmlID)]
		if ttlOverride > 0 {
			for xmlID := range staticDNSEntries {
				for index := range staticDNSEntries[xmlID] {
					staticDNSEntries[xmlID][index].TTL = ttlOverride
				}
			}
		}

		dses[xmlID] = ds
	}

	if err := rows.Err(); err != nil {
		return nil, errors.New("iterating deliveryservice rows: " + err.Error())
	}

	return dses, nil
}