storage

package
v0.9.3 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: BSD-3-Clause-Clear Imports: 27 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Global files/dirs
	AuditDir    = "audit"
	AuthDir     = "auth"
	BrandingDir = "branding"
	CertsDir    = "certs"
	ConfigsDir  = "configs"
	DbFile      = "db.sqlite"
	DevicesDir  = "devices"
	UpdatesDir  = "updates"
	TufDir      = "tuf"

	CertsCasPemFile = "cas.pem"
	CertsTlsCsrFile = "tls.csr"
	CertsTlsKeyFile = "tls.key"
	CertsTlsPemFile = "tls.pem"

	CertsRootKeyFile     = "root.key"
	CertsRootPemFile     = "root.crt"
	CertsDeviceCaKeyFile = "device-ca.key"
	CertsDeviceCaPemFile = "device-ca.crt"

	AuthConfigFile     = "auth-config.json"
	BrandingConfigFile = "branding.json"
	HmacFile           = "hmac.secret"

	// Per config class files/dirs
	ConfigsFactoryDir  = "factory"
	ConfigsGroupDir    = "group"
	ConfigsDeviceDir   = "device"
	ConfigsJournalFile = ".journal"
	ConfigSotaOverride = "z-50-fioctl.toml"

	// Per device files/dirs
	ConfigAppliedFile   = "config-applied"
	AktomlFile          = "aktoml"
	HwInfoFile          = "hardware-info"
	NetInfoFile         = "network-info"
	EventsPrefix        = "events"
	StatesPrefix        = "apps-states"
	TestsPrefix         = "tests"
	TestArtifactsPrefix = "test-artifacts"

	// Per update files/dirs
	// Update categories
	UpdatesTufDir      = "tuf"
	UpdatesOstreeDir   = "ostree_repo"
	UpdatesAppsDir     = "apps"
	UpdatesRolloutsDir = "rollouts"
	UpdatesLogsDir     = "logs"
	// TUF category files
	TufRootFile      = "root.json"
	TufTimestampFile = "timestamp.json"
	TufSnapshotFile  = "snapshot.json"
	TufTargetsFile   = "targets.json"
	// Logs category files
	LogRolloutsFile = "rollouts.log"
)

Variables

View Source
var (
	ErrDbConstraintUnique = sqllite.ErrConstraintUnique
	ErrUpdateInUse        = errors.New("update is referenced by one or more devices")
)
View Source
var ErrInvalidUpdate = errors.New("invalid update archive")
View Source
var ErrTufAlreadyInitialized = errors.New("TUF is already initialized")

ErrTufAlreadyInitialized is returned by InitTuf when TUF data already exists.

View Source
var ErrTufNotInitialized = errors.New("TUF is not initialized")

ErrTufNotInitialized is returned when TUF operations are attempted before the TUF metadata and keys have been created with InitTuf.

View Source
var TestIdRegex = regexp.MustCompile(`^[A-Za-z0-9\-\_]{15,48}$`)
View Source
var ValidCorrelationId = regexp.MustCompile(`^[a-zA-Z0-9_\-]+$`).MatchString

Functions

func AbsPathNoEscape

func AbsPathNoEscape(root, path string) (absPath string, err error)

func IsDbError

func IsDbError(err error, code sqllite.ErrNoExtended) bool

func LoadPemFile added in v0.9.3

func LoadPemFile[T any](path string, parse func([]byte) (T, error)) (T, error)

func PemBytesToObject added in v0.9.3

func PemBytesToObject[T any](pemBytes []byte, parse func([]byte) (T, error)) (T, error)

Types

type AppliedConfigs

type AppliedConfigs struct {
	Files      map[string]ConfigFile `json:"Files"`
	AppliedAt  int64                 `json:"AppliedAt"`
	AuditTrail [3]struct {
		// global, group, and device audit fields.
		CreatedAt int64  `json:"CreatedAt,omitempty"`
		CreatedBy string `json:"CreatedBy,omitempty"`
		Reason    string `json:"Reason,omitempty"`
		Auxiliary string `json:"Auxiliary,omitempty"`
	} `json:"AuditTrail"`
}

AppliedConfigs wraps the merged config sent to a device along with the Unix timestamp (seconds) at which it was delivered.

type AppsStates

type AppsStates struct {
	DeviceTime string `json:"deviceTime"`
	Ostree     string `json:"ostree"`
	Apps       map[string]struct {
		Uri      string `json:"uri"`
		State    string `json:"state"`
		Services []struct {
			Name     string `json:"name"`
			Hash     string `json:"hash"`
			Health   string `json:"health,omitempty"`
			ImageUri string `json:"image"`
			Logs     string `json:"logs,omitempty"`
			State    string `json:"state"`
			Status   string `json:"status"`
		} `json:"services"`
	} `json:"apps"`
}

type AuditLogsFsHandle

type AuditLogsFsHandle struct {
	// contains filtered or unexported fields
}

func (AuditLogsFsHandle) AppendEvent

func (h AuditLogsFsHandle) AppendEvent(userid int64, event string)

func (AuditLogsFsHandle) ReadEvents

func (h AuditLogsFsHandle) ReadEvents(userid int64) (string, error)

type AuthConfig

type AuthConfig struct {
	Type                 string
	SessionTimeoutHours  int // Default is 48 hours
	NewUserDefaultScopes []string
	RateLimits           RateLimitConfig
	Config               json.RawMessage
}

type AuthFsHandle

type AuthFsHandle struct {
	// contains filtered or unexported fields
}

func (AuthFsHandle) GetAuthConfig

func (h AuthFsHandle) GetAuthConfig() (*AuthConfig, error)

GetAuthConfig returns the settings for how authorization is configured.

func (AuthFsHandle) GetHmacSecret

func (h AuthFsHandle) GetHmacSecret() ([]byte, error)

func (AuthFsHandle) InitHmacSecret

func (h AuthFsHandle) InitHmacSecret() error

func (AuthFsHandle) SaveAuthConfig

func (h AuthFsHandle) SaveAuthConfig(cfg AuthConfig) error

type CertsFsHandle

type CertsFsHandle struct {
	// contains filtered or unexported fields
}

func (CertsFsHandle) AssertCleanPki added in v0.9.3

func (s CertsFsHandle) AssertCleanPki() error

func (CertsFsHandle) AssertCleanTls

func (s CertsFsHandle) AssertCleanTls() error

func (CertsFsHandle) FilePath

func (s CertsFsHandle) FilePath(name string) string

func (CertsFsHandle) ReadFile

func (s CertsFsHandle) ReadFile(name string) ([]byte, error)

func (CertsFsHandle) WriteFile

func (s CertsFsHandle) WriteFile(name string, content []byte) error

type ConfigFile

type ConfigFile struct {
	Value       string   `json:"Value"`
	Unencrypted bool     `json:"Unencrypted,omitempty"`
	OnChanged   []string `json:"OnChanged,omitempty"`
}

type ConfigFileSet

type ConfigFileSet struct {
	// Storage returns RawFiles, but API returns parsed Files.
	RawFiles  string                `json:"-"`
	Files     map[string]ConfigFile `json:"Files"`
	Reason    string                `json:"Reason,omitempty"`
	CreatedAt int64                 `json:"CreatedAt,omitempty"`
	CreatedBy string                `json:"CreatedBy,omitempty"`
}

type ConfigsFsHandle

type ConfigsFsHandle struct {
	// contains filtered or unexported fields
}

func (ConfigsFsHandle) PurgeDeviceConfigHistory

func (s ConfigsFsHandle) PurgeDeviceConfigHistory(uuid string, keepLatest int) error

func (ConfigsFsHandle) PurgeFactoryConfigHistory

func (s ConfigsFsHandle) PurgeFactoryConfigHistory(keepLatest int) error

func (ConfigsFsHandle) PurgeGroupConfigHistory

func (s ConfigsFsHandle) PurgeGroupConfigHistory(name string, keepLatest int) error

func (ConfigsFsHandle) ReadDeviceConfigHistory

func (s ConfigsFsHandle) ReadDeviceConfigHistory(uuid string, latest int, withFiles bool) (history []*ConfigFileSet, err error)

func (ConfigsFsHandle) ReadFactoryConfigHistory

func (s ConfigsFsHandle) ReadFactoryConfigHistory(latest int, withFiles bool) (history []*ConfigFileSet, err error)

func (ConfigsFsHandle) ReadGroupConfigHistory

func (s ConfigsFsHandle) ReadGroupConfigHistory(name string, latest int, withFiles bool) (history []*ConfigFileSet, err error)

func (ConfigsFsHandle) ReadGroupNames

func (s ConfigsFsHandle) ReadGroupNames() ([]string, error)

func (ConfigsFsHandle) SaveUpload

func (s ConfigsFsHandle) SaveUpload(payload io.Reader, onCleanupFailure func(error)) error

func (ConfigsFsHandle) WriteDeviceConfig

func (s ConfigsFsHandle) WriteDeviceConfig(uuid, content, username, reason string) error

func (ConfigsFsHandle) WriteFactoryConfig

func (s ConfigsFsHandle) WriteFactoryConfig(content, username, reason string) error

func (ConfigsFsHandle) WriteGroupConfig

func (s ConfigsFsHandle) WriteGroupConfig(name, content, username, reason string) error

type DbHandle

type DbHandle struct {
	// contains filtered or unexported fields
}

func NewDb

func NewDb(dbfile string) (*DbHandle, error)

func (DbHandle) Close

func (d DbHandle) Close() error

func (DbHandle) InitStmt

func (d DbHandle) InitStmt(stmt ...DbStmtInit) (err error)

func (DbHandle) Prepare

func (d DbHandle) Prepare(name, query string) (stmt *sql.Stmt, err error)

type DbStmt

type DbStmt struct {
	Stmt *sql.Stmt
}

type DbStmtInit

type DbStmtInit interface {
	Init(db DbHandle) error
}

type DeviceEvent

type DeviceEvent struct {
	CorrelationId string `json:"correlationId"`
	Ecu           string `json:"ecu"`
	Success       *bool  `json:"success,omitempty"`
	TargetName    string `json:"targetName"`
	Version       string `json:"version"`
	Details       string `json:"details,omitempty"`
}

type DeviceEventType

type DeviceEventType struct {
	Id      string `json:"id"`
	Version int    `json:"version"`
}

type DeviceStatus

type DeviceStatus struct {
	Uuid          string `json:"uuid"`
	CorrelationId string `json:"correlationId"`
	TargetName    string `json:"target-name"`
	Status        string `json:"status"`
	DeviceTime    string `json:"deviceTime"`
}

type DeviceUpdateEvent

type DeviceUpdateEvent struct {
	Id         string          `json:"id"`
	DeviceTime string          `json:"deviceTime"`
	Event      DeviceEvent     `json:"event"`
	EventType  DeviceEventType `json:"eventType"`
}

DeviceUpdateEvent represents update events that devices send the device-gateway.

func (DeviceUpdateEvent) ParseStatus

func (e DeviceUpdateEvent) ParseStatus() DeviceStatus

type DevicesFsHandle

type DevicesFsHandle struct {
	// contains filtered or unexported fields
}

func (DevicesFsHandle) AppendFile

func (s DevicesFsHandle) AppendFile(uuid, name, content string) error

func (DevicesFsHandle) Delete

func (s DevicesFsHandle) Delete(uuid string) error

func (DevicesFsHandle) ListFiles

func (s DevicesFsHandle) ListFiles(uuid, prefix string, sortByModTime bool) ([]string, error)

func (DevicesFsHandle) ReadFile

func (s DevicesFsHandle) ReadFile(uuid, name string) (string, error)

func (DevicesFsHandle) ReadFileStream

func (s DevicesFsHandle) ReadFileStream(uuid string, name string) (io.ReadCloser, error)

func (DevicesFsHandle) RolloverFiles

func (s DevicesFsHandle) RolloverFiles(uuid, prefix string, max int) error

func (DevicesFsHandle) WriteFile

func (s DevicesFsHandle) WriteFile(uuid, name, content string) error

func (DevicesFsHandle) WriteFileStream

func (s DevicesFsHandle) WriteFileStream(uuid, name string, src io.Reader) error

type DoneChan

type DoneChan = <-chan struct{} // Dictated by Context.Done

type ErrConfigUploadBroken

type ErrConfigUploadBroken struct {
	UploadPath  string
	ConfigsPath string
	// contains filtered or unexported fields
}

func (ErrConfigUploadBroken) Error

func (e ErrConfigUploadBroken) Error() string

type FsConfig

type FsConfig string

func (FsConfig) AuditDir

func (c FsConfig) AuditDir() string

func (FsConfig) AuthDir

func (c FsConfig) AuthDir() string

func (FsConfig) BrandingDir

func (c FsConfig) BrandingDir() string

BrandingDir is the directory operators drop branding.json and assets into.

func (FsConfig) CertsDir

func (c FsConfig) CertsDir() string

func (FsConfig) ConfigsDir

func (c FsConfig) ConfigsDir() string

func (FsConfig) DbFile

func (c FsConfig) DbFile() string

func (FsConfig) DevicesDir

func (c FsConfig) DevicesDir() string

func (FsConfig) ReadBrandingConfig

func (c FsConfig) ReadBrandingConfig() ([]byte, error)

ReadBrandingConfig returns the raw bytes of branding.json, or (nil, nil) when the file does not exist — an absent file means "use built-in defaults".

func (FsConfig) RootDir

func (c FsConfig) RootDir() string

func (FsConfig) TufDir

func (c FsConfig) TufDir() string

func (FsConfig) UpdatesDir

func (c FsConfig) UpdatesDir() string

type FsHandle

type FsHandle struct {
	Config FsConfig

	Audit   AuditLogsFsHandle
	Auth    AuthFsHandle
	Certs   CertsFsHandle
	Configs ConfigsFsHandle
	Devices DevicesFsHandle
	Updates updatesFsHandleWrap
	Tuf     TufFsHandle
}

func NewFs

func NewFs(root string) (*FsHandle, error)

type RateLimitConfig

type RateLimitConfig struct {
	AttemptsPerSecond        int
	AttemptsBlockDurationSec int
	BadAuthLimit             int
	BadAuthBlockDurationSec  int
}

type RolloutsFsHandle

type RolloutsFsHandle struct {
	UpdatesFsHandle
}

func (RolloutsFsHandle) AppendJournal

func (s RolloutsFsHandle) AppendJournal(content string) error

func (RolloutsFsHandle) ListFiles

func (s RolloutsFsHandle) ListFiles(tag, update string) ([]string, error)

func (RolloutsFsHandle) ReadJournal

func (s RolloutsFsHandle) ReadJournal() iter.Seq2[string, error]

func (RolloutsFsHandle) RolloverJournal

func (s RolloutsFsHandle) RolloverJournal() (err error)

type TarHeader

type TarHeader = tar.Header

type TarUnpackOption

type TarUnpackOption func(tarUnpackConfig) tarUnpackConfig

func TarUnpackCreateDest

func TarUnpackCreateDest(val bool) TarUnpackOption

func TarUnpackDirAccess

func TarUnpackDirAccess(mode os.FileMode) TarUnpackOption

func TarUnpackFileAccess

func TarUnpackFileAccess(mode os.FileMode) TarUnpackOption

func TarUnpackMergeDest

func TarUnpackMergeDest(val bool) TarUnpackOption

func TarUnpackOnEvents

func TarUnpackOnEvents(val tarUnpackEvents) TarUnpackOption

func TarUnpackReplaceDest

func TarUnpackReplaceDest(val bool) TarUnpackOption

func TarUnpackUseTmpDir

func TarUnpackUseTmpDir(val string) TarUnpackOption

Use temporary directory to unpack files instead of unpacking directory into the destination. A temporary directory is then moved to destination in a two-phase commit.

func TarUnpackUseTmpFile

func TarUnpackUseTmpFile(val string) TarUnpackOption

Use temporary file for a tarball instead of processing it in memory. This allows to read the file from network faster, minimizing a chance for errors and network stack conservation.

type TargetTest

type TargetTest struct {
	Uuid        string             `json:"uuid"`
	Name        string             `json:"name"`
	TargetName  string             `json:"target_name"`
	Status      string             `json:"status"`
	CreatedOn   int64              `json:"created_on"`
	CompletedOn *int64             `json:"completed_on"`
	Details     string             `json:"details,omitempty"`
	Artifacts   []string           `json:"artifacts,omitempty"`
	Results     []TargetTestResult `json:"results,omitempty"`
}

type TargetTestResult

type TargetTestResult struct {
	Name    string             `json:"name"`
	Status  string             `json:"status"`
	LocalTs float64            `json:"local_ts"`
	Details string             `json:"details"`
	Metrics map[string]float64 `json:"metrics"`
}

type TufFsHandle

type TufFsHandle struct {

	// RootExpiration is the validity period used for newly created root.json.
	RootExpiration time.Duration
	// TimestampExpiration is the validity period for timestamp metadata.
	TimestampExpiration time.Duration
	// TargetsExpiration is the validity period for targets metadata; snapshot
	// metadata uses the same value.
	TargetsExpiration time.Duration
	// contains filtered or unexported fields
}

TufFsHandle manages TUF keys and metadata stored under <datadir>/tuf.

func (TufFsHandle) Enabled

func (h TufFsHandle) Enabled() bool

Enabled reports whether TUF signing is available, i.e. LoadTuf has loaded the role keys.

func (TufFsHandle) GetRoots

func (h TufFsHandle) GetRoots() ([]tuf.AtsTufRoot, error)

GetRoots returns every root.json file on disk, unmarshalled and ordered by ascending version.

func (TufFsHandle) ImportTuf

func (h TufFsHandle) ImportTuf(rootJSONs [][]byte, candidateKeys []tuf.AtsKey) error

ImportTuf initializes TUF for this server by migrating from an existing fioctl/ota-tuf setup.

rootJSONs are the raw bytes of every known root.json version. candidateKeys are the private keys extracted from a fioctl offline keys tarball, including the offline private key(s) for the root role. Every imported root.json is stored verbatim, fresh online keys are generated for every role, and a new root.json (version = highest imported version + 1) is created and signed by both the imported (old) root key(s) and the newly generated root key so that clients can verify the chain of trust from the previously trusted root.

It fails if TUF data already exists.

func (TufFsHandle) InitTuf

func (h TufFsHandle) InitTuf() error

InitTuf creates the TUF role keys (root, targets, snapshot, timestamp), an initial root.json, and stores the private keys encrypted with a key derived from the HMAC secret. It fails if TUF data already exists.

func (*TufFsHandle) LoadTuf

func (h *TufFsHandle) LoadTuf() error

LoadTuf loads and decrypts the role private keys into the handle. It returns ErrTufNotInitialized if TUF has not been initialized.

func (TufFsHandle) ReadRoot

func (h TufFsHandle) ReadRoot(version int) ([]byte, error)

ReadRoot returns the raw JSON bytes of a root metadata file. A version <= 0 returns the latest (highest version) root metadata. It returns an error that wraps os.ErrNotExist when the requested root does not exist.

func (TufFsHandle) ReadTufMeta

func (h TufFsHandle) ReadTufMeta(tag, update, name string, v any) error

ReadTufMeta reads and unmarshals a TUF metadata file from an update.

func (TufFsHandle) Sign

func (h TufFsHandle) Sign(role tuf.RoleName, v any) (tuf.Signature, error)

func (TufFsHandle) WriteMeta

func (h TufFsHandle) WriteMeta(tufDir string, targets, snapshot, timestamp []byte) error

func (TufFsHandle) WriteTimestamp

func (h TufFsHandle) WriteTimestamp(tag, update string, ts []byte) error

type Update

type Update struct {
	Name       string `json:"name"`
	UploadedAt int64  `json:"uploaded-at"`
	UploadedBy string `json:"uploaded-by"`

	DeviceCount int `json:"device-count"`
}

type UpdatesFsHandle

type UpdatesFsHandle struct {
	// contains filtered or unexported fields
}

func (UpdatesFsHandle) AppendFile

func (s UpdatesFsHandle) AppendFile(tag, update, name, content string) error

func (UpdatesFsHandle) FilePath

func (s UpdatesFsHandle) FilePath(tag, update, name string) string

func (UpdatesFsHandle) LatestRootMetaName

func (s UpdatesFsHandle) LatestRootMetaName(tag, update string) (string, error)

func (UpdatesFsHandle) ReadFile

func (s UpdatesFsHandle) ReadFile(tag, update, name string) (string, error)

func (UpdatesFsHandle) TailFileLines

func (s UpdatesFsHandle) TailFileLines(tag, update, name string, stop DoneChan) iter.Seq2[string, error]

func (UpdatesFsHandle) WriteFile

func (s UpdatesFsHandle) WriteFile(tag, update, name, content string) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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