diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ac6841b14..af3a862e14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Fixed searching of the ds parameter merge_parent_groups slice. - Fixed TO API `PUT /servers/:id/status` to only queue updates on the same CDN as the updated server - t3c-generate fix for combining remapconfig and cachekeyconfig parameters for MakeRemapDotConfig call. +- [#6780](https://github.com/apache/trafficcontrol/issues/6780) Fixed t3c to use secondary parents when there are no primary parents available. ### Removed - Remove traffic\_portal dependencies to mitigate `npm audit` issues, specifically `grunt-concurrent`, `grunt-contrib-concat`, `grunt-contrib-cssmin`, `grunt-contrib-jsmin`, `grunt-contrib-uglify`, `grunt-contrib-htmlmin`, `grunt-newer`, and `grunt-wiredep` diff --git a/lib/go-atscfg/parentdotconfig.go b/lib/go-atscfg/parentdotconfig.go index 9adc67a6d5..6535bb27c5 100644 --- a/lib/go-atscfg/parentdotconfig.go +++ b/lib/go-atscfg/parentdotconfig.go @@ -970,7 +970,13 @@ func getTopologyParentConfigLine( return nil, warnings, errors.New("getting topology parents for '" + *ds.XMLID + "': skipping! " + err.Error()) } if len(parents) == 0 { - return nil, warnings, errors.New("getting topology parents for '" + *ds.XMLID + "': no parents found! skipping! (Does your Topology have a CacheGroup with no servers in it?)") + if len(secondaryParents) > 0 { + warnings = append(warnings, "getting topology parents for '"+*ds.XMLID+"': no parents found! using secondary parents") + parents = secondaryParents + secondaryParents = nil + } else { + return nil, warnings, errors.New("getting topology parents for '" + *ds.XMLID + "': no parents found! skipping! (Does your Topology have a CacheGroup with no servers in it?)") + } } txt.Parents = parents diff --git a/lib/go-atscfg/parentdotconfig_test.go b/lib/go-atscfg/parentdotconfig_test.go index 628b973cbd..3710c97521 100644 --- a/lib/go-atscfg/parentdotconfig_test.go +++ b/lib/go-atscfg/parentdotconfig_test.go @@ -404,6 +404,122 @@ func TestMakeParentDotConfigMSOSecondaryParent(t *testing.T) { } } +func TestMakeParentDotConfigMSONoPrimaryParent(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("http://ds0.example.net") + ds0.MultiSiteOrigin = util.BoolPtr(true) + dses := []DeliveryService{*ds0} + + 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("midCG0") + mid0.CachegroupID = util.IntPtr(500) + mid0.HostName = util.StrPtr("my-parent-0") + mid0.DomainName = util.StrPtr("my-parent-0-domain") + mid0.Status = util.StrPtr(string(tc.CacheStatusAdminDown)) + mid0.ID = util.IntPtr(45) + setIP(mid0, "192.168.2.2") + + mid1 := makeTestParentServer() + mid1.Cachegroup = util.StrPtr("midCG1") + mid1.CachegroupID = util.IntPtr(501) + mid1.HostName = util.StrPtr("my-parent-1") + mid1.DomainName = util.StrPtr("my-parent-1-domain") + 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 + 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 + + mCG1 := &tc.CacheGroupNullable{} + mCG1.Name = mid1.Cachegroup + mCG1.ID = mid1.CachegroupID + mCGType1 := tc.CacheGroupMidTypeName + mCG1.Type = &mCGType1 + + cgs := []tc.CacheGroupNullable{*eCG, *mCG, *mCG1} + + dss := []DeliveryServiceServer{ + DeliveryServiceServer{ + Server: *server.ID, + DeliveryService: *ds0.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) + + txtx := strings.Replace(txt, " ", "", -1) + + if !strings.Contains(txtx, `parent="my-parent-1.my-parent-1-domain:80|0.999`) { + t.Errorf("expected primary parent 'my-parent-1.my-parent-1-domain', actual: '%v'", txt) + } +} + func TestMakeParentDotConfigTopologies(t *testing.T) { hdr := &ParentConfigOpts{AddComments: false, HdrComment: "myHeaderComment"} @@ -2932,6 +3048,153 @@ func TestMakeParentDotConfigHTTPSOriginTopology(t *testing.T) { } } +func TestMakeParentDotConfigHTTPSOriginTopologyNoPrimaryParent(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) + mid0.Status = util.StrPtr(string(tc.CacheStatusAdminDown)) + 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, `parent="mymid1.mydomain.example.net:80|0.999"`) { + t.Errorf("expected topology parent.config withparent=\"mymid1.mydomain.example.net:80|0.999\", actual: '%v'", txt) + } +} + func TestMakeParentDotConfigMergeParentGroupTopology(t *testing.T) { hdr := &ParentConfigOpts{AddComments: true, HdrComment: "myHeaderComment"}