console: inert claim-operation adapters and construction fields (claim Plan 5 Task 4)
Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+67
−0
internal/console/hostclaimops.go+63 −0internal/console/server.go+4 −0
CI passed — run details
diff --git a/internal/console/hostclaimops.go b/internal/console/hostclaimops.go| new file mode 100644 |
| index 000000000..1f70ef3f1 |
| --- /dev/null |
| +++ b/internal/console/hostclaimops.go |
| @@ -0,0 +1,63 @@ |
| +package console |
| + |
| +import ( |
| + "context" |
| + "log" |
| + "time" |
| + |
| + "github.com/carlosframework/platform/internal/hostclaim" |
| + "github.com/carlosframework/platform/internal/hostops" |
| + "github.com/carlosframework/platform/internal/provision" |
| +) |
| + |
| +func (s *Server) retireHostRecord(ctx context.Context, ref provision.RetireRef) error { |
| + var claims provision.ClaimRetirer |
| + if s.cfg.HostClaimOps != nil { |
| + claims = s.cfg.HostClaimOps |
| + } |
| + return provision.RetireRecord(ctx, s.cfg.Releases, ref, provision.RetireOptions{HostClaim: s.cfg.HostClaim, Claims: claims}) |
| +} |
| +func (s *Server) adoptHostRecord(ctx context.Context, key string) (hostclaim.Observed, error) { |
| + if !s.cfg.HostClaim || s.cfg.HostClaimOps == nil { |
| + return hostclaim.Observed{}, hostops.ErrContract |
| + } |
| + rec, err := hostops.ReadRecord(ctx, s.cfg.Releases, key) |
| + if err != nil { |
| + return hostclaim.Observed{}, err |
| + } |
| + return s.cfg.HostClaimOps.Adopt(ctx, rec) |
| +} |
| + |
| +const claimRecoveryInterval = 2 * time.Minute |
| + |
| +// Called by serve, never NewServer. Tests can invoke the one-pass method. |
| +func (s *Server) StartClaimRecoveryPass(ctx context.Context) { |
| + if !s.cfg.HostClaim { |
| + return |
| + } |
| + if s.cfg.HostClaimRecovery == nil { |
| + log.Printf("console: claim recovery: %v", hostops.ErrContract) |
| + return |
| + } |
| + t := time.NewTicker(claimRecoveryInterval) |
| + defer t.Stop() |
| + for { |
| + if err := s.claimRecoveryPass(ctx); err != nil { |
| + log.Printf("console: claim recovery: %v", err) |
| + } |
| + select { |
| + case <-ctx.Done(): |
| + return |
| + case <-t.C: |
| + } |
| + } |
| +} |
| +func (s *Server) claimRecoveryPass(ctx context.Context) error { |
| + if !s.cfg.HostClaim { |
| + return nil |
| + } |
| + if s.cfg.HostClaimRecovery == nil { |
| + return hostops.ErrContract |
| + } |
| + return s.cfg.HostClaimRecovery.Pass(ctx) |
| +} |
diff --git a/internal/console/server.go b/internal/console/server.go| index 9e1fb9cdc..68426e7c2 100644 |
| --- a/internal/console/server.go |
| +++ b/internal/console/server.go |
| @@ -13,6 +13,7 @@ import ( |
| "encoding/json" |
| "errors" |
| "fmt" |
| + "github.com/carlosframework/platform/internal/hostops" |
| "github.com/carlosframework/platform/internal/lease" |
| "html/template" |
| "log" |
| @@ -456,6 +457,9 @@ const ( |
| // Config is everything the server reads its world through. |
| type Config struct { |
| + HostClaimOps *hostops.Controller |
| + HostClaimRecovery *hostops.Recovery |
| + |
| HostClaim bool |
| DBVersions lease.VersionedStore |
| Origin string // the console's public origin — the OAuth client_id |