Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 18 additions & 21 deletions internal/cli/resources.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,11 +36,11 @@ func newResourcesCmd() *cobra.Command {
Short: "Show how much of this machine tracebloc may use",
Long: `Shows, in plain terms, how much of this machine tracebloc may use:

This machine — the CPU and memory the cluster can schedule
tracebloc uses — the ceiling a single training run may use right now
Your secure environment — the CPU and memory it can schedule
Each training run — the per-run ceiling every run may use (cluster-wide)

No Kubernetes concepts, no YAML — one number for the machine and one for
tracebloc's share of it.
No Kubernetes concepts, no YAML — one number for your environment and one for
each training run's share of it.

Raise the share with ` + "`tracebloc resources set`" + `. Run with --verbose for the
per-node breakdown and the raw values.
Expand DownExpand Up@@ -125,16 +125,16 @@ func renderResources(ctx context.Context, p *ui.Printer, target *clusterTarget)
train.HasGPU = false
}

p.Section("This machine")
if nodeErr != nil {
p.Field("capacity", "unavailable")
p.Hintf(" couldn't read node capacity: %v", nodeErr)
p.Stat("Your secure environment is equipped with:", "unavailable")
p.Hintf(" couldn't read capacity: %v", nodeErr)
} else {
p.Field("capacity", machineLine(machine))
p.Stat("Your secure environment is equipped with:", machineLine(machine))
}

p.Section("tracebloc uses")
p.Field("per training run", trainingLine(train))
// The per-run ceiling is cluster-wide — jobs-manager stamps it on EVERY
// training run (there is no per-run override today). perRunSize is the same
// "CPU · mem" string `resources set` shows; the label carries the "up to".
p.Stat("A training run is allocated up to:", perRunSize(train))

if p.Verbose() {
p.Section("Details")
Expand All@@ -151,7 +151,13 @@ func renderResources(ctx context.Context, p *ui.Printer, target *clusterTarget)
}

p.Newline()
p.Hintf("Raise tracebloc's share with `tracebloc resources set` (run it on a terminal for a guided walkthrough).")
// Match the home screen's launcher resolution so the hint reads `tb …` on a
// real install (where the `tb` alias exists) and `tracebloc …` otherwise.
cmd := invokedName()
if tbAliasAvailable() {
cmd = binTB
}
p.Hintf("Do you want to change the allocation? Run `%s resources set` (guided walkthrough on a terminal).", cmd)
return nil
}

Expand All@@ -165,15 +171,6 @@ func machineLine(m resources.Machine) string {
return line
}

// trainingLine renders the per-run ceiling: "up to 2 CPU · 8 GiB" (+ GPU).
func trainingLine(t resources.Training) string {
line := "up to " + resources.FormatCPU(t.CPU) + " · " + resources.FormatMem(t.Mem)
if t.HasGPU {
line += " · " + resources.FormatGPU(t.GPUName, t.GPU)
}
return line
}

// firstNonEmptyEnv returns the first present, non-empty value among keys.
func firstNonEmptyEnv(env map[string]string, keys ...string) string {
for _, k := range keys {
Expand Down
5 changes: 3 additions & 2 deletions internal/cli/resources_test.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -72,7 +72,7 @@ func TestRenderResources_ShowsMachineAndTrainingCeiling(t *testing.T) {
t.Fatalf("renderResources: %v", err)
}
out := buf.String()
for _, want := range []string{"This machine", "8 CPU · 32 GiB", "tracebloc uses", "up to4 CPU · 16 GiB"} {
for _, want := range []string{"Your secure environment is equipped with:", "8 CPU · 32 GiB", "A training run is allocated up to:", "4 CPU · 16 GiB"} {
if !strings.Contains(out, want) {
t.Errorf("missing %q in:\n%s", want, out)
}
Expand All@@ -93,7 +93,8 @@ func TestRenderResources_ChartDefaultWhenEnvUnset(t *testing.T) {
if err := renderResources(context.Background(), ui.New(&buf, ui.WithColor(false)), resTarget(cs)); err != nil {
t.Fatalf("renderResources: %v", err)
}
if !strings.Contains(buf.String(), "up to 2 CPU · 8 GiB") {
if !strings.Contains(buf.String(), "A training run is allocated up to:") ||
!strings.Contains(buf.String(), "2 CPU · 8 GiB") {
t.Errorf("want chart-default ceiling 2 CPU · 8 GiB:\n%s", buf.String())
}
}
Expand Down
7 changes: 7 additions & 0 deletions internal/ui/ui.go
Original file line numberDiff line numberDiff line change
Expand Up@@ -245,6 +245,13 @@ func (p *Printer) Field(label, value string) {
p.out(" %s %s\n", p.paint(fmt.Sprintf("%-14s", label+":"), color.Faint), value)
}

// Stat prints an aligned "label value" row with a dimmed, fixed-width label,
// so a short block of them lines up. Unlike Field's compact 14-col key, Stat
// fits full-sentence labels (e.g. the resources view's two lines).
func (p *Printer) Stat(label, value string) {
p.out(" %s %s\n", p.paint(fmt.Sprintf("%-42s", label), color.Faint), value)
}

// Action prints an imperative instruction row — a bold verb label and its value,
// with no trailing colon: " Open https://…". Used for the device-flow
// sign-in steps (Open the URL / Enter the code), where the label is a thing to
Expand Down
Loading