cli: carlos add -backing unit — whole-app tenant defaults
Unit tenants default their socket to the carlos-app@<host>.socket path (/run/carlos/apps/<host>.sock) and take no /data db default — their data lives in the unit's StateDirectory under the box replicator. Instances listing shows the backing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+20
−7
cli.go+20 −7
diff --git a/cli.go b/cli.go| index 089135fcf..dd602f9c0 100644 |
| --- a/cli.go |
| +++ b/cli.go |
| @@ -55,6 +55,7 @@ func runAdd(args []string) { |
| addr := fs.String("addr", "", "TCP upstream host:port (whole-app tenants)") |
| channel := fs.String("channel", "stable", "release channel to follow") |
| hibernate := fs.Bool("hibernate", false, "hibernate when idle") |
| + backing := fs.String("backing", "", `process backing: "" (agent exec child) | "unit" (carlos-app@<host> systemd unit)`) |
| dbPath := fs.String("db", "", "instance database path") |
| fs.Parse(args) |
| if fs.NArg() != 1 { |
| @@ -64,10 +65,22 @@ func runAdd(args []string) { |
| if reservedSlugs()[*slug] { |
| log.Fatalf("slug %q is reserved", *slug) |
| } |
| + if *backing != "" && *backing != registry.BackingUnit { |
| + log.Fatalf("backing %q: want \"\" or %q", *backing, registry.BackingUnit) |
| + } |
| if *socket == "" && *addr == "" && *kind == "instance" { |
| - *socket = filepath.Join("/run/carlos", host+".sock") |
| + if *backing == registry.BackingUnit { |
| + // The carlos-app@<host>.socket unit's path — enable that unit |
| + // alongside this route (or use -addr for a TCP-only app). |
| + *socket = filepath.Join("/run/carlos/apps", host+".sock") |
| + } else { |
| + *socket = filepath.Join("/run/carlos", host+".sock") |
| + } |
| } |
| - if *dbPath == "" && *kind == "instance" { |
| + // No DB default for unit tenants: their data lives in the unit's |
| + // StateDirectory (/var/lib/carlos-app/<host>), replicated by the box |
| + // litestream unit — -db stays an explicit operator choice there. |
| + if *dbPath == "" && *kind == "instance" && *backing != registry.BackingUnit { |
| *dbPath = filepath.Join(dataDir(), host+".db") |
| } |
| r, err := registry.Open(*reg) |
| @@ -76,8 +89,8 @@ func runAdd(args []string) { |
| } |
| if err := r.Upsert(registry.Route{ |
| Host: host, Slug: *slug, Kind: *kind, Socket: *socket, Addr: *addr, |
| - App: *app, Channel: *channel, Hibernate: *hibernate, DBPath: *dbPath, |
| - Status: "ready", |
| + App: *app, Channel: *channel, Hibernate: *hibernate, Backing: *backing, |
| + DBPath: *dbPath, Status: "ready", |
| }); err != nil { |
| log.Fatal(err) |
| } |
| @@ -115,14 +128,14 @@ func runInstances(args []string) { |
| log.Fatal(err) |
| } |
| w := tabwriter.NewWriter(os.Stdout, 0, 4, 2, ' ', 0) |
| - fmt.Fprintln(w, "HOST\tAPP\tKIND\tCHANNEL\tSTATUS\tVERSION\tHIB") |
| + fmt.Fprintln(w, "HOST\tAPP\tKIND\tCHANNEL\tSTATUS\tVERSION\tHIB\tBACKING") |
| for _, t := range routes { |
| hib := "" |
| if t.Hibernate { |
| hib = "yes" |
| } |
| - fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n", |
| - t.Host, t.App, t.Kind, t.Channel, t.Status, t.Version, hib) |
| + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", |
| + t.Host, t.App, t.Kind, t.Channel, t.Status, t.Version, hib, t.Backing) |
| } |
| w.Flush() |
| } |