package host import ( "context" "errors" "os" "path/filepath" "slices" "github.com/carlosframework/platform/internal/activator" "github.com/carlosframework/platform/internal/cgroup" "github.com/carlosframework/platform/internal/hostbox" "github.com/carlosframework/platform/internal/hostwrite" "github.com/carlosframework/platform/internal/instancectl" "github.com/carlosframework/platform/internal/provision" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) func (h *ClaimLaunchRoot) boundInputs(ctx context.Context, rt registry.Route) (*hostbox.UnitLaunchInputs, error) { if h.unitBindings == nil || h.unitProgram == nil { return nil, os.ErrPermission } var result *hostbox.UnitLaunchInputs err := func() error { b, err := h.unitBindings.read(rt.Host) if errors.Is(err, os.ErrNotExist) { if _, e := h.unitBindings.canonical(ctx, rt.Host); e == nil { return os.ErrPermission } if rt.Unit != "" || rt.Backing != "" || rt.Tunnel != "" { return hostbox.ErrUnsupported } return nil } if err != nil { return err } b, err = h.unitBindings.check(ctx, rt.Host, &rt) if err != nil { return err } p, err := h.unitProgram(b.Shape) if err != nil { return err } result = &hostbox.UnitLaunchInputs{Unit: b.Shape.Unit, Socket: b.Shape.Socket, Addr: b.Shape.Addr, DBPath: b.Shape.DBPath, Program: b.Shape.Program, Args: append([]string(nil), p.Args...), Env: append([]string(nil), p.Env...)} return nil }() return result, err } type claimUnitInputReader func(context.Context, registry.Route) (*hostbox.UnitLaunchInputs, error) func claimBoundSnapshot(ctx context.Context, backend *activator.ExecBackend, rt registry.Route, read claimUnitInputReader) (ClaimServingLaunch, error) { var out ClaimServingLaunch unit, err := read(ctx, rt) if err != nil { return out, err } if unit == nil { return out, hostbox.ErrUnsupported } if err = validateClaimUnitInputs(rt.Host, unit); err != nil { return out, err } id, err := release.ResolveLive(backend.OptDir, rt.Host) if err != nil { return out, err } if id.Version == "" || !claimHexDigest(id.Digest) { return out, hostbox.ErrChanged } out = ClaimServingLaunch{Unit: unit, Identity: hostwrite.Identity{Config: unit.Program, Release: id.Digest}, Executable: release.LiveLink(backend.OptDir, rt.Host), ExecutableSHA256: id.Digest, Args: unit.Args, Env: unit.Env, Version: id.Version, Staged: id, Limit: cgroup.TierDefault, Roles: []string{"main"}} return out, nil } func validateClaimUnitInputs(host string, in *hostbox.UnitLaunchInputs) error { if in == nil || !claimHexDigest(in.Program) || !provision.ValidHostShape(host) || filepath.Dir(in.DBPath) != provision.InstanceDir("/data", host) { return hostbox.ErrRoleLaunchShape } if !instancectl.ValidBoundClaimUnit(in.Unit) || (in.Socket == "") == (in.Addr == "") || filepath.Clean(in.DBPath) != in.DBPath { return hostbox.ErrRoleLaunchShape } if in.Socket != "" && in.Socket != provision.NestedSocket(host) && !claimFlatSocket(claimUnitShape{Socket: in.Socket}) { return hostbox.ErrRoleLaunchShape } return nil } func claimBoundInputMatch(host string, in ClaimLaunchInputs) error { if err := validateClaimUnitInputs(host, in.Unit); err != nil { return err } if in.DBPath != in.Unit.DBPath || in.Identity.Config != in.Unit.Program || !slices.Equal(in.Args, in.Unit.Args) || !slices.Equal(in.Env, in.Unit.Env) { return hostbox.ErrRoleLaunchShape } return nil }