Skip to content

Commit d4e7025

Browse files
authored
Merge pull request #2323 from h2zh/fix-downtime-registry-director
Bugfix for downtime handling in Director
2 parents 38fbc9c + c47be6d commit d4e7025

3 files changed

Lines changed: 76 additions & 6 deletions

File tree

config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1898,5 +1898,5 @@ func ResetConfig() {
18981898

18991899
ResetClientInitialized()
19001900

1901-
// other than what's above, resetting Origin exports will be done by ResetTestState() in server_utils pkg
1901+
// There are other test state resets in server_utils.ResetTestState()
19021902
}

director/cache_ads.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ func getCachedDowntimes(serverName string) ([]server_structs.Downtime, error) {
365365
// Get the downtimes set by federation admin in the Registry
366366
func updateDowntimeFromRegistry(ctx context.Context) error {
367367
fedInfo, err := config.GetFederation(ctx)
368-
if err != nil || fedInfo.DirectorEndpoint == "" {
368+
if err != nil || fedInfo.RegistryEndpoint == "" {
369369
log.Error("Failed to get federation info: ", err)
370370
return errors.Wrap(err, "failed to get federation info")
371371
}
@@ -398,10 +398,9 @@ func updateDowntimeFromRegistry(ctx context.Context) error {
398398
return errors.Wrap(err, "failed to marshal response in to JSON")
399399
}
400400

401-
if len(latestFedDowntimes) == 0 {
402-
log.Debug("No downtimes set by federation admin in the Registry")
403-
return nil
404-
}
401+
// If `latestFedDowntimes` is empty, it means there's no downtime set by federation admin,
402+
// or the downtime is expired (deleted). In either case, we still need to proceed to use
403+
// it to update `filteredServers` and `federationDowntimes`, clearing out stale info.
405404

406405
filteredServersMutex.Lock()
407406
defer filteredServersMutex.Unlock()

director/director_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import (
4747

4848
"github.com/pelicanplatform/pelican/config"
4949
"github.com/pelicanplatform/pelican/param"
50+
"github.com/pelicanplatform/pelican/pelican_url"
5051
"github.com/pelicanplatform/pelican/server_structs"
5152
"github.com/pelicanplatform/pelican/server_utils"
5253
"github.com/pelicanplatform/pelican/test_utils"
@@ -1294,6 +1295,76 @@ func TestDirectorRegistration(t *testing.T) {
12941295

12951296
}
12961297

1298+
func TestUpdateDowntimeFromRegistry(t *testing.T) {
1299+
server_utils.ResetTestState()
1300+
ctx, cancel, egrp := test_utils.TestContext(context.Background(), t)
1301+
t.Cleanup(func() {
1302+
cancel()
1303+
assert.NoError(t, egrp.Wait())
1304+
server_utils.ResetTestState()
1305+
})
1306+
1307+
// Mock Registry that always returns an empty downtime list
1308+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
1309+
if r.Method == http.MethodGet && strings.HasSuffix(r.URL.Path, "/api/v1.0/downtime") {
1310+
w.Header().Set("Content-Type", "application/json")
1311+
_, _ = w.Write([]byte("[]")) // empty list
1312+
return
1313+
}
1314+
w.WriteHeader(http.StatusNotFound)
1315+
}))
1316+
defer ts.Close()
1317+
1318+
// Satisfy config.GetFederation() expectations in updateDowntimeFromRegistry func
1319+
config.SetFederation(pelican_url.FederationDiscovery{
1320+
RegistryEndpoint: ts.URL,
1321+
})
1322+
fedInfo, err := config.GetFederation(ctx)
1323+
require.NoError(t, err)
1324+
require.Equal(t, ts.URL, fedInfo.RegistryEndpoint)
1325+
1326+
now := time.Now().UTC().UnixMilli()
1327+
makeDT := func(start, end int64) server_structs.Downtime {
1328+
return server_structs.Downtime{
1329+
UUID: "00000000-0000-0000-0000-000000000000",
1330+
ServerName: "test-cache",
1331+
CreatedBy: "testuser",
1332+
UpdatedBy: "testuser",
1333+
Source: "cache",
1334+
Class: server_structs.SCHEDULED,
1335+
Description: "",
1336+
Severity: server_structs.Outage,
1337+
StartTime: start,
1338+
EndTime: end,
1339+
CreatedAt: now,
1340+
UpdatedAt: now,
1341+
DeletedAt: nil,
1342+
}
1343+
}
1344+
1345+
// Tests that when the Registry (source of fed admin downtimes) reports no current downtimes for a server,
1346+
// any previously recorded Registry-set downtimes for that server are cleared in the Director.
1347+
t.Run("clears-registry-downtime-when-deleted", func(t *testing.T) {
1348+
// Pre-seed state as if a Registry-set downtime is active
1349+
filteredServersMutex.Lock()
1350+
filteredServers["test-cache"] = tempFiltered
1351+
filteredServersMutex.Unlock()
1352+
federationDowntimes = map[string][]server_structs.Downtime{
1353+
"test-cache": {makeDT(now-10_000, now+10_000)},
1354+
}
1355+
1356+
require.NoError(t, updateDowntimeFromRegistry(ctx))
1357+
1358+
// Expect the Registry-derived filter to be gone
1359+
filteredServersMutex.RLock()
1360+
_, ok := filteredServers["test-cache"]
1361+
filteredServersMutex.RUnlock()
1362+
assert.False(t, ok, "tempFiltered entry should be removed")
1363+
1364+
assert.Empty(t, federationDowntimes, "federationDowntimes should be cleared")
1365+
})
1366+
}
1367+
12971368
func TestGetAuthzEscaped(t *testing.T) {
12981369
// Test passing a token via header with no bearer prefix
12991370
req, err := http.NewRequest(http.MethodPost, "http://fake-server.com", bytes.NewBuffer([]byte("a body")))

0 commit comments

Comments
 (0)