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
- Variables
- type AttachResponse
- type Config
- type CreateRequest
- type DBTX
- type DevtunnelAccess
- type DevtunnelCredentials
- type DevtunnelManager
- type GPUSample
- type Gres
- type InsertRunParams
- type InsertSessionParams
- type LinkAccess
- type ListRunsByOwnerRow
- type ListRunsRow
- type ListSessionsByOwnerRow
- type ListSessionsRow
- type Partition
- type Queries
- func (q *Queries) ClearRuns(ctx context.Context) error
- func (q *Queries) ClearSessions(ctx context.Context) error
- func (q *Queries) GetSession(ctx context.Context, id string) (string, error)
- func (q *Queries) InsertRun(ctx context.Context, arg InsertRunParams) error
- func (q *Queries) InsertSession(ctx context.Context, arg InsertSessionParams) error
- func (q *Queries) ListRuns(ctx context.Context) ([]ListRunsRow, error)
- func (q *Queries) ListRunsByOwner(ctx context.Context, owner string) ([]ListRunsByOwnerRow, error)
- func (q *Queries) ListSessions(ctx context.Context) ([]ListSessionsRow, error)
- func (q *Queries) ListSessionsByOwner(ctx context.Context, owner string) ([]ListSessionsByOwnerRow, error)
- func (q *Queries) WithTx(tx *sql.Tx) *Queries
- type Resource
- type Resources
- type Run
- type RunList
- type RunStats
- type RunnerProvider
- type SSHAccessResponse
- type Service
- func (s Service) Access(principal security.Principal, id string) (*SessionAccessResponse, error)
- func (s Service) Attach(ctx context.Context, principal security.Principal, id string, ...) (*AttachResponse, error)
- func (s Service) Close()
- func (s Service) Define(principal security.Principal, request CreateRequest) (*Session, bool, error)
- func (s Service) Delete(principal security.Principal, id string) (*Session, error)
- func (s Service) Discover(ctx context.Context, principal security.Principal, alias string) (Resource, error)
- func (s Service) Forward(writer http.ResponseWriter, request *http.Request)
- func (s Service) Get(principal security.Principal, id string) (*Session, error)
- func (s Service) Jupyter(writer http.ResponseWriter, request *http.Request)
- func (s Service) Link(writer http.ResponseWriter, request *http.Request)
- func (s Service) List(principal security.Principal) (SessionList, error)
- func (s Service) Mount(mux *http.ServeMux)
- func (s Service) Routes() router.Routes
- func (s Service) Runs(principal security.Principal) ([]Run, error)
- func (s Service) Start(ctx context.Context, principal security.Principal, id string) (*Session, error)
- func (s Service) StartSSH(ctx context.Context, principal security.Principal, id, publicKey string) (*SSHAccessResponse, error)
- func (s Service) Stop(principal security.Principal, id string) (*Session, error)
- func (s Service) Usage(principal security.Principal, id string) (SessionSeries, error)
- func (s Service) Validate(ctx context.Context, principal security.Principal, request CreateRequest) (*ValidationResult, error)
- type Session
- type SessionAccessResponse
- type SessionJupyterAccess
- type SessionList
- type SessionLogLine
- type SessionLogTail
- type SessionResponse
- type SessionSeries
- type Store
- type UsageSample
- type ValidationResult
Constants ¶
const DefaultLinkspanPath = "$HOME/.cybershuttle/bin/linkspan"
Variables ¶
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 DevtunnelAccess ¶
type DevtunnelCredentials ¶
type DevtunnelManager ¶
type InsertRunParams ¶
type InsertSessionParams ¶
type LinkAccess ¶
type ListRunsByOwnerRow ¶
type ListRunsRow ¶
type ListSessionsByOwnerRow ¶
type ListSessionsRow ¶
type Queries ¶
type Queries struct {
// contains filtered or unexported fields
}
func (*Queries) GetSession ¶
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) ListRunsByOwner ¶
func (*Queries) ListSessions ¶
func (q *Queries) ListSessions(ctx context.Context) ([]ListSessionsRow, error)
func (*Queries) ListSessionsByOwner ¶
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 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 SSHAccessResponse ¶
type SSHAccessResponse struct {
Port int `json:"port"`
}
type Service ¶
type Service struct {
Config
// contains filtered or unexported fields
}
func NewService ¶
func (Service) Forward ¶
func (s Service) Forward(writer http.ResponseWriter, request *http.Request)
func (Service) Jupyter ¶
func (s Service) Jupyter(writer http.ResponseWriter, request *http.Request)
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 SessionList ¶
type SessionList struct {
Sessions []SessionResponse `json:"sessions"`
Logs []SessionLogTail `json:"logs"`
}
type SessionLogLine ¶
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"`
}