From 2b42366a74e510365567e17d70b00a40492b5493 Mon Sep 17 00:00:00 2001 From: Robert Butts Date: Fri, 6 Aug 2021 09:48:45 -0600 Subject: [PATCH] Fix cache config for https origins --- CHANGELOG.md | 1 + lib/go-atscfg/parentdotconfig.go | 42 +- lib/go-atscfg/parentdotconfig_test.go | 258 +++++++++++ lib/go-atscfg/remapdotconfig.go | 44 +- lib/go-atscfg/remapdotconfig_test.go | 608 +++++++++++++++++++++++++- 5 files changed, 936 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36857b4433..8613c0e329 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -96,6 +96,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - [#5981](https://github.com/apache/trafficcontrol/issues/5891) - `/deliveryservices/{{ID}}/safe` returns incorrect response for the requested API version - [#5984](https://github.com/apache/trafficcontrol/issues/5894) - `/servers/{{ID}}/deliveryservices` returns incorrect response for the requested API version - [#6027](https://github.com/apache/trafficcontrol/issues/6027) - Collapsed DB migrations +- [#6091](https://github.com/apache/trafficcontrol/issues/6091) - Fixed cache config of internal cache communication for https origins - [#6066](https://github.com/apache/trafficcontrol/issues/6066) - Fixed missing/incorrect indices on some tables - [#5576](https://github.com/apache/trafficcontrol/issues/5576) - Inconsistent Profile Name restrictions diff --git a/lib/go-atscfg/parentdotconfig.go b/lib/go-atscfg/parentdotconfig.go index 1ade8d8d14..9fe657b292 100644 --- a/lib/go-atscfg/parentdotconfig.go +++ b/lib/go-atscfg/parentdotconfig.go @@ -335,10 +335,15 @@ func MakeParentDotConfig( parentQStr = "consider" } - orgURI, orgWarns, err := getOriginURI(*ds.OrgServerFQDN) + orgFQDNStr := *ds.OrgServerFQDN + // if this cache isn't the last tier, i.e. we're not going to the origin, use http not https + if isLastCacheTier := noTopologyServerIsLastCacheForDS(server, &ds); !isLastCacheTier { + orgFQDNStr = strings.Replace(orgFQDNStr, `https://`, `http://`, -1) + } + orgURI, orgWarns, err := getOriginURI(orgFQDNStr) warnings = append(warnings, orgWarns...) if err != nil { - warnings = append(warnings, "DS '"+*ds.XMLID+"' has malformed origin URI: '"+*ds.OrgServerFQDN+"': skipping!"+err.Error()) + warnings = append(warnings, "DS '"+*ds.XMLID+"' has malformed origin URI: '"+orgFQDNStr+"': skipping!"+err.Error()) continue } @@ -381,7 +386,13 @@ func MakeParentDotConfig( warnings = append(warnings, parentWarns...) text := "" - orgURI, orgWarns, err := getOriginURI(*ds.OrgServerFQDN) + + orgFQDNStr := *ds.OrgServerFQDN + // if this cache isn't the last tier, i.e. we're not going to the origin, use http not https + if isLastCacheTier := noTopologyServerIsLastCacheForDS(server, &ds); !isLastCacheTier { + orgFQDNStr = strings.Replace(orgFQDNStr, `https://`, `http://`, -1) + } + orgURI, orgWarns, err := getOriginURI(orgFQDNStr) warnings = append(warnings, orgWarns...) if err != nil { warnings = append(warnings, "DS '"+*ds.XMLID+"' had malformed origin URI: '"+*ds.OrgServerFQDN+"': skipping!"+err.Error()) @@ -389,6 +400,7 @@ func MakeParentDotConfig( } text += makeParentComment(opt.AddComments, *ds.XMLID, "") + // TODO encode this in a DSType func, IsGoDirect() ? if *ds.Type == tc.DSTypeHTTPNoCache || *ds.Type == tc.DSTypeHTTPLive || *ds.Type == tc.DSTypeDNSLive { text += `dest_domain=` + orgURI.Hostname() + ` port=` + orgURI.Port() + ` go_direct=true` + "\n" @@ -757,20 +769,11 @@ func getTopologyParentConfigLine( return "", warnings, nil } - orgURI, orgWarns, err := getOriginURI(*ds.OrgServerFQDN) - warnings = append(warnings, orgWarns...) - if err != nil { - return "", warnings, errors.New("DS '" + *ds.XMLID + "' has malformed origin URI: '" + *ds.OrgServerFQDN + "': skipping!" + err.Error()) - } - topology := nameTopologies[TopologyName(*ds.Topology)] if topology.Name == "" { return "", warnings, errors.New("DS " + *ds.XMLID + " topology '" + *ds.Topology + "' not found in Topologies!") } - txt += makeParentComment(addComments, *ds.XMLID, *ds.Topology) - txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port() - serverPlacement, err := getTopologyPlacement(tc.CacheGroupName(*server.Cachegroup), topology, cacheGroups, ds) if err != nil { return "", warnings, errors.New("getting topology placement: " + err.Error()) @@ -778,7 +781,20 @@ func getTopologyParentConfigLine( if !serverPlacement.InTopology { return "", warnings, nil // server isn't in topology, no error } - // TODO add Topology/Capabilities to remap.config + + orgFQDNStr := *ds.OrgServerFQDN + // if this cache isn't the last tier, i.e. we're not going to the origin, use http not https + if !serverPlacement.IsLastCacheTier { + orgFQDNStr = strings.Replace(orgFQDNStr, `https://`, `http://`, -1) + } + orgURI, orgWarns, err := getOriginURI(orgFQDNStr) + warnings = append(warnings, orgWarns...) + if err != nil { + return "", warnings, errors.New("DS '" + *ds.XMLID + "' has malformed origin URI: '" + *ds.OrgServerFQDN + "': skipping!" + err.Error()) + } + + txt += makeParentComment(addComments, *ds.XMLID, *ds.Topology) + txt += "dest_domain=" + orgURI.Hostname() + " port=" + orgURI.Port() parents, secondaryParents, parentWarnings, err := getTopologyParents(server, ds, servers, parentConfigParams, topology, serverPlacement.IsLastTier, serverCapabilities, dsRequiredCapabilities, dsOrigins) warnings = append(warnings, parentWarnings...) diff --git a/lib/go-atscfg/parentdotconfig_test.go b/lib/go-atscfg/parentdotconfig_test.go index ef47b20fa0..d29df294d1 100644 --- a/lib/go-atscfg/parentdotconfig_test.go +++ b/lib/go-atscfg/parentdotconfig_test.go @@ -2619,6 +2619,264 @@ func TestMakeParentDotConfigCommentTopology(t *testing.T) { } } +func TestMakeParentDotConfigHTTPSOrigin(t *testing.T) { + hdr := &ParentConfigOpts{AddComments: false, HdrComment: "myHeaderComment"} + + ds0 := makeParentDS() + ds0Type := tc.DSTypeHTTP + ds0.Type = &ds0Type + ds0.QStringIgnore = util.IntPtr(int(tc.QStringIgnoreUseInCacheKeyAndPassUp)) + ds0.OrgServerFQDN = util.StrPtr("https://ds0.example.net") + + ds1 := makeParentDS() + ds1.ID = util.IntPtr(43) + ds1Type := tc.DSTypeDNS + ds1.Type = &ds1Type + ds1.QStringIgnore = util.IntPtr(int(tc.QStringIgnoreDrop)) + ds1.OrgServerFQDN = util.StrPtr("http://ds1.example.net") + + dses := []DeliveryService{*ds0, *ds1} + + parentConfigParams := []tc.Parameter{ + tc.Parameter{ + Name: ParentConfigParamQStringHandling, + ConfigFile: "parent.config", + Value: "myQStringHandlingParam", + Profiles: []byte(`["serverprofile"]`), + }, + tc.Parameter{ + Name: ParentConfigParamAlgorithm, + ConfigFile: "parent.config", + Value: tc.AlgorithmConsistentHash, + Profiles: []byte(`["serverprofile"]`), + }, + tc.Parameter{ + Name: ParentConfigParamQString, + ConfigFile: "parent.config", + Value: "myQstringParam", + Profiles: []byte(`["serverprofile"]`), + }, + } + + serverParams := []tc.Parameter{ + tc.Parameter{ + Name: "trafficserver", + ConfigFile: "package", + Value: "7", + Profiles: []byte(`["global"]`), + }, + } + + server := makeTestParentServer() + + mid0 := makeTestParentServer() + mid0.Cachegroup = util.StrPtr("midCG") + mid0.HostName = util.StrPtr("mymid0") + mid0.ID = util.IntPtr(45) + setIP(mid0, "192.168.2.2") + + mid1 := makeTestParentServer() + mid1.Cachegroup = util.StrPtr("midCG") + mid1.HostName = util.StrPtr("mymid1") + mid1.ID = util.IntPtr(46) + setIP(mid1, "192.168.2.3") + + servers := []Server{*server, *mid0, *mid1} + + topologies := []tc.Topology{} + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + eCG := &tc.CacheGroupNullable{} + eCG.Name = server.Cachegroup + eCG.ID = server.CachegroupID + eCG.ParentName = mid0.Cachegroup + eCG.ParentCachegroupID = mid0.CachegroupID + eCGType := tc.CacheGroupEdgeTypeName + eCG.Type = &eCGType + + mCG := &tc.CacheGroupNullable{} + mCG.Name = mid0.Cachegroup + mCG.ID = mid0.CachegroupID + mCGType := tc.CacheGroupMidTypeName + mCG.Type = &mCGType + + cgs := []tc.CacheGroupNullable{*eCG, *mCG} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds0.ID, + }, + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds1.ID, + }, + } + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + cfg, err := MakeParentDotConfig(dses, server, servers, topologies, serverParams, parentConfigParams, serverCapabilities, dsRequiredCapabilities, cgs, dss, cdn, hdr) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + testComment(t, txt, hdr.HdrComment) + + if !strings.Contains(txt, "dest_domain=ds0.example.net port=80") { + t.Errorf("expected edge parent.config of https origin to use internal http port 80 (not https/443), actual: '%v'", txt) + } +} + +func TestMakeParentDotConfigHTTPSOriginTopology(t *testing.T) { + hdr := &ParentConfigOpts{AddComments: true, HdrComment: "myHeaderComment"} + + ds0 := makeParentDS() + ds0Type := tc.DSTypeHTTP + ds0.Type = &ds0Type + ds0.QStringIgnore = util.IntPtr(int(tc.QStringIgnoreUseInCacheKeyAndPassUp)) + ds0.OrgServerFQDN = util.StrPtr("https://ds0.example.net") + ds0.ProfileID = util.IntPtr(311) + ds0.ProfileName = util.StrPtr("ds0Profile") + + ds1 := makeParentDS() + ds1.ID = util.IntPtr(43) + ds1Type := tc.DSTypeDNS + ds1.Type = &ds1Type + ds1.QStringIgnore = util.IntPtr(int(tc.QStringIgnoreDrop)) + ds1.OrgServerFQDN = util.StrPtr("http://ds1.example.net") + ds1.Topology = util.StrPtr("t0") + ds1.ProfileID = util.IntPtr(312) + ds1.ProfileName = util.StrPtr("ds1Profile") + + dses := []DeliveryService{*ds0, *ds1} + + parentConfigParams := []tc.Parameter{ + { + Name: ParentConfigParamQStringHandling, + ConfigFile: "parent.config", + Value: "myQStringHandlingParam", + Profiles: []byte(`["serverprofile"]`), + }, + { + Name: ParentConfigParamAlgorithm, + ConfigFile: "parent.config", + Value: tc.AlgorithmConsistentHash, + Profiles: []byte(`["serverprofile"]`), + }, + { + Name: ParentConfigParamQString, + ConfigFile: "parent.config", + Value: "myQstringParam", + Profiles: []byte(`["serverprofile"]`), + }, + } + + serverParams := []tc.Parameter{ + { + Name: "trafficserver", + ConfigFile: "package", + Value: "8", + Profiles: []byte(`["global"]`), + }, + } + + server := makeTestParentServer() + server.Cachegroup = util.StrPtr("edgeCG") + server.CachegroupID = util.IntPtr(400) + + mid0 := makeTestParentServer() + mid0.Cachegroup = util.StrPtr("midCG") + mid0.CachegroupID = util.IntPtr(500) + mid0.HostName = util.StrPtr("mymid") + mid0.ID = util.IntPtr(45) + setIP(mid0, "192.168.2.2") + + mid1 := makeTestParentServer() + mid1.Cachegroup = util.StrPtr("midCG2") + mid1.CachegroupID = util.IntPtr(501) + mid1.HostName = util.StrPtr("mymid1") + mid1.ID = util.IntPtr(46) + setIP(mid1, "192.168.2.3") + + servers := []Server{*server, *mid0, *mid1} + + topologies := []tc.Topology{ + { + Name: "t0", + Nodes: []tc.TopologyNode{ + { + Cachegroup: "edgeCG", + Parents: []int{1, 2}, + }, + { + Cachegroup: "midCG", + }, + { + Cachegroup: "midCG2", + }, + }, + }, + } + + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + eCG := &tc.CacheGroupNullable{} + eCG.Name = server.Cachegroup + eCG.ID = server.CachegroupID + eCG.ParentName = mid0.Cachegroup + eCG.ParentCachegroupID = mid0.CachegroupID + eCG.SecondaryParentName = mid1.Cachegroup + eCG.SecondaryParentCachegroupID = mid1.CachegroupID + eCGType := tc.CacheGroupEdgeTypeName + eCG.Type = &eCGType + + mCG := &tc.CacheGroupNullable{} + mCG.Name = mid0.Cachegroup + mCG.ID = mid0.CachegroupID + mCGType := tc.CacheGroupMidTypeName + mCG.Type = &mCGType + + mCG2 := &tc.CacheGroupNullable{} + mCG2.Name = mid1.Cachegroup + mCG2.ID = mid1.CachegroupID + mCGType2 := tc.CacheGroupMidTypeName + mCG2.Type = &mCGType2 + + cgs := []tc.CacheGroupNullable{*eCG, *mCG, *mCG2} + + dss := []DeliveryServiceServer{ + { + Server: *server.ID, + DeliveryService: *ds0.ID, + }, + { + Server: *server.ID, + DeliveryService: *ds1.ID, + }, + } + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + cfg, err := MakeParentDotConfig(dses, server, servers, topologies, serverParams, parentConfigParams, serverCapabilities, dsRequiredCapabilities, cgs, dss, cdn, hdr) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + testComment(t, txt, hdr.HdrComment) + + if !strings.Contains(txt, "dest_domain=ds0.example.net port=80") { + t.Errorf("expected topology parent.config of https origin to be http/80 not https/443, actual: '%v'", txt) + } +} + func makeTestParentServer() *Server { server := &Server{} server.ProfileID = util.IntPtr(42) diff --git a/lib/go-atscfg/remapdotconfig.go b/lib/go-atscfg/remapdotconfig.go index 08f88863fc..7803dcf54e 100644 --- a/lib/go-atscfg/remapdotconfig.go +++ b/lib/go-atscfg/remapdotconfig.go @@ -242,7 +242,9 @@ func getServerConfigRemapDotConfigForMid( continue } - if midRemaps[*ds.OrgServerFQDN] != "" { + remapFrom := strings.Replace(*ds.OrgServerFQDN, `https://`, `http://`, -1) + + if midRemaps[remapFrom] != "" { continue // skip remap rules from extra HOST_REGEXP entries } @@ -285,13 +287,13 @@ func getServerConfigRemapDotConfigForMid( } if midRemap != "" { - midRemaps[*ds.OrgServerFQDN] = midRemap + midRemaps[remapFrom] = *ds.OrgServerFQDN + midRemap } } textLines := []string{} for originFQDN, midRemap := range midRemaps { - textLines = append(textLines, "map "+originFQDN+" "+originFQDN+midRemap+"\n") + textLines = append(textLines, "map "+originFQDN+" "+midRemap+"\n") } sort.Strings(textLines) @@ -404,6 +406,17 @@ func buildEdgeRemapLine( // ds = 'remap' in perl mapFrom = strings.Replace(mapFrom, `__http__`, *server.HostName, -1) + isLastCache, err := serverIsLastCacheForDS(server, &ds, nameTopologies, cacheGroups) + if err != nil { + return "", warnings, errors.New("determining if cache is the last tier: " + err.Error()) + } + + // if this remap is going to a parent, use http not https. + // cache-to-cache communication inside the CDN is always http (though that's likely to change in the future) + if !isLastCache { + mapTo = strings.Replace(mapTo, `https://`, `http://`, -1) + } + if _, hasDSCPRemap := pData["dscp_remap"]; hasDSCPRemap { text += "map " + mapFrom + " " + mapTo + ` @plugin=dscp_remap.so @pparam=` + strconv.Itoa(*ds.DSCP) } else { @@ -815,3 +828,28 @@ func getDSRequestFQDNs(ds *DeliveryService, regexes []tc.DeliveryServiceRegex, s } return fqdns, nil } + +func serverIsLastCacheForDS(server *Server, ds *DeliveryService, topologies map[TopologyName]tc.Topology, cacheGroups map[tc.CacheGroupName]tc.CacheGroupNullable) (bool, error) { + if ds.Topology != nil && strings.TrimSpace(*ds.Topology) != "" { + if server.Cachegroup == nil { + return false, errors.New("Server has no CacheGroup") + } + topology, ok := topologies[TopologyName(*ds.Topology)] + if !ok { + return false, errors.New("DS topology '" + *ds.Topology + "' not found in topologies") + } + topoPlacement, err := getTopologyPlacement(tc.CacheGroupName(*server.Cachegroup), topology, cacheGroups, ds) + if err != nil { + return false, errors.New("getting topology placement: " + err.Error()) + } + return topoPlacement.IsLastCacheTier, nil + } + + return noTopologyServerIsLastCacheForDS(server, ds), nil +} + +// noTopologyServerIsLastCacheForDS returns whether the server is the last tier for the DS, if the DS has no Topology. +// This helper MUST NOT be called if the DS has a Topology. It does not check. +func noTopologyServerIsLastCacheForDS(server *Server, ds *DeliveryService) bool { + return strings.HasPrefix(server.Type, tc.MidTypePrefix) || !ds.Type.UsesMidCache() +} diff --git a/lib/go-atscfg/remapdotconfig_test.go b/lib/go-atscfg/remapdotconfig_test.go index 3ec89d59bb..e9b646660b 100644 --- a/lib/go-atscfg/remapdotconfig_test.go +++ b/lib/go-atscfg/remapdotconfig_test.go @@ -35,7 +35,7 @@ func makeTestRemapServer() *Server { server.DomainName = util.StrPtr("mydomain") server.CDNID = util.IntPtr(43) server.HostName = util.StrPtr("server0") - server.HTTPSPort = util.IntPtr(12443) + server.HTTPSPort = util.IntPtr(12345) server.ID = util.IntPtr(44) setIP(server, "192.168.2.4") server.ProfileID = util.IntPtr(46) @@ -7128,3 +7128,609 @@ func TestMakeRemapDotConfigMidNoNoCacheRemapLine(t *testing.T) { t.Errorf("expected remap line for HTTP_NO_CACHE to not exist on Mid server, regardless of Mid Header Rewrite, actual '%v'", txt) } } + +func TestMakeRemapDotConfigEdgeHTTPSOriginHTTPRemap(t *testing.T) { + hdr := "myHeaderComment" + + server := makeTestRemapServer() + server.Type = "EDGE" + + ds := DeliveryService{} + ds.ID = util.IntPtr(48) + dsType := tc.DSType("HTTP_LIVE_NATNL") + ds.Type = &dsType + ds.OrgServerFQDN = util.StrPtr("https://origin.example.test") + ds.MidHeaderRewrite = util.StrPtr("") + ds.RangeRequestHandling = util.IntPtr(tc.RangeRequestHandlingCacheRangeRequest) + ds.RemapText = util.StrPtr("@plugin=tslua.so @pparam=my-range-manipulator.lua") + ds.EdgeHeaderRewrite = nil + ds.SigningAlgorithm = util.StrPtr("foo") + ds.XMLID = util.StrPtr("mydsname") + ds.QStringIgnore = util.IntPtr(int(tc.QueryStringIgnoreIgnoreInCacheKeyAndPassUp)) + ds.RegexRemap = util.StrPtr("") + ds.FQPacingRate = util.IntPtr(314159) + ds.DSCP = util.IntPtr(0) + ds.RoutingName = util.StrPtr("myroutingname") + ds.MultiSiteOrigin = util.BoolPtr(false) + ds.OriginShield = util.StrPtr("myoriginshield") + ds.ProfileID = util.IntPtr(49) + ds.ProfileName = util.StrPtr("dsprofile") + ds.Protocol = util.IntPtr(int(tc.DSProtocolHTTPToHTTPS)) + ds.AnonymousBlockingEnabled = util.BoolPtr(false) + ds.Active = util.BoolPtr(true) + + dses := []DeliveryService{ds} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds.ID, + }, + } + + dsRegexes := []tc.DeliveryServiceRegexes{ + tc.DeliveryServiceRegexes{ + DSName: *ds.XMLID, + Regexes: []tc.DeliveryServiceRegex{ + tc.DeliveryServiceRegex{ + Type: string(tc.DSMatchTypeHostRegex), + SetNumber: 0, + Pattern: `myliteralpattern__http__foo`, + }, + }, + }, + } + + serverParams := []tc.Parameter{ + tc.Parameter{ + Name: "trafficserver", + ConfigFile: "package", + Value: "7", + Profiles: []byte(`["global"]`), + }, + tc.Parameter{ + Name: "serverpkgval", + ConfigFile: "package", + Value: "serverpkgval __HOSTNAME__ foo", + Profiles: []byte(*server.Profile), + }, + tc.Parameter{ + Name: "dscp_remap_no", + ConfigFile: "package", + Value: "notused", + Profiles: []byte(*server.Profile), + }, + } + + remapConfigParams := []tc.Parameter{ + tc.Parameter{ + Name: "not_location", + ConfigFile: "cachekey.config", + Value: "notinconfig", + Profiles: []byte(`["global"]`), + }, + } + + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + topologies := []tc.Topology{} + cgs := []tc.CacheGroupNullable{} + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + cfg, err := MakeRemapDotConfig(server, dses, dss, dsRegexes, serverParams, cdn, remapConfigParams, topologies, cgs, serverCapabilities, dsRequiredCapabilities, &RemapDotConfigOpts{HdrComment: hdr}) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + txt = strings.TrimSpace(txt) + + testComment(t, txt, hdr) + + txtLines := strings.Split(txt, "\n") + + if len(txtLines) != 2 { + t.Fatalf("expected 1 remaps from HTTP_TO_HTTPS DS, actual: '%v' count %v", txt, len(txtLines)) + } + + remapLine := txtLines[1] + + if !strings.HasPrefix(remapLine, "map") { + t.Errorf("expected to start with 'map', actual '%v'", txt) + } + + if strings.Contains(remapLine, "https://origin.example.test") { + t.Errorf("expected https origin to create http remap target not https (edge->mid communication always uses http), actual: ''%v'''", txt) + } + + if !strings.Contains(remapLine, "http://origin.example.test") { + t.Errorf("expected https origin to create http remap target (edge->mid communication always uses http), actual: ''%v'''", txt) + } + + if strings.Contains(remapLine, "443") { + t.Errorf("expected https origin to create http remap target not using 443 (edge->mid communication always uses http), actual: ''%v'''", txt) + } +} + +func TestMakeRemapDotConfigMidHTTPSOriginHTTPRemap(t *testing.T) { + hdr := "myHeaderComment" + + server := makeTestRemapServer() + server.Type = "MID" + + ds := DeliveryService{} + ds.ID = util.IntPtr(48) + dsType := tc.DSType("DNS") + ds.Type = &dsType + ds.OrgServerFQDN = util.StrPtr("https://origin.example.test") + ds.RangeRequestHandling = util.IntPtr(tc.RangeRequestHandlingCacheRangeRequest) + ds.RemapText = util.StrPtr("@plugin=tslua.so @pparam=my-range-manipulator.lua") + ds.SigningAlgorithm = util.StrPtr("foo") + ds.XMLID = util.StrPtr("mydsname") + ds.QStringIgnore = util.IntPtr(int(tc.QueryStringIgnoreIgnoreInCacheKeyAndPassUp)) + ds.RegexRemap = util.StrPtr("") + ds.FQPacingRate = util.IntPtr(314159) + ds.DSCP = util.IntPtr(0) + ds.RoutingName = util.StrPtr("myroutingname") + ds.MultiSiteOrigin = util.BoolPtr(false) + ds.OriginShield = util.StrPtr("myoriginshield") + ds.ProfileID = util.IntPtr(49) + ds.ProfileName = util.StrPtr("dsprofile") + ds.Protocol = util.IntPtr(int(tc.DSProtocolHTTP)) + ds.AnonymousBlockingEnabled = util.BoolPtr(false) + ds.Active = util.BoolPtr(true) + + // non-nil default values should not trigger header rewrite plugin directive + ds.EdgeHeaderRewrite = util.StrPtr("") + ds.MidHeaderRewrite = util.StrPtr("") + ds.ServiceCategory = util.StrPtr("") + ds.MaxOriginConnections = util.IntPtr(0) + + dses := []DeliveryService{ds} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds.ID, + }, + } + + dsRegexes := []tc.DeliveryServiceRegexes{ + tc.DeliveryServiceRegexes{ + DSName: *ds.XMLID, + Regexes: []tc.DeliveryServiceRegex{ + tc.DeliveryServiceRegex{ + Type: string(tc.DSMatchTypeHostRegex), + SetNumber: 0, + Pattern: `.*\.mypattern\..*`, + }, + }, + }, + } + + serverParams := []tc.Parameter{ + tc.Parameter{ + Name: "trafficserver", + ConfigFile: "package", + Value: "7", + Profiles: []byte(`["global"]`), + }, + tc.Parameter{ + Name: "serverpkgval", + ConfigFile: "package", + Value: "serverpkgval __HOSTNAME__ foo", + Profiles: []byte(*server.Profile), + }, + tc.Parameter{ + Name: "dscp_remap_no", + ConfigFile: "package", + Value: "notused", + Profiles: []byte(*server.Profile), + }, + } + + remapConfigParams := []tc.Parameter{ + tc.Parameter{ + Name: "not_location", + ConfigFile: "cachekey.config", + Value: "notinconfig", + Profiles: []byte(`["global"]`), + }, + } + + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + topologies := []tc.Topology{} + cgs := []tc.CacheGroupNullable{} + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + cfg, err := MakeRemapDotConfig(server, dses, dss, dsRegexes, serverParams, cdn, remapConfigParams, topologies, cgs, serverCapabilities, dsRequiredCapabilities, &RemapDotConfigOpts{HdrComment: hdr}) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + txt = strings.TrimSpace(txt) + + testComment(t, txt, hdr) + + txtLines := strings.Split(txt, "\n") + + if len(txtLines) != 2 { + t.Fatalf("expected 1 remaps from HTTP_TO_HTTPS DS, actual: '%v' count %v", txt, len(txtLines)) + } + + remapLine := txtLines[1] + + if !strings.HasPrefix(remapLine, "map") { + t.Errorf("expected to start with 'map', actual '%v'", txt) + } + + if !strings.Contains(remapLine, "map http://origin.example.test https://origin.example.test") { + t.Errorf("expected mid https origin to create remap from http to https (edge->mid communication always uses http, but the origin needs to still be https), actual: ''%v'''", txt) + } +} + +func TestMakeRemapDotConfigEdgeHTTPSOriginHTTPRemapTopology(t *testing.T) { + hdr := "myHeaderComment" + + server := makeTestRemapServer() + server.Type = "EDGE" + server.Cachegroup = util.StrPtr("edgeCG") + + ds := DeliveryService{} + ds.ID = util.IntPtr(48) + dsType := tc.DSType("HTTP_LIVE_NATNL") + ds.Type = &dsType + ds.OrgServerFQDN = util.StrPtr("https://origin.example.test") + ds.MidHeaderRewrite = util.StrPtr("") + ds.RangeRequestHandling = util.IntPtr(tc.RangeRequestHandlingCacheRangeRequest) + ds.RemapText = util.StrPtr("@plugin=tslua.so @pparam=my-range-manipulator.lua") + ds.EdgeHeaderRewrite = nil + ds.SigningAlgorithm = util.StrPtr("foo") + ds.XMLID = util.StrPtr("mydsname") + ds.QStringIgnore = util.IntPtr(int(tc.QueryStringIgnoreIgnoreInCacheKeyAndPassUp)) + ds.RegexRemap = util.StrPtr("") + ds.FQPacingRate = util.IntPtr(314159) + ds.DSCP = util.IntPtr(0) + ds.RoutingName = util.StrPtr("myroutingname") + ds.MultiSiteOrigin = util.BoolPtr(false) + ds.OriginShield = util.StrPtr("myoriginshield") + ds.ProfileID = util.IntPtr(49) + ds.ProfileName = util.StrPtr("dsprofile") + ds.Protocol = util.IntPtr(int(tc.DSProtocolHTTPToHTTPS)) + ds.AnonymousBlockingEnabled = util.BoolPtr(false) + ds.Active = util.BoolPtr(true) + ds.Topology = util.StrPtr("t0") + + dses := []DeliveryService{ds} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds.ID, + }, + } + + dsRegexes := []tc.DeliveryServiceRegexes{ + tc.DeliveryServiceRegexes{ + DSName: *ds.XMLID, + Regexes: []tc.DeliveryServiceRegex{ + tc.DeliveryServiceRegex{ + Type: string(tc.DSMatchTypeHostRegex), + SetNumber: 0, + Pattern: `myliteralpattern__http__foo`, + }, + }, + }, + } + + serverParams := []tc.Parameter{ + tc.Parameter{ + Name: "trafficserver", + ConfigFile: "package", + Value: "7", + Profiles: []byte(`["global"]`), + }, + tc.Parameter{ + Name: "serverpkgval", + ConfigFile: "package", + Value: "serverpkgval __HOSTNAME__ foo", + Profiles: []byte(*server.Profile), + }, + tc.Parameter{ + Name: "dscp_remap_no", + ConfigFile: "package", + Value: "notused", + Profiles: []byte(*server.Profile), + }, + } + + remapConfigParams := []tc.Parameter{ + tc.Parameter{ + Name: "not_location", + ConfigFile: "cachekey.config", + Value: "notinconfig", + Profiles: []byte(`["global"]`), + }, + } + + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + topologies := []tc.Topology{ + { + Name: "t0", + Nodes: []tc.TopologyNode{ + { + Cachegroup: "edgeCG", + Parents: []int{1, 2}, + }, + { + Cachegroup: "midCG", + }, + { + Cachegroup: "midCG2", + }, + }, + }, + } + + mid0 := makeTestParentServer() + mid0.Cachegroup = util.StrPtr("midCG") + mid0.HostName = util.StrPtr("mymid0") + mid0.ID = util.IntPtr(45) + setIP(mid0, "192.168.2.2") + + mid1 := makeTestParentServer() + mid1.Cachegroup = util.StrPtr("midCG") + mid1.HostName = util.StrPtr("mymid1") + mid1.ID = util.IntPtr(46) + setIP(mid1, "192.168.2.3") + + eCG := &tc.CacheGroupNullable{} + eCG.Name = server.Cachegroup + eCG.ID = server.CachegroupID + eCG.ParentName = mid0.Cachegroup + eCG.ParentCachegroupID = mid0.CachegroupID + eCG.SecondaryParentName = mid1.Cachegroup + eCG.SecondaryParentCachegroupID = mid1.CachegroupID + eCGType := tc.CacheGroupEdgeTypeName + eCG.Type = &eCGType + + mCG := &tc.CacheGroupNullable{} + mCG.Name = mid0.Cachegroup + mCG.ID = mid0.CachegroupID + mCGType := tc.CacheGroupMidTypeName + mCG.Type = &mCGType + + mCG2 := &tc.CacheGroupNullable{} + mCG2.Name = mid1.Cachegroup + mCG2.ID = mid1.CachegroupID + mCGType2 := tc.CacheGroupMidTypeName + mCG2.Type = &mCGType2 + + cgs := []tc.CacheGroupNullable{*eCG, *mCG, *mCG2} + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + cfg, err := MakeRemapDotConfig(server, dses, dss, dsRegexes, serverParams, cdn, remapConfigParams, topologies, cgs, serverCapabilities, dsRequiredCapabilities, &RemapDotConfigOpts{HdrComment: hdr}) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + txt = strings.TrimSpace(txt) + + testComment(t, txt, hdr) + + txtLines := strings.Split(txt, "\n") + + if len(txtLines) != 2 { + t.Fatalf("expected 1 remaps from HTTP_TO_HTTPS DS, actual: '%v' count %v", txt, len(txtLines)) + } + + remapLine := txtLines[1] + + if !strings.HasPrefix(remapLine, "map") { + t.Errorf("expected to start with 'map', actual '%v'", txt) + } + + if strings.Contains(remapLine, "https://origin.example.test") { + t.Errorf("expected https origin to create http remap target not https (edge->mid communication always uses http), actual: ''%v'''", txt) + } + + if !strings.Contains(remapLine, "http://origin.example.test") { + t.Errorf("expected https origin to create http remap target (edge->mid communication always uses http), actual: ''%v'''", txt) + } + + if strings.Contains(remapLine, "443") { + t.Errorf("expected topology edge https origin to create http remap target not using 443 (edge->mid communication always uses http), actual: ''%v'''", txt) + } +} + +func TestMakeRemapDotConfigMidHTTPSOriginHTTPRemapTopology(t *testing.T) { + hdr := "myHeaderComment" + + server := makeTestRemapServer() + server.Type = "MID" + server.Cachegroup = util.StrPtr("midCG") + + ds := DeliveryService{} + ds.ID = util.IntPtr(48) + dsType := tc.DSType("DNS") + ds.Type = &dsType + ds.OrgServerFQDN = util.StrPtr("https://origin.example.test") + ds.RangeRequestHandling = util.IntPtr(tc.RangeRequestHandlingCacheRangeRequest) + ds.RemapText = util.StrPtr("@plugin=tslua.so @pparam=my-range-manipulator.lua") + ds.SigningAlgorithm = util.StrPtr("foo") + ds.XMLID = util.StrPtr("mydsname") + ds.QStringIgnore = util.IntPtr(int(tc.QueryStringIgnoreIgnoreInCacheKeyAndPassUp)) + ds.RegexRemap = util.StrPtr("") + ds.FQPacingRate = util.IntPtr(314159) + ds.DSCP = util.IntPtr(0) + ds.RoutingName = util.StrPtr("myroutingname") + ds.MultiSiteOrigin = util.BoolPtr(false) + ds.OriginShield = util.StrPtr("myoriginshield") + ds.ProfileID = util.IntPtr(49) + ds.ProfileName = util.StrPtr("dsprofile") + ds.Protocol = util.IntPtr(int(tc.DSProtocolHTTP)) + ds.AnonymousBlockingEnabled = util.BoolPtr(false) + ds.Active = util.BoolPtr(true) + ds.Topology = util.StrPtr("t0") + + // non-nil default values should not trigger header rewrite plugin directive + ds.EdgeHeaderRewrite = util.StrPtr("") + ds.MidHeaderRewrite = util.StrPtr("") + ds.ServiceCategory = util.StrPtr("") + ds.MaxOriginConnections = util.IntPtr(0) + + dses := []DeliveryService{ds} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds.ID, + }, + } + + dsRegexes := []tc.DeliveryServiceRegexes{ + tc.DeliveryServiceRegexes{ + DSName: *ds.XMLID, + Regexes: []tc.DeliveryServiceRegex{ + tc.DeliveryServiceRegex{ + Type: string(tc.DSMatchTypeHostRegex), + SetNumber: 0, + Pattern: `.*\.mypattern\..*`, + }, + }, + }, + } + + serverParams := []tc.Parameter{ + tc.Parameter{ + Name: "trafficserver", + ConfigFile: "package", + Value: "7", + Profiles: []byte(`["global"]`), + }, + tc.Parameter{ + Name: "serverpkgval", + ConfigFile: "package", + Value: "serverpkgval __HOSTNAME__ foo", + Profiles: []byte(*server.Profile), + }, + tc.Parameter{ + Name: "dscp_remap_no", + ConfigFile: "package", + Value: "notused", + Profiles: []byte(*server.Profile), + }, + } + + remapConfigParams := []tc.Parameter{ + tc.Parameter{ + Name: "not_location", + ConfigFile: "cachekey.config", + Value: "notinconfig", + Profiles: []byte(`["global"]`), + }, + } + + cdn := &tc.CDN{ + DomainName: "cdndomain.example", + Name: "my-cdn-name", + } + + topologies := []tc.Topology{ + { + Name: "t0", + Nodes: []tc.TopologyNode{ + { + Cachegroup: "edgeCG", + Parents: []int{1, 2}, + }, + { + Cachegroup: "midCG", + }, + { + Cachegroup: "midCG2", + }, + }, + }, + } + + mid0 := makeTestParentServer() + mid0.Cachegroup = util.StrPtr("midCG") + mid0.HostName = util.StrPtr("mymid0") + mid0.ID = util.IntPtr(45) + setIP(mid0, "192.168.2.2") + + mid1 := makeTestParentServer() + mid1.Cachegroup = util.StrPtr("midCG") + mid1.HostName = util.StrPtr("mymid1") + mid1.ID = util.IntPtr(46) + setIP(mid1, "192.168.2.3") + + eCG := &tc.CacheGroupNullable{} + eCG.Name = server.Cachegroup + eCG.ID = server.CachegroupID + eCG.ParentName = mid0.Cachegroup + eCG.ParentCachegroupID = mid0.CachegroupID + eCG.SecondaryParentName = mid1.Cachegroup + eCG.SecondaryParentCachegroupID = mid1.CachegroupID + eCGType := tc.CacheGroupEdgeTypeName + eCG.Type = &eCGType + + mCG := &tc.CacheGroupNullable{} + mCG.Name = mid0.Cachegroup + mCG.ID = mid0.CachegroupID + mCGType := tc.CacheGroupMidTypeName + mCG.Type = &mCGType + + mCG2 := &tc.CacheGroupNullable{} + mCG2.Name = mid1.Cachegroup + mCG2.ID = mid1.CachegroupID + mCGType2 := tc.CacheGroupMidTypeName + mCG2.Type = &mCGType2 + + cgs := []tc.CacheGroupNullable{*eCG, *mCG, *mCG2} + serverCapabilities := map[int]map[ServerCapability]struct{}{} + dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{} + + cfg, err := MakeRemapDotConfig(server, dses, dss, dsRegexes, serverParams, cdn, remapConfigParams, topologies, cgs, serverCapabilities, dsRequiredCapabilities, &RemapDotConfigOpts{HdrComment: hdr}) + if err != nil { + t.Fatal(err) + } + txt := cfg.Text + + txt = strings.TrimSpace(txt) + + testComment(t, txt, hdr) + + txtLines := strings.Split(txt, "\n") + + if len(txtLines) != 2 { + t.Fatalf("expected 1 remaps from HTTP_TO_HTTPS DS, actual: '%v' count %v", txt, len(txtLines)) + } + + remapLine := txtLines[1] + + if !strings.HasPrefix(remapLine, "map") { + t.Errorf("expected to start with 'map', actual '%v'", txt) + } + + if !strings.Contains(remapLine, "map http://origin.example.test https://origin.example.test") { + t.Errorf("expected topology mid https origin to create remap from http to https (edge->mid communication always uses http, but the origin needs to still be https), actual: ''%v'''", txt) + } +}