database

package
v0.0.0-...-44018a4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 15, 2026 License: Apache-2.0 Imports: 43 Imported by: 0

Documentation

Index

Constants

View Source
const (

	// naclNonceSize is the byte length of a NaCl box nonce.
	NaclNonceSize = 24
)

Variables

View Source
var (
	ErrForbidden = errors.New("forbidden")
	// ErrReservedGroupPrefix indicates a requested group name collides with the
	// reserved prefix used for automatically managed personal groups.
	ErrReservedGroupPrefix = errors.New("reserved group name prefix 'user-'")
)
View Source
var DirectorDB *gorm.DB
View Source
var EmbedOriginMigrations embed.FS
View Source
var EmbedRegistryMigrations embed.FS
View Source
var EmbedUniversalMigrations embed.FS
View Source
var ErrDatabaseExists = errors.New("database already exists at restore target")

ErrDatabaseExists is returned by RestoreFromSpecificBackup when the target database file already exists and force is false.

View Source
var ServerDatabase *gorm.DB

Functions

func AddCollectionMembers

func AddCollectionMembers(db *gorm.DB, id string, members []string, addedBy string, groups []string, isAdmin bool) error

func AddGroupMember

func AddGroupMember(db *gorm.DB, groupId, userId, addedByUserId string, isAdmin bool) error

func ClearMasterKeyRows

func ClearMasterKeyRows(ctx context.Context, db *gorm.DB) error

ClearMasterKeyRows removes all rows from server_master_keys.

func CreateBackup

func CreateBackup(ctx context.Context) error

CreateBackup creates a compressed and encrypted backup of the database. This is the exported entry point for the CLI.

func CreateCounter

func CreateCounter(key string, value int) error

func CreateDowntime

func CreateDowntime(downtime *server_structs.Downtime) error

CRUD operations for downtimes table Create a new downtime entry

func CreateOrUpdateCounter

func CreateOrUpdateCounter(key string, value int) error

func DecryptMasterKey

func DecryptMasterKey(encryptedBlob []byte, serverKey jwk.Key) ([]byte, error)

DecryptMasterKey decrypts a blob produced by EncryptMasterKey using the corresponding server private key.

func DeleteCollection

func DeleteCollection(db *gorm.DB, id string, owner string, groups []string, isAdmin bool) error

func DeleteCollectionMetadata

func DeleteCollectionMetadata(db *gorm.DB, id, user string, groups []string, key string, isAdmin bool) error

func DeleteDowntime

func DeleteDowntime(uuid string) error

Delete a downtime entry by UUID (hard delete)

func DeleteGroup

func DeleteGroup(db *gorm.DB, groupID, requestorUserID string, isAdmin bool) error

DeleteGroup deletes a group and cleans up any collection ACL entries that reference the group's name (ACLs store group names, not group slugs).

If isAdmin is false, only the group creator (CreatedBy) may delete the group.

func DeleteMasterKeyRows

func DeleteMasterKeyRows(ctx context.Context, db *gorm.DB, fingerprints []string) error

DeleteMasterKeyRows removes rows whose fingerprints are in the given list.

func DeleteUser

func DeleteUser(db *gorm.DB, userID, requestorUserID string, isAdmin bool) error

DeleteUser deletes a user and cleans up any collection ACL entries that reference the user's implicit personal group name ("user-"+username).

If isAdmin is false, only the user themselves may delete their account.

func DeriveSubKey

func DeriveSubKey(masterKey []byte, purpose string, length int) ([]byte, error)

DeriveSubKey derives a purpose-specific sub-key from the master key using HKDF-SHA256. The purpose string (HKDF "info") distinguishes different key usages, preventing one derived key from being usable in another context.

func EncryptMasterKey

func EncryptMasterKey(masterKey []byte, serverKey jwk.Key) ([]byte, error)

EncryptMasterKey encrypts the master key using a NaCl box derived from the given server private key. Returns nonce (24 bytes) || ciphertext.

func GetAllDowntimes

func GetAllDowntimes(source string) ([]server_structs.Downtime, error)

Retrieve all downtime entries

func GetDowntimeByUUID

func GetDowntimeByUUID(uuid string) (*server_structs.Downtime, error)

Retrieve a downtime entry by UUID

func GetIncompleteDowntimes

func GetIncompleteDowntimes(source string) ([]server_structs.Downtime, error)

Retrieve all downtime entries where EndTime is later than the current UTC time.

func GetServerLocalMetadata

func GetServerLocalMetadata() (server_structs.ServerLocalMetadata, error)

Retrieve the server local metadata in use - lookup the entry whose UpdatedAt is the most recent

func GetServerLocalMetadataHistory

func GetServerLocalMetadataHistory() ([]server_structs.ServerLocalMetadata, error)

Retrieve server local metadata history from most recent to oldest

func GrantCollectionAcl

func GrantCollectionAcl(db *gorm.DB, id, user string, groups []string, groupId string, role AclRole, expiresAt *time.Time, isAdmin bool) error

func InitServerDatabase

func InitServerDatabase(serverType server_structs.ServerType) error

Initialize a centralized server database and run universal and server-type-specific migrations

func InsertMockDowntime

func InsertMockDowntime(d server_structs.Downtime) error

func LaunchPeriodicBackup

func LaunchPeriodicBackup(ctx context.Context, egrp *errgroup.Group)

LaunchPeriodicBackup starts a background goroutine that periodically creates database backups. The goroutine is managed by the provided errgroup and cancellable via the context.

On startup, the function checks for existing backups. If none exist, one is created immediately. Otherwise, the first backup is scheduled based on the age of the most recent backup so that the configured frequency is maintained across restarts.

func LoadMasterKeyRows

func LoadMasterKeyRows(ctx context.Context, db *gorm.DB) (map[string][]byte, error)

LoadMasterKeyRows returns all rows from server_master_keys as a map[keyFingerprint] → encryptedBlob.

func LoadOrCreateMasterKey

func LoadOrCreateMasterKey(db *gorm.DB) ([]byte, error)

LoadOrCreateMasterKey loads the master key by decrypting any available row in server_master_keys using the server's private keys. If no rows exist (first start), a fresh 32-byte master key is generated. After loading or creating, the rows are synced to match the current set of server private keys so that key rotation is handled transparently.

func RemoveCollectionMembers

func RemoveCollectionMembers(db *gorm.DB, id string, members []string, user string, groups []string, isAdmin bool) error

func RemoveGroupMember

func RemoveGroupMember(db *gorm.DB, groupId, userId, removedByUserId string, isAdmin bool) error

func RestoreFromBackup

func RestoreFromBackup(dbPath string) (bool, error)

RestoreFromBackup restores the database from the most recent backup file if the primary database file is missing. This is the exported entry point used by InitServerDatabase.

func RestoreFromSpecificBackup

func RestoreFromSpecificBackup(dbPath, backupPath string, force bool) error

RestoreFromSpecificBackup restores the database from a specific backup file. If force is true, the existing database is backed up then overwritten. Returns an error if the database already exists and force is false.

func RevokeCollectionAcl

func RevokeCollectionAcl(db *gorm.DB, id, user string, groups []string, groupId string, role AclRole, isAdmin bool) error

func SaveMasterKeyRow

func SaveMasterKeyRow(ctx context.Context, db *gorm.DB, fingerprint string, encryptedKey []byte) error

SaveMasterKeyRow inserts or replaces an encrypted master key row.

func SetupMockDowntimeDB

func SetupMockDowntimeDB(t *testing.T)

Test helper functions for Downtime

func ShutdownDB

func ShutdownDB() error

func SoftDeleteServerLocalMetadata

func SoftDeleteServerLocalMetadata(id string) error

Mark a server local metadata as deleted without actually removing it from the database

func SyncMasterKeyRows

func SyncMasterKeyRows(db *gorm.DB, masterKey []byte, currentKeys map[string]jwk.Key) error

SyncMasterKeyRows ensures server_master_keys has exactly one row per current server private key, each containing the master key encrypted for that key. Rows for keys no longer present are removed.

All changes are made in a single database transaction so the table is never left in an inconsistent state. As a safety measure, if a sync would delete every existing row (implying all server keys were replaced at once), the deletion is skipped and an error is returned — the admin may still be able to recover a missing key file.

func TeardownMockDowntimeDB

func TeardownMockDowntimeDB(t *testing.T)

func UpdateCollection

func UpdateCollection(db *gorm.DB, id, user string, groups []string, name, description *string, visibility *Visibility, isAdmin bool) error

func UpdateDowntime

func UpdateDowntime(uuid string, updatedDowntime *server_structs.Downtime) error

Update an existing downtime entry by UUID

func UpdateGroup

func UpdateGroup(db *gorm.DB, id string, name, description *string, requestorUserID string, isAdmin bool) error

func UpdateUser

func UpdateUser(db *gorm.DB, id string, username, sub, issuer *string) error

func UpsertCollectionMetadata

func UpsertCollectionMetadata(db *gorm.DB, id, user string, groups []string, key, value string, isAdmin bool) error

func UpsertServerLocalMetadata

func UpsertServerLocalMetadata(metadata server_structs.ServerRegistration) error

Create or update a record to sync local server metadata with the Registry Server id is an unique 7 characters string randomly generated by the server itself during initial registration, consisting of [0-9a-z], e.g. 18f1jk5 Server name is a human-friendly name set by the admin via SiteName field in webUI or Xrootd.Sitename in local config during initial registration, e.g. "UW_OSDF_CACHE" 1) If no such row exists, it inserts a new one. 2) If a row with that server ID exists, it updates the existing entry.

func VerifyBackup

func VerifyBackup(backupPath string) error

VerifyBackup checks that a backup file can be successfully decrypted and decompressed without writing any data. Returns nil on success.

Types

type AclRole

type AclRole string
const (
	AclRoleRead  AclRole = "read"
	AclRoleWrite AclRole = "write"
	AclRoleOwner AclRole = "owner"
)

type BackupInfo

type BackupInfo struct {
	Name      string          `json:"name"`
	Path      string          `json:"path"`
	Size      int64           `json:"size"`
	Timestamp time.Time       `json:"timestamp"`
	Metadata  *BackupMetadata `json:"metadata,omitempty"`
}

BackupInfo holds metadata about a backup file, suitable for display in CLI listings.

func ListBackups

func ListBackups() ([]BackupInfo, error)

ListBackups returns metadata about all available backups in the configured backup directory, sorted newest-first.

type BackupMetadata

type BackupMetadata struct {
	// FormatVersion is the backup format version (currently "1").
	FormatVersion string `json:"format_version"`
	// Timestamp is the RFC3339 UTC time the backup was created.
	Timestamp string `json:"timestamp"`
	// Hostname is the hostname of the machine that created the backup.
	Hostname string `json:"hostname,omitempty"`
	// Username is the OS user that created the backup.
	Username string `json:"username,omitempty"`
	// PelicanVersion is the version of Pelican that created the backup.
	PelicanVersion string `json:"pelican_version"`
	// ServerURL is the external web URL of the server, if configured.
	ServerURL string `json:"server_url,omitempty"`
	// DatabasePath is the path to the database that was backed up.
	DatabasePath string `json:"database_path,omitempty"`
	// GOOS is the operating system (e.g., "linux", "darwin").
	GOOS string `json:"goos"`
	// GOARCH is the architecture (e.g., "amd64", "arm64").
	GOARCH string `json:"goarch"`
}

BackupMetadata contains human-readable information about a backup file. These fields are stored as PEM headers in the first block of the backup file and are visible even without decryption keys.

func ReadBackupMetadata

func ReadBackupMetadata(backupPath string) (*BackupMetadata, error)

ReadBackupMetadata reads the metadata from a backup file at the given path. It returns nil (without error) for older backup files that lack a metadata block.

type Collection

type Collection struct {
	ID          string               `gorm:"primaryKey" json:"id"`
	Name        string               `gorm:"not null;uniqueIndex:idx_owner_name" json:"name"`
	Description string               `json:"description"`
	Owner       string               `gorm:"not null;uniqueIndex:idx_owner_name" json:"owner"`
	Namespace   string               `gorm:"not null" json:"namespace"`
	Visibility  Visibility           `gorm:"not null;default:private" json:"visibility"`
	CreatedAt   time.Time            `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
	UpdatedAt   time.Time            `gorm:"not null;default:CURRENT_TIMESTAMP" json:"updatedAt"`
	Members     []CollectionMember   `gorm:"foreignKey:CollectionID" json:"members"`
	ACLs        []CollectionACL      `gorm:"foreignKey:CollectionID" json:"acls"`
	Metadata    []CollectionMetadata `gorm:"foreignKey:CollectionID" json:"metadata"`
}

func CreateCollection

func CreateCollection(db *gorm.DB, name, description, owner, namespace string, visibility Visibility) (*Collection, error)

func CreateCollectionWithMetadata

func CreateCollectionWithMetadata(db *gorm.DB, name, description, owner, namespace string, visibility Visibility, metadata map[string]string) (*Collection, error)

func GetAllCollections

func GetAllCollections(db *gorm.DB) ([]Collection, error)

func GetCollection

func GetCollection(db *gorm.DB, id string, user string, groups []string) (*Collection, error)

func ListCollections

func ListCollections(db *gorm.DB, user string, groups []string) ([]Collection, error)

type CollectionACL

type CollectionACL struct {
	CollectionID string     `gorm:"primaryKey" json:"collectionId"`
	GroupID      string     `gorm:"primaryKey" json:"groupId"`
	Role         AclRole    `gorm:"primaryKey;not null" json:"role"`
	GrantedBy    string     `gorm:"not null" json:"createdBy"`
	GrantedAt    time.Time  `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
	ExpiresAt    *time.Time `json:"expiresAt"`
}

func GetCollectionAcls

func GetCollectionAcls(db *gorm.DB, id, user string, groups []string) ([]CollectionACL, error)

type CollectionMember

type CollectionMember struct {
	CollectionID string    `gorm:"primaryKey" json:"collectionId"`
	ObjectURL    string    `gorm:"primaryKey" json:"objectUrl"` // full pelican:// URL
	AddedBy      string    `gorm:"not null" json:"createdBy"`
	AddedAt      time.Time `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
}

func GetCollectionMembers

func GetCollectionMembers(db *gorm.DB, id, user string, groups []string, since *time.Time, limit int) ([]CollectionMember, error)

type CollectionMetadata

type CollectionMetadata struct {
	CollectionID string `gorm:"primaryKey" json:"collectionId"`
	Key          string `gorm:"primaryKey;not null" json:"key"`
	Value        string `gorm:"not null" json:"value"`
}

func GetCollectionMetadata

func GetCollectionMetadata(db *gorm.DB, id, user string, groups []string) ([]CollectionMetadata, error)

type Counter

type Counter struct {
	Key   string `gorm:"primaryKey"`
	Value int    `gorm:"not null;default:0"`
}

type ErrNoMatchingKey

type ErrNoMatchingKey struct {
	RequiredKeyIDs []string
}

ErrNoMatchingKey is returned when a backup cannot be decrypted because none of the currently-available issuer keys match the keys used to encrypt the backup. The RequiredKeyIDs field lists the key IDs that the backup was encrypted with.

func (*ErrNoMatchingKey) Error

func (e *ErrNoMatchingKey) Error() string

type Group

type Group struct {
	ID          string        `gorm:"primaryKey" json:"id"`
	Name        string        `gorm:"not null;unique" json:"name"`
	Description string        `json:"description"`
	CreatedBy   string        `gorm:"not null" json:"createdBy"`
	CreatedAt   time.Time     `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
	Members     []GroupMember `gorm:"foreignKey:GroupID" json:"members"`
}

func CreateGroup

func CreateGroup(db *gorm.DB, name, description, createdByUserID string, groups []string) (*Group, error)

func GetGroupWithMembers

func GetGroupWithMembers(db *gorm.DB, groupId string) (*Group, error)

func GetMemberGroups

func GetMemberGroups(db *gorm.DB, userId string) ([]Group, error)

func ListGroups

func ListGroups(db *gorm.DB) ([]Group, error)

type GroupMember

type GroupMember struct {
	GroupID string    `gorm:"primaryKey" json:"groupId"`
	UserID  string    `gorm:"primaryKey" json:"userId"`
	User    User      `gorm:"foreignKey:UserID" json:"user"`
	AddedBy string    `gorm:"not null" json:"createdBy"`
	AddedAt time.Time `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
}

type User

type User struct {
	ID        string    `gorm:"primaryKey" json:"id"`
	Username  string    `gorm:"not null;uniqueIndex:idx_user_issuer" json:"username"`
	Sub       string    `gorm:"not null;uniqueIndex:idx_user_sub_issuer" json:"sub"`
	Issuer    string    `gorm:"not null;uniqueIndex:idx_user_issuer;uniqueIndex:idx_user_sub_issuer" json:"issuer"`
	CreatedAt time.Time `gorm:"not null;default:CURRENT_TIMESTAMP" json:"createdAt"`
}

func CreateUser

func CreateUser(db *gorm.DB, username string, sub string, issuer string) (*User, error)

func GetOrCreateUser

func GetOrCreateUser(db *gorm.DB, username string, sub string, issuer string) (*User, error)

func GetUserByID

func GetUserByID(db *gorm.DB, id string) (*User, error)

func GetUserByUsername

func GetUserByUsername(db *gorm.DB, username string) (*User, error)

func ListUsers

func ListUsers(db *gorm.DB) ([]User, error)

type Visibility

type Visibility string
const (
	VisibilityPrivate Visibility = "private"
	VisibilityPublic  Visibility = "public"
)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL