Help us shape the future of Go! Take the 2026 Go Developer Survey

session

package
v0.4.2 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Overview

A session's Dev Tunnel is part of the session state machine: deterministic ports, requested lifetime, remote Dev Tunnel validation, compensation, and the private per-run tokens all derive from session identity and state. The Dev Tunnels manager supplies vendor operations and DevtunnelCredentials supplies the owner's connected account; no other subsystem owns or persists session lifecycle state. A defined session that never ran has `seq` 0 and no tokens; a run's tokens are the Jupyter and link tokens plus, with the devtunnel transport, the connect token.

Session run history owns bounded process-local logs and usage samples, remote collection, and the durable runs. Logs are sanitized before storage, while usage and Slurm accounting remain principal-scoped remote operations. A run freezes when its session ends; accounting may arrive after termination. Incomplete runs are retried for a bounded window without changing run identity or blocking samples.

The session state machine. Define records a stopped session under an ID derived from the idempotency key, so a replay answers it. Start launches a run through Slurm, serialized across processes before Dev Tunnel side effects, and persists intent before provisioning. A conclusive submission failure compensates through abandonSubmitIntent; an ambiguous one stays durable. A stop proceeds locally without a usable link, and reads the Dev Tunnels account only for a session that has a Dev Tunnel. Attach admits a run the client launches itself, which cs-plane never schedules or cancels.

Session traffic. A session's Linkspan dials out and holds one WebSocket, authenticated by the per-run link token only cs-plane and whoever started the job hold; each stream is a yamux channel on which cs-plane writes the port in two bytes and Linkspan answers 1 carried or 0 refused. A Dev Tunnel, through Linkspan's forward route, is the fallback. HTTP into a job dials the address <id>.<seq>.session, which pools connections per run. Forward and the Jupyter proxy sit outside the bearer boundary under the shared origin policy, opened by the Jupyter token compared in constant time; a CORS preflight passes through. A link for the current run makes it READY.

Linkspan's launch contract, owned here so the rest of preparation never spells its CLI: the release floor, the transports a session may select, the flags a session job execs Linkspan with for them, and the sbatch exports those flags read. The flags reference exported variables rather than values so the script text stays free of secrets and per-run identity; the link and Dev Tunnel host tokens reach Linkspan only through its own environment names, and each is exported only when its transport is selected.

Session and run persistence belongs to the session subsystem. Rows hold the nested lifecycle values as JSON text beside explicit owner and identity columns for principal isolation and stable composite keys. Writes keep the in-memory mutation model: each cycle loads state under the process-wide lock and replaces both tables in one transaction, so a read is one unlocked statement that sees a whole cycle or none of it. Queries in query.sql are generated into query.sql.go by sqlc.

Session preparation validates public requests against discovered Slurm resources and resolves the root folder. It builds the Linkspan workflow and job script, then performs bounded provisioning and submission operations. Validate narrates into a throwaway log so a dry run never writes into a session's visible log tail. Slurm framing and parsing live in internal/slurm; session policy and API error mapping remain here. Secrets are composed only at the final submission boundary.

Scheduler reconciliation folds neutral Slurm observations into sessions grouped by principal and SSH host. Slurm vocabulary and wire parsing stay in internal/slurm; this file owns session-state and walltime policy. Silence is not evidence, so a session with no observation stays put until its propagation window expires. Foreground and background refreshes share one serialized, rate-limited service runtime. A run is READY once its link connects; a running job's log tail is the READY signal only without a link. Client-launched sessions are never observed or accounted; a stop retires them locally, and one with a Dev Tunnel is READY once Linkspan answers its health route.

Package session owns session orchestration and its HTTP surface. RunnerProvider supplies principal-scoped SSH execution, while DevtunnelCredentials supplies connected Dev Tunnels accounts; sessions owns the resulting state, Dev Tunnel, run history, and run lifecycles. Every exported operation takes the acting principal explicitly and checks ownership itself, so it is usable without HTTP; Routes are one-line adapters over those operations.

Index

Constants

View Source
const DefaultLinkspanPath = "$HOME/.cybershuttle/bin/linkspan"

Variables

View Source
var Schema string

Functions

This section is empty.

Types

type AttachResponse

type AttachResponse struct {
	Session   SessionResponse  `json:"session"`
	Port      uint16           `json:"port"`
	Link      *LinkAccess      `json:"link,omitempty"`
	Devtunnel *DevtunnelAccess `json:"devtunnel,omitempty"`
}

type Config

type Config struct {
	Runners              RunnerProvider
	Store                Store
	LinkspanPath         string
	DevtunnelManager     DevtunnelManager
	DevtunnelCredentials DevtunnelCredentials
	TokenDir             string
	PublicURL            string
	UpstreamTimeout      time.Duration
	Origins              security.Origins
}

type CreateRequest

type CreateRequest struct {
	ID             string    `json:"-"`
	IdempotencyKey string    `json:"idempotencyKey,omitempty"`
	Alias          string    `json:"alias"`
	Account        string    `json:"account,omitempty"`
	Partition      string    `json:"partition"`
	RootFolder     string    `json:"rootFolder"`
	Resources      Resources `json:"resources"`
	TunnelModes    []string  `json:"tunnelModes,omitempty"`
}

type DBTX

type DBTX interface {
	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
	PrepareContext(context.Context, string) (*sql.Stmt, error)
	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}

type DevtunnelAccess

type DevtunnelAccess struct {
	ID        string `json:"id"`
	Cluster   string `json:"cluster"`
	HostToken string `json:"hostToken"`
}

type DevtunnelCredentials

type DevtunnelCredentials interface {
	Credential(context.Context, security.Principal) (devtunnel.Credential, error)
}

type GPUSample

type GPUSample struct {
	Index       int `json:"index"`
	UtilPct     int `json:"utilPct"`
	MemUsedMiB  int `json:"memUsedMiB"`
	MemTotalMiB int `json:"memTotalMiB"`
}

type Gres

type Gres struct {
	Name  string `json:"name"`
	Count int    `json:"count"`
}

type InsertRunParams

type InsertRunParams struct {
	SessionID string
	Seq       int64
	Owner     string
	Payload   string
}

type InsertSessionParams

type InsertSessionParams struct {
	ID      string
	Owner   string
	Payload string
}

type LinkAccess

type LinkAccess struct {
	URL   string `json:"url"`
	Token string `json:"token"`
}

type ListRunsByOwnerRow

type ListRunsByOwnerRow struct {
	SessionID string
	Seq       int64
	Payload   string
}

type ListRunsRow

type ListRunsRow struct {
	SessionID string
	Seq       int64
	Payload   string
}

type ListSessionsByOwnerRow

type ListSessionsByOwnerRow struct {
	ID      string
	Payload string
}

type ListSessionsRow

type ListSessionsRow struct {
	ID      string
	Payload string
}

type Partition

type Partition struct {
	Name     string `json:"name"`
	CPUCount int    `json:"cpuCount"`
	MemoryMB int    `json:"memoryMb"`
	GRES     []Gres `json:"gres"`
}

type Queries

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

func New

func New(db DBTX) *Queries

func (*Queries) ClearRuns

func (q *Queries) ClearRuns(ctx context.Context) error

func (*Queries) ClearSessions

func (q *Queries) ClearSessions(ctx context.Context) error

func (*Queries) GetSession

func (q *Queries) GetSession(ctx context.Context, id string) (string, error)

func (*Queries) InsertRun

func (q *Queries) InsertRun(ctx context.Context, arg InsertRunParams) error

func (*Queries) InsertSession

func (q *Queries) InsertSession(ctx context.Context, arg InsertSessionParams) error

func (*Queries) ListRuns

func (q *Queries) ListRuns(ctx context.Context) ([]ListRunsRow, error)

func (*Queries) ListRunsByOwner

func (q *Queries) ListRunsByOwner(ctx context.Context, owner string) ([]ListRunsByOwnerRow, error)

func (*Queries) ListSessions

func (q *Queries) ListSessions(ctx context.Context) ([]ListSessionsRow, error)

func (*Queries) ListSessionsByOwner

func (q *Queries) ListSessionsByOwner(ctx context.Context, owner string) ([]ListSessionsByOwnerRow, error)

func (*Queries) WithTx

func (q *Queries) WithTx(tx *sql.Tx) *Queries

type Resource

type Resource struct {
	Alias      string      `json:"alias"`
	Accounts   []string    `json:"accounts"`
	Partitions []Partition `json:"partitions"`
	HomeDir    string      `json:"homeDir"`
}

type Resources

type Resources struct {
	Cores       int    `json:"cores"`
	MemoryMB    int    `json:"memoryMb"`
	WallMinutes int    `json:"wallMinutes"`
	GPUType     string `json:"gpuType,omitempty"`
	GPUCount    int    `json:"gpuCount,omitempty"`
}

type Run

type Run struct {
	SessionID   string           `json:"sessionId"`
	Seq         int              `json:"seq"`
	Platform    string           `json:"platform,omitempty"`
	Alias       string           `json:"alias"`
	Account     string           `json:"account,omitempty"`
	Partition   string           `json:"partition"`
	RootFolder  string           `json:"rootFolder"`
	Resources   Resources        `json:"resources"`
	TunnelModes []string         `json:"tunnelModes"`
	FinalState  string           `json:"finalState"`
	Error       string           `json:"error,omitempty"`
	StartedAt   time.Time        `json:"startedAt,omitzero"`
	EndedAt     time.Time        `json:"endedAt"`
	Stats       *RunStats        `json:"stats,omitempty"`
	Samples     []UsageSample    `json:"samples,omitempty"`
	Logs        []SessionLogLine `json:"logs,omitempty"`
}

type RunList

type RunList struct {
	Runs []Run `json:"runs"`
}

type RunStats

type RunStats struct {
	Cores               int     `json:"cores,omitempty"`
	RequestedMemory     string  `json:"requestedMemory,omitempty"`
	ElapsedSeconds      int64   `json:"elapsedSeconds,omitempty"`
	MaxRSS              string  `json:"maxRss,omitempty"`
	CPUEfficiencyPct    float64 `json:"cpuEfficiencyPct,omitempty"`
	MemoryEfficiencyPct float64 `json:"memoryEfficiencyPct,omitempty"`
}

type RunnerProvider

type RunnerProvider interface {
	Runner(principal security.Principal) ssh.Runner
}

type SSHAccessResponse

type SSHAccessResponse struct {
	Port int `json:"port"`
}

type Service

type Service struct {
	Config
	// contains filtered or unexported fields
}

func NewService

func NewService(config Config) *Service

func (Service) Access

func (s Service) Access(principal security.Principal, id string) (*SessionAccessResponse, error)

func (Service) Attach

func (s Service) Attach(ctx context.Context, principal security.Principal, id string, transports []string) (*AttachResponse, error)

func (Service) Close

func (s Service) Close()

func (Service) Define

func (s Service) Define(principal security.Principal, request CreateRequest) (*Session, bool, error)

func (Service) Delete

func (s Service) Delete(principal security.Principal, id string) (*Session, error)

func (Service) Discover

func (s Service) Discover(ctx context.Context, principal security.Principal, alias string) (Resource, error)

func (Service) Forward

func (s Service) Forward(writer http.ResponseWriter, request *http.Request)

func (Service) Get

func (s Service) Get(principal security.Principal, id string) (*Session, error)

func (Service) Jupyter

func (s Service) Jupyter(writer http.ResponseWriter, request *http.Request)
func (s Service) Link(writer http.ResponseWriter, request *http.Request)

func (Service) List

func (s Service) List(principal security.Principal) (SessionList, error)

func (Service) Mount

func (s Service) Mount(mux *http.ServeMux)

func (Service) Routes

func (s Service) Routes() router.Routes

func (Service) Runs

func (s Service) Runs(principal security.Principal) ([]Run, error)

func (Service) Start

func (s Service) Start(ctx context.Context, principal security.Principal, id string) (*Session, error)

func (Service) StartSSH

func (s Service) StartSSH(ctx context.Context, principal security.Principal, id, publicKey string) (*SSHAccessResponse, error)

func (Service) Stop

func (s Service) Stop(principal security.Principal, id string) (*Session, error)

func (Service) Usage

func (s Service) Usage(principal security.Principal, id string) (SessionSeries, error)

func (Service) Validate

func (s Service) Validate(ctx context.Context, principal security.Principal, request CreateRequest) (*ValidationResult, error)

type Session

type Session struct {
	SessionResponse
	Owner          security.Principal `json:"owner"`
	Devtunnel      devtunnelMetadata  `json:"devtunnel"`
	JobID          string             `json:"jobId,omitempty"`
	JobName        string             `json:"jobName"`
	Node           string             `json:"node,omitempty"`
	PrivateRoot    string             `json:"privateRoot"`
	RootFolderPath string             `json:"rootFolderPath"`
}

type SessionAccessResponse

type SessionAccessResponse struct {
	SessionID string               `json:"sessionId"`
	Seq       int                  `json:"seq"`
	ExpiresAt time.Time            `json:"expiresAt"`
	Jupyter   SessionJupyterAccess `json:"jupyter"`
}

type SessionJupyterAccess

type SessionJupyterAccess struct {
	URI   string `json:"uri"`
	Token string `json:"token"`
}

type SessionList

type SessionList struct {
	Sessions []SessionResponse `json:"sessions"`
	Logs     []SessionLogTail  `json:"logs"`
}

type SessionLogLine

type SessionLogLine struct {
	Stream string    `json:"stream"`
	Text   string    `json:"text"`
	At     time.Time `json:"at"`
}

type SessionLogTail

type SessionLogTail struct {
	SessionID string           `json:"sessionId"`
	Lines     []SessionLogLine `json:"lines"`
}

type SessionResponse

type SessionResponse struct {
	ID          string    `json:"id"`
	Seq         int       `json:"seq"`
	State       string    `json:"state"`
	Platform    string    `json:"platform"`
	Alias       string    `json:"alias"`
	Account     string    `json:"account,omitempty"`
	Partition   string    `json:"partition"`
	RootFolder  string    `json:"rootFolder"`
	Resources   Resources `json:"resources"`
	TunnelModes []string  `json:"tunnelModes"`
	Error       string    `json:"error,omitempty"`
	CreatedAt   time.Time `json:"createdAt"`
	StartedAt   time.Time `json:"startedAt,omitzero"`
	UpdatedAt   time.Time `json:"updatedAt"`
}

type SessionSeries

type SessionSeries struct {
	SessionID string        `json:"sessionId"`
	Samples   []UsageSample `json:"samples"`
}

type Store

type Store struct {
	Dir      string
	Database *db.DB
}

type UsageSample

type UsageSample struct {
	At           time.Time   `json:"at"`
	MemBytes     *int64      `json:"memBytes,omitempty"`
	CPUUsageUsec *int64      `json:"cpuUsageUsec,omitempty"`
	GPUs         []GPUSample `json:"gpus,omitempty"`
}

type ValidationResult

type ValidationResult struct {
	SessionID string `json:"sessionId"`
	Script    string `json:"script"`
	Status    string `json:"status"`
	Message   string `json:"message"`
	Stdout    string `json:"stdout,omitempty"`
	Stderr    string `json:"stderr,omitempty"`
}

Jump to

Keyboard shortcuts

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