Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tune up file transfer tests #1300

Merged
merged 1 commit into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions cache/self_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,15 @@ import (
"strings"
"time"

"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"

"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/metrics"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/token"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/errgroup"
"github.com/pelicanplatform/pelican/token_scopes"
)

const (
Expand Down Expand Up @@ -174,7 +176,7 @@ func generateFileTestScitoken() (string, error) {
fTestTokenCfg.Lifetime = time.Minute
fTestTokenCfg.Issuer = issuerUrl
fTestTokenCfg.Subject = "cache"
fTestTokenCfg.Claims = map[string]string{"scope": "storage.read:/pelican/monitoring/selfTest"}
fTestTokenCfg.AddResourceScopes(token_scopes.NewResourceScope(token_scopes.Storage_Read, "/pelican/monitoring/selfTest"))
// For self-tests, the audience is the server itself
fTestTokenCfg.AddAudienceAny()

Expand Down
18 changes: 10 additions & 8 deletions director/cache_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@ import (
"io"
"net/http"
"net/url"
"path"
"strings"
"time"

"github.com/pelicanplatform/pelican/config"
"github.com/pkg/errors"
)

const (
cacheMonitroingBasePath = "/pelican/monitoring"
testFileContent = "This object was created by the Pelican director-test functionality. Test is issued at "
"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/server_utils"
)

// Run one object transfer to a cache from the director. Since director-based cache tests require a different
// workflow than the origin tests. We can't reuse server_utils.RunTests(), but we want to keep common
// pieces together
func runCacheTest(ctx context.Context, cacheUrl url.URL) error {
nowStr := time.Now().Format(time.RFC3339)
cacheUrl.Path = fmt.Sprintf("/pelican/monitoring/%s.txt", nowStr)
dirMonPath := path.Join(server_utils.MonitoringBaseNs, "directorTest")
cacheUrl = *cacheUrl.JoinPath(path.Join(dirMonPath, server_utils.DirectorTest.String()+"-"+nowStr+".txt"))
client := http.Client{Transport: config.GetTransport()}
req, err := http.NewRequestWithContext(ctx, "GET", cacheUrl.String(), nil)
if err != nil {
Expand All @@ -62,9 +64,9 @@ func runCacheTest(ctx context.Context, cacheUrl url.URL) error {
}
strBody := string(byteBody)

if strings.TrimSuffix(strBody, "\n") == testFileContent+nowStr {
if strings.TrimSuffix(strBody, "\n") == server_utils.DirectorTestBody {
return nil
} else {
return fmt.Errorf("cache response file does not match expectation. Expected:%s, Got:%s", testFileContent+nowStr, strBody)
return fmt.Errorf("cache response file does not match expectation. Expected:%s, Got:%s", server_utils.DirectorTestBody, strBody)
}
}
11 changes: 5 additions & 6 deletions director/director.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/pelicanplatform/pelican/metrics"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/server_structs"
"github.com/pelicanplatform/pelican/server_utils"
"github.com/pelicanplatform/pelican/token"
"github.com/pelicanplatform/pelican/token_scopes"
)
Expand Down Expand Up @@ -945,16 +946,16 @@ func getPrefixByPath(ctx *gin.Context) {
// Generate a mock file for caches to fetch. This is for director-based health tests for caches
// So that we don't require an origin to feed the test file to the cache
func getHealthTestFile(ctx *gin.Context) {
// Expected path: /pelican/monitoring/2006-01-02T15:04:05Z07:00.txt
// Expected path: /pelican/monitoring/directorTest/2006-01-02T15:04:05Z07:00.txt
pathParam := ctx.Param("path")
cleanedPath := path.Clean(pathParam)
if cleanedPath == "" || !strings.HasPrefix(cleanedPath, cacheMonitroingBasePath+"/") {
if cleanedPath == "" || !strings.HasPrefix(cleanedPath, server_utils.MonitoringBaseNs+"/") {
ctx.JSON(http.StatusBadRequest, server_structs.SimpleApiResp{
Status: server_structs.RespFailed,
Msg: "Path parameter is not a valid health test path: " + cleanedPath})
return
}
fileName := strings.TrimPrefix(cleanedPath, cacheMonitroingBasePath+"/")
fileName := strings.TrimPrefix(cleanedPath, server_utils.MonitoringBaseNs+"/")
if fileName == "" {
ctx.JSON(http.StatusBadRequest, server_structs.SimpleApiResp{
Status: server_structs.RespFailed,
Expand All @@ -969,9 +970,7 @@ func getHealthTestFile(ctx *gin.Context) {
return
}

filenameWoExt := fileNameSplit[0]

fileContent := fmt.Sprintf("%s%s\n", testFileContent, filenameWoExt)
fileContent := server_utils.DirectorTestBody + "\n"

if ctx.Request.Method == "HEAD" {
ctx.Header("Content-Length", strconv.Itoa(len(fileContent)))
Expand Down
3 changes: 2 additions & 1 deletion director/director_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (

"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/server_structs"
"github.com/pelicanplatform/pelican/server_utils"
"github.com/pelicanplatform/pelican/test_utils"
"github.com/pelicanplatform/pelican/token"
"github.com/pelicanplatform/pelican/token_scopes"
Expand Down Expand Up @@ -1159,7 +1160,7 @@ func TestGetHealthTestFile(t *testing.T) {

bytes, err := io.ReadAll(w.Result().Body)
require.NoError(t, err)
assert.Equal(t, testFileContent+"testfile\n", string(bytes))
assert.Equal(t, server_utils.DirectorTestBody+"\n", string(bytes))
})
}

Expand Down
2 changes: 1 addition & 1 deletion director/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func LaunchPeriodicDirectorTest(ctx context.Context, serverAd server_structs.Ser
var err error
if serverAd.Type == server_structs.OriginType {
fileTests := server_utils.TestFileTransferImpl{}
ok, err = fileTests.RunTests(ctx, serverUrl, serverUrl, "", server_utils.DirectorFileTest)
ok, err = fileTests.RunTests(ctx, serverUrl, serverUrl, "", server_utils.DirectorTest)
} else if serverAd.Type == server_structs.CacheType {
err = runCacheTest(ctx, serverAd.URL)
}
Expand Down
2 changes: 1 addition & 1 deletion origin/self_monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func doSelfMonitor(ctx context.Context) {
log.Debug("Starting a new self-test monitoring cycle")
fileTests := server_utils.TestFileTransferImpl{}
issuerUrl := param.Server_ExternalWebUrl.GetString()
ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.OriginSelfFileTest)
ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.ServerSelfTest)
if ok && err == nil {
log.Debugln("Self-test monitoring cycle succeeded at", time.Now().Format(time.UnixDate))
metrics.SetComponentHealthStatus(metrics.OriginCache_XRootD, metrics.StatusOK, "Self-test monitoring cycle succeeded at "+time.Now().Format(time.RFC3339))
Expand Down
44 changes: 26 additions & 18 deletions server_utils/test_file_transfer.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ import (
"io"
"net/http"
"net/url"
"path"
"time"

"github.com/pkg/errors"

"github.com/pelicanplatform/pelican/config"
"github.com/pelicanplatform/pelican/param"
"github.com/pelicanplatform/pelican/token"
"github.com/pkg/errors"
)

type (
Expand All @@ -45,22 +47,24 @@ type (
RunTests(ctx context.Context, baseUrl string, testType TestType) (bool, error)
}
TestFileTransferImpl struct {
audiences []string
issuerUrl string
testType TestType
testBody string
audiences []string
issuerUrl string
testType TestType
testBody string
testFilePath string // the path to the test file folder. e.g. /pelican/monitoring/selfTest
}
)

const (
OriginSelfFileTest TestType = "self-test"
DirectorFileTest TestType = "director-test"
CacheTest TestType = "cache-test"
ServerSelfTest TestType = "self-test" // Origin/Cache object transfer self-test
DirectorTest TestType = "director-test" // Director-based object transfer test
)

const MonitoringBaseNs string = "/pelican/monitoring" // The base namespace for monitoring objects

const (
selfTestBody string = "This object was created by the Pelican self-test functionality"
directorTestBody string = "This object was created by the Pelican director-test functionality"
SelfTestBody string = "This object was created by the Pelican self-test functionality"
DirectorTestBody string = "This object was created by the Pelican director-test functionality"
)

func (t TestType) String() string {
Expand Down Expand Up @@ -89,13 +93,12 @@ func (t TestFileTransferImpl) generateFileTestScitoken() (string, error) {
if err != nil {
return "", errors.Wrap(err, "failed to create file test token")
}

return tok, nil
}

// Private function to upload a test file to the `baseUrl` of an exported xrootd file directory
// the test file content is based on the `testType` attribute
func (t TestFileTransferImpl) uploadTestfile(ctx context.Context, baseUrl string, namespace string) (string, error) {
func (t TestFileTransferImpl) uploadTestfile(ctx context.Context, baseUrl string) (string, error) {
tkn, err := t.generateFileTestScitoken()
if err != nil {
return "", errors.Wrap(err, "Failed to create a token for test file transfer")
Expand All @@ -105,7 +108,8 @@ func (t TestFileTransferImpl) uploadTestfile(ctx context.Context, baseUrl string
if err != nil {
return "", errors.Wrap(err, "The baseUrl is not parseable as a URL")
}
uploadURL.Path = namespace + t.testType.String() + "-" + time.Now().Format(time.RFC3339) + ".txt"
// /pelican/monitoring/<selfTest|directorTest>/<self-test|director-test>-YYYY-MM-DDTHH:MM:SSZ.txt
uploadURL = uploadURL.JoinPath(path.Join(t.testFilePath, t.testType.String()+"-"+time.Now().Format(time.RFC3339)+".txt"))

req, err := http.NewRequestWithContext(ctx, http.MethodPut, uploadURL.String(), bytes.NewBuffer([]byte(t.testBody)))
if err != nil {
Expand Down Expand Up @@ -208,15 +212,19 @@ func (t TestFileTransferImpl) RunTests(ctx context.Context, baseUrl, audienceUrl
t.audiences = []string{baseUrl, audienceUrl}
t.issuerUrl = issuerUrl
t.testType = testType
if testType == OriginSelfFileTest {
t.testBody = selfTestBody
} else if testType == DirectorFileTest {
t.testBody = directorTestBody
t.testFilePath = MonitoringBaseNs

if t.testType == ServerSelfTest {
t.testBody = SelfTestBody
t.testFilePath = path.Join(MonitoringBaseNs, "selfTest")
} else if t.testType == DirectorTest {
t.testBody = DirectorTestBody
t.testFilePath = path.Join(MonitoringBaseNs, "directorTest")
} else {
return false, errors.New("Unsupported testType: " + testType.String())
}

downloadUrl, err := t.uploadTestfile(ctx, baseUrl, "/pelican/monitoring/")
downloadUrl, err := t.uploadTestfile(ctx, baseUrl)
if err != nil {
return false, errors.Wrap(err, "Test file transfer failed during upload")
}
Expand Down
4 changes: 2 additions & 2 deletions xrootd/origin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func TestOrigin(t *testing.T) {
issuerUrl, err := config.GetServerIssuerURL()
require.NoError(t, err)

ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.OriginSelfFileTest)
ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.ServerSelfTest)
require.NoError(t, err)
require.True(t, ok)
}
Expand Down Expand Up @@ -228,7 +228,7 @@ func TestMultiExportOrigin(t *testing.T) {
issuerUrl, err := config.GetServerIssuerURL()
require.NoError(t, err)

ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.OriginSelfFileTest)
ok, err := fileTests.RunTests(ctx, param.Origin_Url.GetString(), config.GetServerAudience(), issuerUrl, server_utils.ServerSelfTest)
require.NoError(t, err)
require.True(t, ok)
}
Expand Down
Loading