panel

package
v0.7.2 Latest Latest
Warning

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

Go to latest
Published: Sep 29, 2026 License: AGPL-3.0 Imports: 65 Imported by: 0

Documentation

Overview

Package panel is the unprivileged half of Zelie: the web interface, its API and user accounts. It never listens on the network. The proxy hands it web traffic over a Unix socket, and it asks the core to do anything that needs root.

Index

Constants

This section is empty.

Variables

View Source
var ErrSetupDone = errors.New("an administrator exists already")

ErrSetupDone means an administrator exists, so there is no setup link.

Functions

This section is empty.

Types

type Client

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

Client talks to the panel's socket from the server itself.

func NewClient

func NewClient(socket string) *Client
func (c *Client) ResetLink(ctx context.Context, email string) (token, account string, err error)

ResetLink asks the panel for a reset link, for the account with email or the only administrator. It returns the token and whose it is.

func (c *Client) SetupLink(ctx context.Context) (string, error)

SetupLink asks the panel for a new setup token.

func (*Client) Version added in v0.2.0

func (c *Client) Version(ctx context.Context) (string, error)

Version asks the running panel which version it is.

type Core

type Core interface {
	List(ctx context.Context) ([]engine.Status, error)
	Run(ctx context.Context, s engine.Spec) error
	RunApp(ctx context.Context, s engine.Spec, sealedEnv []string, linked ...core.LinkedVar) (string, error)
	RunInstall(ctx context.Context, req core.InstallRequest) (string, error)
	PrepareVolume(ctx context.Context, name string, req core.PrepareRequest) (core.PrepareResponse, error)
	ListFiles(ctx context.Context, ref core.FileRef, dir string) (core.FileList, error)
	ReadFile(ctx context.Context, ref core.FileRef, path string) ([]byte, error)
	WriteFile(ctx context.Context, ref core.FileRef, path string, content []byte, create bool) error
	MakeFolder(ctx context.Context, ref core.FileRef, path string) error
	RenameFile(ctx context.Context, ref core.FileRef, from, to string) error
	DeleteFiles(ctx context.Context, ref core.FileRef, paths []string) error
	UploadFile(ctx context.Context, ref core.FileRef, path string, size int64, body io.Reader) error
	DownloadFile(ctx context.Context, ref core.FileRef, path string) (io.ReadCloser, int64, error)
	CompressFiles(ctx context.Context, ref core.FileRef, dir string, paths []string, name string) (string, error)
	ExtractFile(ctx context.Context, ref core.FileRef, path, dir string) (core.ExtractResult, error)
	WriteStdin(ctx context.Context, id string, data []byte) error
	Signal(ctx context.Context, id, signal string) error
	Pin(ctx context.Context, image string) (string, error)
	SetLinks(ctx context.Context, app string, links []engine.Link) error
	SetForwards(ctx context.Context, app string, forwards []engine.Forward) error
	ClearForwards(ctx context.Context, app string) error
	UsedPorts(ctx context.Context) ([]int, error)
	PublicAddress(ctx context.Context) (core.PublicAddress, error)
	Build(ctx context.Context, app, version string, env, sealedEnv []string, source io.Reader, out io.Writer) (build.Result, error)
	Wait(ctx context.Context, id string) (int, error)
	SecretKey(ctx context.Context) (secret.PublicKey, error)
	Stop(ctx context.Context, id string, graceSeconds int) error
	Remove(ctx context.Context, id string) error
	Logs(ctx context.Context, id string, follow bool, tail int64, w io.Writer) error
	RemoveImage(ctx context.Context, name string) error
	SweepImages(ctx context.Context, keep []string) ([]string, error)
	RemoveBuildCache(ctx context.Context, app string) error
	SetExternal(ctx context.Context, app, engine, container string, port, target int, sealedPassword string) error
	RemoveExternal(ctx context.Context, app, engine, container string) error
	SyncExternal(ctx context.Context, list []core.ExternalListener) error
	SetSFTPVolumes(ctx context.Context, names []string) error
	SetSFTPPort(ctx context.Context, port int) error
	SFTP(ctx context.Context) (core.SFTPStatus, error)
	UpdateStatus(ctx context.Context) (core.UpdateStatus, error)
	Update(ctx context.Context, version string) error
	Usage(ctx context.Context, id string) (engine.Usage, error)
	Host(ctx context.Context) (engine.Host, error)
	CreateVolume(ctx context.Context, name string) error
	RemoveVolume(ctx context.Context, name string) error
	VolumeSizes(ctx context.Context) (map[string]int64, error)
	CreateBackup(ctx context.Context, app, container, kind string) (core.Backup, error)
	DownloadBackup(ctx context.Context, app, name string, w io.Writer) error
	RemoveBackup(ctx context.Context, app, name string) error
	RestoreBackup(ctx context.Context, app, name, kind, container, volume string) error
	BackUpVolumes(ctx context.Context, app string, vols []core.VolumeRef, live bool) (core.Backup, error)
	RestoreVolumes(ctx context.Context, app, name string, vols []core.VolumeRef, size int64) error
	RecoveryKey(ctx context.Context, host string, w io.Writer) error
	Offsite(ctx context.Context) (core.OffsiteInfo, error)
	SetOffsite(ctx context.Context, cfg core.OffsiteConfig) (core.OffsiteInfo, error)
	RemoveOffsite(ctx context.Context) error
	UploadBackup(ctx context.Context, app, name string, meta core.BackupMeta) error
	OffsiteBackups(ctx context.Context) (core.OffsiteList, error)
	AddOldKey(ctx context.Context, recovery string) ([]string, error)
	RemoveOffsiteBackup(ctx context.Context, app, name string) error
	FetchBackup(ctx context.Context, app, name string) error
	StartUpload(ctx context.Context, app string, size int64) (core.Upload, error)
	Upload(ctx context.Context, id string) (core.Upload, error)
	AppendUpload(ctx context.Context, id string, offset int64, piece io.Reader) (core.Upload, error)
	RemoveUpload(ctx context.Context, id string) error
	ImportUpload(ctx context.Context, id, kind string) (core.Backup, error)
	DataTables(ctx context.Context, app, container, engine string) ([]dataview.Table, error)
	DataRows(ctx context.Context, app, container, engine string, q dataview.Query) (dataview.Page, error)
	DataExport(ctx context.Context, app, container, engine string, q dataview.Query, w io.Writer) error
	DataKeys(ctx context.Context, app, container, pattern, cursor string) (dataview.KeyPage, error)
	DataKey(ctx context.Context, app, container, key string) (dataview.Value, error)
}

Core is what the panel asks the privileged core to do. *core.Client implements it; tests use a fake.

type EggFetcher added in v0.6.0

type EggFetcher interface {
	// Catalog fetches an entry of the curated list.
	Catalog(ctx context.Context, e egg.Entry) (*egg.Egg, []byte, error)
	// URL fetches an egg from an https address.
	URL(ctx context.Context, address string) (*egg.Egg, []byte, error)
}

EggFetcher downloads egg files. Tests replace it; nil uses the real sources.

type Proxy

type Proxy interface {
	Config(ctx context.Context) (proxy.Config, error)
	Apply(ctx context.Context, cfg proxy.Config) error
	Stats(ctx context.Context) (proxy.Stats, error)
}

Proxy is how the panel tells the proxy where each domain goes.

type PublicGitHub

type PublicGitHub struct {
	Client   *http.Client
	API      string // https://api.github.com
	Codeload string // https://codeload.github.com
}

PublicGitHub reads public repositories without an account. Private ones need the GitHub connection.

func NewPublicGitHub

func NewPublicGitHub() *PublicGitHub

func (*PublicGitHub) Archive

func (g *PublicGitHub) Archive(ctx context.Context, repo, commit string) (io.ReadCloser, error)

func (*PublicGitHub) Resolve

func (g *PublicGitHub) Resolve(ctx context.Context, repo, branch string) (string, error)

type Registry added in v0.3.0

type Registry interface {
	Digest(ctx context.Context, ref string) (digest.Digest, error)
	Version(ctx context.Context, ref string) (string, error)
}

Registry answers what an image tag points at now. Tests replace it.

type Release added in v0.2.0

type Release struct {
	Version   string    `json:"version"`
	Notes     string    `json:"notes"`
	Published time.Time `json:"published"`
	URL       string    `json:"url"`
}

Release is a published version of Zelie.

func GitHubRelease added in v0.2.0

func GitHubRelease(ctx context.Context) (Release, error)

GitHubRelease reads the latest release from GitHub.

type Sealer

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

Sealer encrypts the panel's own secrets, such as authenticator app keys, before they go into the database. A copy of the database alone, from a backup for example, then does not give them away.

func LoadSealer

func LoadSealer(path string) (*Sealer, error)

LoadSealer reads the key at path, creating it on first start.

func (*Sealer) Open

func (s *Sealer) Open(sealed []byte, purpose string) ([]byte, error)

func (*Sealer) Seal

func (s *Sealer) Seal(plain []byte, purpose string) []byte

Seal encrypts plain. purpose is bound to the result, so a value sealed for one use cannot be passed off as another.

type Server

type Server struct {
	Store  *store.Store
	Sealer *Sealer
	Core   Core
	Proxy  Proxy
	Source Source
	Log    *slog.Logger
	// DataDir holds files that do not belong in the database, such as
	// deployment logs.
	DataDir string
	// SFTPUID is the user the SFTP service runs as; it returns 0 while
	// there is no such user. It is looked up on each request because the
	// service may be set up after the panel starts, by an update.
	SFTPUID func() uint32
	// ProxyUID is the user the proxy runs as. Requests from it are web
	// traffic; requests from root come from the zelie command on the server.
	ProxyUID uint32
	Now      func() time.Time
	// Where GitHub is. Empty means the real one; tests set them.
	GitHubAPI  string
	GitHubWeb  string
	GitHubHTTP *http.Client
	// HealthCheck replaces the HTTP request of the health check in tests.
	HealthCheck func(ctx context.Context, url, host string) (int, error)
	// Registry answers what image tags point at; nil asks the real ones.
	Registry Registry
	// Eggs downloads egg files; nil asks the real sources.
	Eggs EggFetcher
	// PortCheck replaces the connection a database's health check makes.
	PortCheck func(ctx context.Context, ip netip.Addr, port int) bool
	// PlayerCount replaces the query that counts the players of a game
	// server; nil asks the server itself.
	PlayerCount func(ctx context.Context, steamGame bool, addr netip.AddrPort) (int, error)

	// Releases returns the latest release; tests replace GitHub.
	Releases func(ctx context.Context) (Release, error)
	// contains filtered or unexported fields
}

func (*Server) Handler

func (s *Server) Handler() http.Handler

func (*Server) Serve

func (s *Server) Serve(ctx context.Context, socket string) error

Serve listens on the socket until ctx is cancelled.

type Source

type Source interface {
	// Resolve returns the commit a branch points at.
	Resolve(ctx context.Context, repo, branch string) (string, error)
	// Archive returns the code at a commit as a gzipped tar.
	Archive(ctx context.Context, repo, commit string) (io.ReadCloser, error)
}

Source fetches an app's code.

Jump to

Keyboard shortcuts

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