package host import ( "context" "errors" "os" "github.com/carlosframework/platform/internal/instancectl" ) // Placement comes from retained root state. Configuration may deny a new // start, but removing it cannot retarget cleanup to the ordinary run unit. type claimUnitDispatch struct { base instancectl.ClaimUnits bindings *claimUnitBindings shapes func() (map[string]claimUnitShape, error) definition func(claimUnitShape) error effective func(context.Context, claimUnitShape) error } func (d claimUnitDispatch) selected(host string) (instancectl.ClaimUnits, error) { u := d.base if d.bindings == nil || d.shapes == nil { return u, os.ErrPermission } b, err := d.bindings.read(host) if err == nil { u.BoundHost, u.BoundUnit, u.BoundAddr = host, b.Shape.Unit, b.Shape.Addr return u, nil } if !errors.Is(err, os.ErrNotExist) { return u, err } return u, nil } func (d claimUnitDispatch) forStart(ctx context.Context, host string) (instancectl.ClaimUnits, error) { u, err := d.selected(host) if err != nil { return u, err } if u.BoundUnit == "" { shapes, e := d.shapes() if e != nil { return u, e } if e == nil { if _, configured := shapes[host]; configured { return u, os.ErrPermission } } if d.effective == nil { return u, os.ErrPermission } if err := d.effective(ctx, claimUnitShape{Host: host, Unit: instancectl.UnitName(instancectl.RoleRun, host)}); err != nil { return u, err } } if u.BoundUnit != "" { shapes, err := d.shapes() if err != nil { return u, err } b, err := d.bindings.check(ctx, host, nil) if err != nil { return u, err } if shapes[host] != b.Shape { return u, os.ErrPermission } if d.definition == nil { return u, os.ErrPermission } if err := d.definition(b.Shape); err != nil { return u, err } if d.effective != nil { if err := d.effective(ctx, b.Shape); err != nil { return u, err } } } return u, nil } func (d claimUnitDispatch) Placement(host string) (string, string, error) { u, err := d.selected(host) if err != nil { return "", "", err } return u.Placement(host) } func (d claimUnitDispatch) StartReserved(ctx context.Context, in instancectl.ClaimUnit, l instancectl.Launch, p instancectl.ClaimExecPermit, check func() error) (instancectl.ClaimUnitStarted, error) { u, err := d.forStart(ctx, in.Host) if err != nil { return instancectl.ClaimUnitStarted{}, err } if check == nil { return instancectl.ClaimUnitStarted{}, os.ErrPermission } return u.StartReserved(ctx, in, l, p, func() error { again, err := d.forStart(ctx, in.Host) if err != nil { return err } if again.BoundHost != u.BoundHost || again.BoundUnit != u.BoundUnit { return os.ErrPermission } return check() }) } func (d claimUnitDispatch) Same(ctx context.Context, started instancectl.ClaimUnitStarted) error { // The caller retained the selected placement in the launch grant. Same // checks that exact invocation without taking a new route from the registry. return d.base.Same(ctx, started) } func (d claimUnitDispatch) Stop(context.Context, string) error { // Dispatch cannot guess which invocation a bare host means. return os.ErrPermission } func (d claimUnitDispatch) StopInvocation(ctx context.Context, host, invocation string) error { u, err := d.selected(host) if err != nil { return err } return u.StopInvocation(ctx, host, invocation) } func (d claimUnitDispatch) Gone(ctx context.Context, host, invocation string) error { u, err := d.selected(host) if err != nil { return err } return u.Gone(ctx, host, invocation) }