carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1// An instance's environment binding and a seed's store (final review F3).
2// A seed marks the store it makes (objstore.Declared.Seed), and its finish
3// tears that store down while the mark stands and no other instance names
4// the environment (seedfinish.go). An instance that comes to name the
5// environment afterwards holds the store from then on, so the binding
6// clears the mark under the store's walk lock, the lock the finish holds
7// from its last check through the teardown. The lock is this process's:
8// one console per deployment is a rollout invariant of the seeds series.
9
10package console
11
12import (
13 "context"
14 "log"
15 "net/http"
16
17 "github.com/carlosframework/platform/internal/objstore"
18 "github.com/carlosframework/platform/internal/provision"
19)
20
21// lockEnvironmentUpdate is the update door's binding: when the patch moves
22// rec to another environment, it takes that environment's store walk lock
23// and moves the store to rec (takeSeedStore). The caller holds unlock
24// across its record write. A store that cannot be read or written answers
25// main's update retry sentence, and ok is false.
26func (s *Server) lockEnvironmentUpdate(ctx context.Context, w http.ResponseWriter, stored, rec provision.Record) (unlock func(), ok bool) {
27 if rec.Environment == stored.Environment {
28 return func() {}, true
29 }
30 unlock = s.storeWalks.lock(rec.Account, rec.App, rec.Environment)
31 if err := s.takeSeedStore(ctx, rec); err != nil {
32 unlock()
33 log.Printf("console: api instances update %s/%s/%s: environment %q: %v", rec.Account, rec.App, rec.Host, rec.Environment, err)
34 jsonError(w, http.StatusBadGateway, "could not update the instance — try again")
35 return nil, false
36 }
37 return unlock, true
38}
39
40// bindEnvironmentCreate is the create door's binding for an instance that
41// names an environment and provisions no store of its own (a private
42// storage create's grant clears the mark itself, by GrantInFor's rule). It
43// moves the store to rec under the lock. A failure answers main's create
44// retry sentence, and the answer is false.
45func (s *Server) bindEnvironmentCreate(ctx context.Context, w http.ResponseWriter, rec provision.Record) bool {
46 if rec.Environment == "" {
47 return true
48 }
49 defer s.storeWalks.lock(rec.Account, rec.App, rec.Environment)()
50 if err := s.takeSeedStore(ctx, rec); err != nil {
51 log.Printf("console: api instances create %s/%s/%s: environment %q: %v", rec.Account, rec.App, rec.Host, rec.Environment, err)
52 jsonError(w, http.StatusBadGateway, "could not create the instance — try again")
53 return false
54 }
55 return true
56}
57
58// takeSeedStore clears the seed mark on the store of rec's environment
59// when it is not rec's own seed's: GrantInFor's rule (objstore
60// claimRawGrantIn) for a binding that grants nothing. Whoever binds the
61// store now holds it, and the seed's finish must never tear it down; an
62// aborted seed's bucket can leak that way, which is the safe direction.
63// The caller holds the environment's store walk lock.
64func (s *Server) takeSeedStore(ctx context.Context, rec provision.Record) error {
65 store, etag, err := objstore.GetIn(ctx, s.cfg.Releases, rec.Account, rec.App, rec.Environment)
66 if err != nil {
67 return err
68 }
69 mine := ""
70 if rec.Seed != nil {
71 mine = rec.Seed.ID
72 }
73 if store == nil || store.Declared == nil || store.Declared.Seed == "" || store.Declared.Seed == mine {
74 return nil
75 }
76 seed := store.Declared.Seed
77 store.Declared.Seed = ""
78 if _, err := objstore.PutIn(ctx, s.cfg.Releases, rec.Account, rec.App, rec.Environment, store, etag); err != nil {
79 return err
80 }
81 log.Printf("console: instance %s/%s/%s binds environment %q: the store seed %s made (bucket %s) is no longer that seed's, and its finish leaves it standing",
82 rec.Account, rec.App, rec.Host, rec.Environment, seed, storeBucketName(store))
83 return nil
84}
85