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

Fix caps 7.11 #1729

Merged
merged 2 commits into from
Nov 12, 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
55 changes: 6 additions & 49 deletions server_structs/director.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,13 @@ type (
CredentialIssuer url.URL `json:"issuer"`
}

// A struct for unmarshalling the old JSON while we stage the breaking change across releases
OldCapabilities struct {
PublicRead bool
Read bool
Write bool
Listing bool
FallBackRead bool
}

// Note that the json are kept in uppercase for backward compatibility
Capabilities struct {
PublicReads bool
Reads bool
Writes bool
Listings bool
DirectReads bool
PublicReads bool `json:"PublicRead"`
Reads bool `json:"Read"`
Writes bool `json:"Write"`
Listings bool `json:"Listing"`
DirectReads bool `json:"FallBackRead"`
}

NamespaceAdV2 struct {
Expand Down Expand Up @@ -187,41 +179,6 @@ type (
}
)

// A helper function to handle JSON->Caps unmarshalling across multiple deprecated JSON keys.
//
// Old Caches/Origins will send various bits of JSON to the Director containing the JSON representation
// of the OldCapabilities struct. To make sure these old JSON representations are unmarshalled correctly
// into the new Capabilities struct, this function determines which JSON format is being sent and handles
// conversion if necessary. We can probably think about removing this function when we don't see origins/directors
// running Pelican <= v7.11.0.
func (c *Capabilities) UnmarshalJSON(data []byte) error {
// Check if it's the old format by looking for a unique field, e.g., "FallBackRead"
if strings.Contains(string(data), "FallBackRead") {
// Detected old JSON format, so unmarshal into OldCapabilities
var oldCaps OldCapabilities
if err := json.Unmarshal(data, &oldCaps); err != nil {
return err
}

// Map the old fields to the new struct
c.PublicReads = oldCaps.PublicRead
c.Reads = oldCaps.Read
c.Writes = oldCaps.Write
c.Listings = oldCaps.Listing
c.DirectReads = oldCaps.FallBackRead
} else {
// Assume it's the new JSON format and unmarshal directly into Capabilities
type Alias Capabilities // Create an alias to avoid recursive calls to UnmarshalJSON
var newCaps Alias
if err := json.Unmarshal(data, &newCaps); err != nil {
return err
}
*c = Capabilities(newCaps) // Copy unmarshalled values back to the original struct
}

return nil
}

func (x XPelNs) GetName() string {
return "X-Pelican-Namespace"
}
Expand Down
117 changes: 0 additions & 117 deletions server_structs/director_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
package server_structs

import (
"encoding/json"
"fmt"
"net/http"
"net/url"
Expand Down Expand Up @@ -282,119 +281,3 @@ func TestXPelTokGenParsing(t *testing.T) {
assert.Len(t, xPelTokGen.BasePaths, 0)
})
}

func TestCapsUnmarshalJSON(t *testing.T) {
oldCaps := `{"PublicRead":true,"Read":true,"Write":false,"Listing":false,"FallBackRead":true}}`
newCaps := `{"PublicReads":false,"Reads":true,"Writes":false,"Listings":false,"DirectReads":true}}`

nsAdV2NoCap := `{"path":"/ncar","token-generation":[{"strategy":"","vault-server":"","max-scope-depth":0,"issuer":{}}],"token-issuer":[],"from-topology":true,"Caps":`
oAdV2NoCap := `{"name": "example-server","registry-prefix": "/origins/example-server","broker-url": "http://example-broker.com","data-url": "http://example-data.com","web-url": "http://example-web.com","namespaces": [{"path": "/example-namespace","token-generation": [],"token-issuer": [],"from-topology": false}],"token-issuer": [],"storageType": "POSIX","directorTest": false,"capabilities":`
sAdV2NoCap := `{"name": "example-server","storageType": "POSIX","directorTest": false,"auth_url": {"Scheme": "http", "Host": "example-auth.com"},"broker_url": {"Scheme": "http", "Host": "example-auth.com"},"url": {"Scheme": "http", "Host": "example-auth.com"},"web_url": {"Scheme": "http", "Host": "example-auth.com"},"type": "cache","latitude": 40.7128,"longitude": -74.0060,"from_topology": true,"io_load": 0.75,"capabilities":`

tests := []struct {
name string
jsonData string
expected Capabilities
target interface{}
}{
{
name: "NamespaceAdV2 with old caps",
jsonData: nsAdV2NoCap + oldCaps,
expected: Capabilities{
PublicReads: true,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &NamespaceAdV2{},
},
{
name: "NamespaceAdV2 with new caps",
jsonData: nsAdV2NoCap + newCaps,
expected: Capabilities{
PublicReads: false,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &NamespaceAdV2{},
},
{
name: "OriginAdvertiseV2 with old caps",
jsonData: oAdV2NoCap + oldCaps,
expected: Capabilities{
PublicReads: true,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &OriginAdvertiseV2{},
},
{
name: "OriginAdvertiseV2 with new caps",
jsonData: oAdV2NoCap + newCaps,
expected: Capabilities{
PublicReads: false,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &OriginAdvertiseV2{},
},
{
name: "ServerAd with old caps",
jsonData: sAdV2NoCap + oldCaps,
expected: Capabilities{
PublicReads: true,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &ServerAd{},
},
{
name: "ServerAd with new caps",
jsonData: sAdV2NoCap + newCaps,
expected: Capabilities{
PublicReads: false,
Reads: true,
Writes: false,
Listings: false,
DirectReads: true,
},
target: &ServerAd{},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Unmarshal JSON into the appropriate struct
if err := json.Unmarshal([]byte(tt.jsonData), tt.target); err != nil {
t.Fatalf("UnmarshalJSON() error = %v", err)
}

// Check Caps field in the struct
switch v := tt.target.(type) {
case *NamespaceAdV2:
if v.Caps != tt.expected {
t.Errorf("NamespaceAdV2 Caps = %v, want %v", v.Caps, tt.expected)
}
case *OriginAdvertiseV2:
if v.Caps != tt.expected {
t.Errorf("OriginAdvertiseV2 Caps = %v, want %v", v.Caps, tt.expected)
}
case *ServerAd:
if v.Caps != tt.expected {
t.Errorf("ServerAd Caps = %v, want %v", v.Caps, tt.expected)
}
default:
t.Errorf("Unknown struct type: %T", tt.target)
}
})
}
}
Loading