rawlinp commented on a change in pull request #4790:
URL: https://github.com/apache/trafficcontrol/pull/4790#discussion_r445175362
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -162,6 +165,24 @@ type OriginURI struct {
Port string
}
+/*
Review comment:
I imagine this comment was helpful for developing this PR but probably
isn't needed anymore.
##########
File path: lib/go-atscfg/hostingdotconfig.go
##########
@@ -74,3 +92,22 @@ func MakeHostingDotConfig(
text += strings.Join(lines, "")
return text
}
+
+func hostingMakeDSTopologies(dses []tc.DeliveryServiceNullable, topologies
[]tc.Topology) map[tc.DeliveryServiceName]tc.Topology {
Review comment:
This function appears to basically duplicate the `makeDSTopologies`
function in remapdotconfig.go except for the `== nil` checks and using
`tc.DeliveryServiceNullable`. Can they be consolidated and shared?
##########
File path: lib/go-atscfg/atscfg.go
##########
@@ -134,3 +136,64 @@ const ConfigSuffix = ".config"
func GetConfigFile(prefix string, xmlId string) string {
return prefix + xmlId + ConfigSuffix
}
+
+// topologyIncludesServer returns whether the given topology includes the
given server
+func topologyIncludesServer(topology tc.Topology, server tc.Server) bool {
+ _, inTopology := serverTopologyTier(server, topology)
+ return inTopology
+}
+
+// serverTopologyTier returns whether the server is the last tier in the
topology, and whether the server is in the topology at all.
+func serverTopologyTier(server tc.Server, topology tc.Topology) (bool, bool) {
Review comment:
With first/inner/last header rewrite now it might make sense for this
function to specify which of those 3 buckets the server is in and use this when
generating those configs.
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
+ if !serverIsLastTier {
+ // TODO make sure this is correct for DSTypeHTTPNoCache ||
DSTypeHTTPLive || DSTypeDNSLive
+ return "false"
+ }
+ if ds.OriginShield != "" {
+ return "true"
+ }
+ if ds.MultiSiteOrigin {
+ return "false"
+ }
+ // TODO make sure this is correct. If we're the last tier, we should go
direct to the origin, right?
+ return "true"
+}
+
+func getTopologyQueryString(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
Review comment:
`server` and `topology` are unused
##########
File path: lib/go-atscfg/atscfg.go
##########
@@ -134,3 +136,64 @@ const ConfigSuffix = ".config"
func GetConfigFile(prefix string, xmlId string) string {
return prefix + xmlId + ConfigSuffix
}
+
+// topologyIncludesServer returns whether the given topology includes the
given server
+func topologyIncludesServer(topology tc.Topology, server tc.Server) bool {
+ _, inTopology := serverTopologyTier(server, topology)
+ return inTopology
+}
+
+// serverTopologyTier returns whether the server is the last tier in the
topology, and whether the server is in the topology at all.
+func serverTopologyTier(server tc.Server, topology tc.Topology) (bool, bool) {
+ serverNode := tc.TopologyNode{}
+ for _, node := range topology.Nodes {
+ if node.Cachegroup == server.Cachegroup {
+ serverNode = node
+ break
+ }
+ }
+ if serverNode.Cachegroup == "" {
+ return false, false
+ }
+
+ return len(serverNode.Parents) == 0, true
Review comment:
So for MSO purposes I think we may need to include `ORG_LOC` cachegroups
in topologies. So a more valid check for this is probably that there are no
parents _or_ the parents are all `ORG_LOC`.
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
+ if !serverIsLastTier {
+ // TODO make sure this is correct for DSTypeHTTPNoCache ||
DSTypeHTTPLive || DSTypeDNSLive
+ return "false"
+ }
+ if ds.OriginShield != "" {
+ return "true"
+ }
+ if ds.MultiSiteOrigin {
+ return "false"
+ }
+ // TODO make sure this is correct. If we're the last tier, we should go
direct to the origin, right?
Review comment:
This seems right to me... 🤔 although, if we're the last tier and the DS
doesn't have an origin shield or MSO, I think we normally don't include a
parent.config line for the DS. So this kind of changes that, right? Every
topology-based DS will get a parent.config line on last-tier caches now?
As long as ATS parenting behavior is unchanged, I don't really see a problem
with that.
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
Review comment:
Should we include the topology name in this comment as well? Seems like
that would be pretty helpful
##########
File path: lib/go-atscfg/remapdotconfig.go
##########
@@ -166,14 +188,20 @@ func GetServerConfigRemapDotConfigForEdge(
cacheURLConfigParams map[string]string,
profilesCacheKeyConfigParams map[int]map[string]string,
serverPackageParamData map[string]string, // map[paramName]paramVal for
this server, config file 'package'
- server *ServerInfo,
+ serverInfo *ServerInfo,
dses []RemapConfigDSData,
atsMajorVersion int,
header string,
+ server tc.Server,
+ topologies map[tc.DeliveryServiceName]tc.Topology,
) string {
textLines := []string{}
for _, ds := range dses {
+ topology, hasTopology :=
topologies[tc.DeliveryServiceName(ds.Name)]
+ if hasTopology && !topologyIncludesServer(topology, server) {
Review comment:
I think this needs to check the required capabilities before generating
a remap line for a given DS, right?
##########
File path: lib/go-atscfg/hostingdotconfig.go
##########
@@ -74,3 +92,22 @@ func MakeHostingDotConfig(
text += strings.Join(lines, "")
return text
}
+
+func hostingMakeDSTopologies(dses []tc.DeliveryServiceNullable, topologies
[]tc.Topology) map[tc.DeliveryServiceName]tc.Topology {
+ dsTops := map[tc.DeliveryServiceName]tc.Topology{}
+ topNames := map[string]tc.Topology{}
+ for _, to := range topologies {
+ topNames[to.Name] = to
+ }
+ for _, ds := range dses {
+ if ds.Topology == nil || ds.XMLID == nil {
+ continue
+ }
+ if to, ok := topNames[*ds.Topology]; ok {
+ dsTops[tc.DeliveryServiceName(*ds.XMLID)] = to
+ } else if *ds.Topology != "" {
+ log.Errorln("Making remap.config for Delivery Service
'" + *ds.XMLID + "': has topology '" + *ds.Topology + "', but that topology
doesn't exist! Treating as if DS has no Topology!")
Review comment:
The error message should say `hosting.config`, but if this function is
consolidated with `makeDSTopologies` maybe it should be left to the caller to
prepend the `Making *.config` context.
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
+ if !serverIsLastTier {
+ // TODO make sure this is correct for DSTypeHTTPNoCache ||
DSTypeHTTPLive || DSTypeDNSLive
+ return "false"
+ }
+ if ds.OriginShield != "" {
+ return "true"
+ }
+ if ds.MultiSiteOrigin {
+ return "false"
+ }
+ // TODO make sure this is correct. If we're the last tier, we should go
direct to the origin, right?
+ return "true"
+}
+
+func getTopologyQueryString(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ if serverIsLastTier {
+ if ds.MultiSiteOrigin && ds.QStringHandling == "" &&
ds.MSOAlgorithm == tc.AlgorithmConsistentHash && ds.QStringIgnore ==
tc.QStringIgnoreUseInCacheKeyAndPassUp {
+ return "consider"
+ }
+ return "ignore"
+ }
+
+ if param := serverParams[ParentConfigParamQStringHandling]; param != ""
{
+ return param
+ }
+ if ds.QStringHandling != "" {
+ return ds.QStringHandling
+ }
+ if ds.QStringIgnore == tc.QStringIgnoreUseInCacheKeyAndPassUp {
+ return "consider"
+ }
+ return "ignore"
+}
+
+// serverParentageParams gets the Parameters used for parent= line, or
defaults if they don't exist
+// Returns the Parameters used for parent= lines, for the given server.
+func serverParentageParams(sv tc.Server, params []ParameterWithProfilesMap)
ProfileCache {
+ // TODO deduplicate with atstccfg/parentdotconfig.go
+ profileCache := DefaultProfileCache()
+ profileCache.Port = sv.TCPPort
+ for _, param := range params {
+ if _, ok := param.ProfileNames[sv.Profile]; !ok {
+ continue
+ }
+ switch param.Name {
+ case ParentConfigCacheParamWeight:
+ profileCache.Weight = param.Value
+ case ParentConfigCacheParamPort:
+ i, err := strconv.ParseInt(param.Value, 10, 64)
+ if err != nil {
+ log.Errorln("parent.config generation: port
param is not an integer, skipping! : " + err.Error())
+ } else {
+ profileCache.Port = int(i)
+ }
+ case ParentConfigCacheParamUseIP:
+ profileCache.UseIP = param.Value == "1"
+ case ParentConfigCacheParamRank:
+ i, err := strconv.ParseInt(param.Value, 10, 64)
+ if err != nil {
+ log.Errorln("parent.config generation: rank
param is not an integer, skipping! : " + err.Error())
+ } else {
+ profileCache.Rank = int(i)
+ }
+ case ParentConfigCacheParamNotAParent:
+ profileCache.NotAParent = param.Value != "false"
+ }
+ }
+ return profileCache
+}
+
+func serverParentStr(sv tc.Server, params []ParameterWithProfilesMap) string {
+ svParams := serverParentageParams(sv, params)
+ if svParams.NotAParent {
+ return ""
+ }
+ host := ""
+ if svParams.UseIP {
+ host = sv.IPAddress
+ } else {
+ host = sv.HostName + "." + sv.DomainName
+ }
+ return host + ":" + strconv.Itoa(svParams.Port) + "|" + svParams.Weight
+}
+
+func GetTopologyParents(
+ server tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
Review comment:
This parameter is unused
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
Review comment:
`server` and `topology` are unused
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
+ if !serverIsLastTier {
+ // TODO make sure this is correct for DSTypeHTTPNoCache ||
DSTypeHTTPLive || DSTypeDNSLive
+ return "false"
+ }
+ if ds.OriginShield != "" {
+ return "true"
+ }
+ if ds.MultiSiteOrigin {
+ return "false"
+ }
+ // TODO make sure this is correct. If we're the last tier, we should go
direct to the origin, right?
+ return "true"
+}
+
+func getTopologyQueryString(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ if serverIsLastTier {
+ if ds.MultiSiteOrigin && ds.QStringHandling == "" &&
ds.MSOAlgorithm == tc.AlgorithmConsistentHash && ds.QStringIgnore ==
tc.QStringIgnoreUseInCacheKeyAndPassUp {
+ return "consider"
+ }
+ return "ignore"
+ }
+
+ if param := serverParams[ParentConfigParamQStringHandling]; param != ""
{
+ return param
+ }
+ if ds.QStringHandling != "" {
+ return ds.QStringHandling
+ }
+ if ds.QStringIgnore == tc.QStringIgnoreUseInCacheKeyAndPassUp {
+ return "consider"
+ }
+ return "ignore"
+}
+
+// serverParentageParams gets the Parameters used for parent= line, or
defaults if they don't exist
+// Returns the Parameters used for parent= lines, for the given server.
+func serverParentageParams(sv tc.Server, params []ParameterWithProfilesMap)
ProfileCache {
+ // TODO deduplicate with atstccfg/parentdotconfig.go
+ profileCache := DefaultProfileCache()
+ profileCache.Port = sv.TCPPort
+ for _, param := range params {
+ if _, ok := param.ProfileNames[sv.Profile]; !ok {
+ continue
+ }
+ switch param.Name {
+ case ParentConfigCacheParamWeight:
+ profileCache.Weight = param.Value
+ case ParentConfigCacheParamPort:
+ i, err := strconv.ParseInt(param.Value, 10, 64)
+ if err != nil {
+ log.Errorln("parent.config generation: port
param is not an integer, skipping! : " + err.Error())
+ } else {
+ profileCache.Port = int(i)
+ }
+ case ParentConfigCacheParamUseIP:
+ profileCache.UseIP = param.Value == "1"
+ case ParentConfigCacheParamRank:
+ i, err := strconv.ParseInt(param.Value, 10, 64)
+ if err != nil {
+ log.Errorln("parent.config generation: rank
param is not an integer, skipping! : " + err.Error())
+ } else {
+ profileCache.Rank = int(i)
+ }
+ case ParentConfigCacheParamNotAParent:
+ profileCache.NotAParent = param.Value != "false"
+ }
+ }
+ return profileCache
+}
+
+func serverParentStr(sv tc.Server, params []ParameterWithProfilesMap) string {
+ svParams := serverParentageParams(sv, params)
+ if svParams.NotAParent {
+ return ""
+ }
+ host := ""
+ if svParams.UseIP {
+ host = sv.IPAddress
+ } else {
+ host = sv.HostName + "." + sv.DomainName
+ }
+ return host + ":" + strconv.Itoa(svParams.Port) + "|" + svParams.Weight
+}
+
+func GetTopologyParents(
+ server tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ servers []tc.Server,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.confign
+ topology tc.Topology,
+ serverIsLastTier bool,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) ([]string, []string, error) {
+ // If it's the last tier, then the parent is the origin.
+ // Note this doesn't include MSO, whose final tier cachegroup points to
the origin cachegroup.
+ if serverIsLastTier {
+ orgURI, err := GetOriginURI(ds.OriginFQDN) // TODO pass,
instead of calling again
+ if err != nil {
+ return nil, nil, err
+ }
+ return []string{orgURI.Host}, nil, nil
+ }
+
+ svNode := tc.TopologyNode{}
+ for _, node := range topology.Nodes {
+ if node.Cachegroup == server.Cachegroup {
+ svNode = node
+ break
+ }
+ }
+ if svNode.Cachegroup == "" {
+ return nil, nil, errors.New("This server '" + server.HostName +
"' not in DS " + string(ds.Name) + " topology, skipping")
+ }
+
+ if len(svNode.Parents) == 0 {
+ return nil, nil, errors.New("DS " + string(ds.Name) + "
topology '" + ds.Topology + "' is last tier, but NonLastTier called! Should
never happen")
+ }
+ if numParents := len(svNode.Parents); numParents > 2 {
+ log.Errorln("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' has " + strconv.Itoa(numParents) + " parent nodes, but Apache
Traffic Server only supports Primary and Secondary (2) lists of parents.
CacheGroup nodes after the first 2 will be ignored!")
+ }
+ if len(topology.Nodes) < svNode.Parents[0] {
Review comment:
I think this needs to be `<=`
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
+ if !serverIsLastTier {
+ // TODO make sure this is correct for DSTypeHTTPNoCache ||
DSTypeHTTPLive || DSTypeDNSLive
Review comment:
This should be correct, because for topology-based DSes, the DS type
should no longer determine whether or not it skips the mid tier.
##########
File path: lib/go-atscfg/remapdotconfig.go
##########
@@ -74,28 +75,49 @@ func MakeRemapDotConfig(
serverPackageParamData map[string]string, // map[paramName]paramVal for
this server, config file 'package'
serverInfo *ServerInfo, // ServerInfo for this server
remapDSData []RemapConfigDSData,
+ topologies []tc.Topology,
) string {
- hdr := GenericHeaderComment(string(serverName), toToolName, toURL)
- text := ""
+ dsTopologies := makeDSTopologies(remapDSData, topologies)
+ hdr := GenericHeaderComment(server.HostName, toToolName, toURL)
if tc.CacheTypeFromString(serverInfo.Type) == tc.CacheTypeMid {
- text = GetServerConfigRemapDotConfigForMid(atsMajorVersion,
dsProfilesCacheKeyConfigParams, serverInfo, remapDSData, hdr)
- } else {
- text =
GetServerConfigRemapDotConfigForEdge(cacheURLConfigParams,
dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo,
remapDSData, atsMajorVersion, hdr)
+ return GetServerConfigRemapDotConfigForMid(atsMajorVersion,
dsProfilesCacheKeyConfigParams, serverInfo, remapDSData, hdr, server,
dsTopologies)
}
- return text
+ return GetServerConfigRemapDotConfigForEdge(cacheURLConfigParams,
dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo,
remapDSData, atsMajorVersion, hdr, server, dsTopologies)
+}
+
+func makeDSTopologies(dses []RemapConfigDSData, topologies []tc.Topology)
map[tc.DeliveryServiceName]tc.Topology {
+ dsTops := map[tc.DeliveryServiceName]tc.Topology{}
+ topNames := map[string]tc.Topology{}
+ for _, to := range topologies {
+ topNames[to.Name] = to
+ }
+ for _, ds := range dses {
+ if to, ok := topNames[ds.Topology]; ok {
+ dsTops[tc.DeliveryServiceName(ds.Name)] = to
+ } else if ds.Topology != "" {
+ log.Errorln("Making remap.config for Delivery Service
'" + ds.Name + "': has topology '" + ds.Topology + "', but that topology
doesn't exist! Treating as if DS has no Topology!")
+ }
+ }
+ return dsTops
}
func GetServerConfigRemapDotConfigForMid(
atsMajorVersion int,
profilesCacheKeyConfigParams map[int]map[string]string,
- server *ServerInfo,
+ serverInfo *ServerInfo,
dses []RemapConfigDSData,
header string,
+ server tc.Server,
+ topologies map[tc.DeliveryServiceName]tc.Topology,
) string {
midRemaps := map[string]string{}
for _, ds := range dses {
- if ds.Type.IsLive() && !ds.Type.IsNational() {
- continue // Live local delivery services skip mids
+ topology, hasTopology :=
topologies[tc.DeliveryServiceName(ds.Name)]
+ if hasTopology && !topologyIncludesServer(topology, server) {
Review comment:
I think this needs to check the required capabilities before generating
a remap line for a given DS, right?
##########
File path: lib/go-atscfg/remapdotconfig.go
##########
@@ -196,7 +224,11 @@ func GetServerConfigRemapDotConfigForEdge(
if ds.ProfileID != nil {
profilecacheKeyConfigParams =
profilesCacheKeyConfigParams[*ds.ProfileID]
}
- remapText = BuildRemapLine(cacheURLConfigParams,
atsMajorVersion, server, serverPackageParamData, remapText, ds, line.From,
line.To, profilecacheKeyConfigParams)
+ remapText = BuildRemapLine(cacheURLConfigParams,
atsMajorVersion, serverInfo, serverPackageParamData, remapText, ds, line.From,
line.To, profilecacheKeyConfigParams)
+ if hasTopology {
+ remapText += " # topology" // debug
Review comment:
This comment should include the topology name as well
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
Review comment:
This TODO seems to be done, but the TODO below doesn't seem to be done
because remap.config generation doesn't seem to check capabilities yet. Did I
miss where you're doing that now?
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
+ return ` parent_is_proxy=false`
+ }
+ return ""
+}
+
+func getTopologyRoundRobin(server tc.Server, ds ParentConfigDSTopLevel,
topology tc.Topology, serverParams map[string]string, serverIsLastTier bool)
string {
+ roundRobinConsistentHash := "consistent_hash"
+ if !serverIsLastTier {
+ return roundRobinConsistentHash
+ }
+ if parentSelectAlg := serverParams[ParentConfigParamAlgorithm];
ds.OriginShield != "" && strings.TrimSpace(parentSelectAlg) != "" {
+ return parentSelectAlg
+ }
+ if ds.MultiSiteOrigin {
+ return ds.MSOAlgorithm
+ }
+ return roundRobinConsistentHash
+}
+
+func getTopologyGoDirect(server tc.Server, ds ParentConfigDSTopLevel, topology
tc.Topology, serverIsLastTier bool) string {
Review comment:
`server` and `topology` are unused
##########
File path: traffic_ops_ort/atstccfg/cfgfile/headerrewritedotconfig.go
##########
@@ -70,7 +70,7 @@ func GetConfigFileCDNHeaderRewrite(toData *config.TOData,
fileName string) (stri
if server.CDNName != *tcDS.CDNName {
continue
}
- if _, ok := dsServerIDs[server.ID]; !ok {
+ if _, ok := dsServerIDs[server.ID]; !ok && tcDS.Topology == nil
{
Review comment:
Do we need to take capabilities into account when determining whether or
not a given header-rewrite should be generated for a cache? I suppose as long
as the remap is omitted in that case, the header-rewrite configs are just cruft.
##########
File path: lib/go-atscfg/remapdotconfig.go
##########
@@ -74,28 +75,49 @@ func MakeRemapDotConfig(
serverPackageParamData map[string]string, // map[paramName]paramVal for
this server, config file 'package'
serverInfo *ServerInfo, // ServerInfo for this server
remapDSData []RemapConfigDSData,
+ topologies []tc.Topology,
) string {
- hdr := GenericHeaderComment(string(serverName), toToolName, toURL)
- text := ""
+ dsTopologies := makeDSTopologies(remapDSData, topologies)
+ hdr := GenericHeaderComment(server.HostName, toToolName, toURL)
if tc.CacheTypeFromString(serverInfo.Type) == tc.CacheTypeMid {
- text = GetServerConfigRemapDotConfigForMid(atsMajorVersion,
dsProfilesCacheKeyConfigParams, serverInfo, remapDSData, hdr)
- } else {
- text =
GetServerConfigRemapDotConfigForEdge(cacheURLConfigParams,
dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo,
remapDSData, atsMajorVersion, hdr)
+ return GetServerConfigRemapDotConfigForMid(atsMajorVersion,
dsProfilesCacheKeyConfigParams, serverInfo, remapDSData, hdr, server,
dsTopologies)
}
- return text
+ return GetServerConfigRemapDotConfigForEdge(cacheURLConfigParams,
dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo,
remapDSData, atsMajorVersion, hdr, server, dsTopologies)
+}
+
+func makeDSTopologies(dses []RemapConfigDSData, topologies []tc.Topology)
map[tc.DeliveryServiceName]tc.Topology {
+ dsTops := map[tc.DeliveryServiceName]tc.Topology{}
+ topNames := map[string]tc.Topology{}
+ for _, to := range topologies {
+ topNames[to.Name] = to
+ }
+ for _, ds := range dses {
+ if to, ok := topNames[ds.Topology]; ok {
+ dsTops[tc.DeliveryServiceName(ds.Name)] = to
+ } else if ds.Topology != "" {
+ log.Errorln("Making remap.config for Delivery Service
'" + ds.Name + "': has topology '" + ds.Topology + "', but that topology
doesn't exist! Treating as if DS has no Topology!")
+ }
+ }
+ return dsTops
}
func GetServerConfigRemapDotConfigForMid(
atsMajorVersion int,
profilesCacheKeyConfigParams map[int]map[string]string,
- server *ServerInfo,
+ serverInfo *ServerInfo,
Review comment:
`serverInfo` is now unused
##########
File path: lib/go-atscfg/parentdotconfig.go
##########
@@ -331,13 +345,270 @@ func MakeParentDotConfig(
defaultDestText += ` qstring=` + qStr
}
defaultDestText += "\n"
-
- sort.Sort(sort.StringSlice(textArr))
- text = hdr + strings.Join(textArr, "") + defaultDestText
}
+
+ sort.Sort(sort.StringSlice(textArr))
+ text := hdr + strings.Join(textArr, "") + defaultDestText
return text
}
+func GetTopologyParentConfigLine(
+ server tc.Server,
+ servers []tc.Server,
+ ds ParentConfigDSTopLevel,
+ serverParams map[string]string,
+ parentConfigParams []ParameterWithProfilesMap, // all params with
configFile parent.config
+ topologies []tc.Topology,
+ serverCapabilities map[int]map[ServerCapability]struct{},
+) (string, error) {
+ txt := ""
+
+ if !HasRequiredCapabilities(serverCapabilities[server.ID],
ds.RequiredCapabilities) {
+ return "", nil
+ }
+
+ orgURI, err := GetOriginURI(ds.OriginFQDN)
+ if err != nil {
+ return "", errors.New("Malformed ds '" + string(ds.Name) + "'
origin URI: '" + ds.OriginFQDN + "': skipping!" + err.Error())
+ }
+
+ // This could be put in a map beforehand to only iterate once, if
performance mattered
+ topology := tc.Topology{}
+ for _, to := range topologies {
+ if to.Name == ds.Topology {
+ topology = to
+ break
+ }
+ }
+ if topology.Name == "" {
+ return "", errors.New("DS " + string(ds.Name) + " topology '" +
ds.Topology + "' not found in Topologies!")
+ }
+
+ txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port()
+
+ serverIsLastTier, serverInTopology := serverTopologyTier(server,
topology)
+ if !serverInTopology {
+ return "", nil // server isn't in topology, no error
+ }
+ // TODO omit server and parents without necessary Capabilities
+ // TODO add Topology/Capabilities to remap.config
+
+ parents, secondaryParents, err := GetTopologyParents(server, ds,
serverParams, servers, parentConfigParams, topology, serverIsLastTier,
serverCapabilities)
+ if err != nil {
+ return "", errors.New("getting topology parents for '" +
string(ds.Name) + "': skipping! " + err.Error())
+ }
+ txt += ` parent="` + strings.Join(parents, `;`) + `"`
+ if len(secondaryParents) > 0 {
+ txt += ` secondary_parent="` + strings.Join(secondaryParents,
`;`) + `"`
+ }
+ txt += ` round_robin=` + getTopologyRoundRobin(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += ` go_direct=` + getTopologyGoDirect(server, ds, topology,
serverIsLastTier)
+ txt += ` qstring=` + getTopologyQueryString(server, ds, topology,
serverParams, serverIsLastTier)
+ txt += getTopologyParentIsProxyStr(serverIsLastTier)
+ txt += " # topology"
+ txt += "\n"
+ return txt, nil
+}
+
+func getTopologyParentIsProxyStr(serverIsLastTier bool) string {
+ if serverIsLastTier { // && ds.MultiSiteOrigin
Review comment:
this comment is confusing
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]