github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/lease/store.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lease 5 6 import ( 7 "context" 8 "strings" 9 "time" 10 11 "github.com/juju/errors" 12 ) 13 14 // Store manipulates leases directly, and is most likely to be seen set on a 15 // worker/lease.ManagerConfig struct (and used by the Manager). Implementations 16 // of Store are not expected to be goroutine-safe. 17 type Store interface { 18 // ClaimLease records the supplied holder's claim to the supplied lease. If 19 // it succeeds, the claim is guaranteed until at least the supplied duration 20 // after the call to ClaimLease was initiated. If it returns ErrInvalid, 21 // check Leases() for updated state. 22 ClaimLease(ctx context.Context, lease Key, request Request) error 23 24 // ExtendLease records the supplied holder's continued claim to the supplied 25 // lease, if necessary. If it succeeds, the claim is guaranteed until at 26 // least the supplied duration after the call to ExtendLease was initiated. 27 // If it returns ErrInvalid, check Leases() for updated state. 28 ExtendLease(ctx context.Context, lease Key, request Request) error 29 30 // RevokeLease records the vacation of the supplied lease. It will fail if 31 // the lease is not held by the holder. 32 RevokeLease(ctx context.Context, lease Key, holder string) error 33 34 // Leases returns a recent snapshot of lease state. Expiry times are 35 // expressed according to the Clock the store was configured with. 36 // Supplying any lease keys will filter the return for those requested. 37 Leases(ctx context.Context, keys ...Key) (map[Key]Info, error) 38 39 // LeaseGroup returns a snapshot of all of the leases for a 40 // particular namespace/model combination. This is useful for 41 // reporting holder information for a model, and can often be 42 // implemented more efficiently than getting all leases when there 43 // are many models. 44 LeaseGroup(ctx context.Context, namespace, modelUUID string) (map[Key]Info, error) 45 46 // PinLease ensures that the current holder of the lease for the input key 47 // will not lose the lease to expiry. 48 // If there is no current holder of the lease, the next claimant will be 49 // the recipient of the pin behaviour. 50 // The input entity denotes the party responsible for the 51 // pinning operation. 52 PinLease(ctx context.Context, lease Key, entity string) error 53 54 // UnpinLease reverses a Pin operation for the same key and entity. 55 // Normal expiry behaviour is restored when no entities remain with 56 // pins for the application. 57 UnpinLease(ctx context.Context, lease Key, entity string) error 58 59 // Pinned returns a snapshot of pinned leases. 60 // The return consists of each pinned lease and the collection of entities 61 // requiring its pinned behaviour. 62 Pinned(ctx context.Context) (map[Key][]string, error) 63 } 64 65 // Key fully identifies a lease, including the namespace and 66 // model it belongs to. 67 type Key struct { 68 Namespace string 69 ModelUUID string 70 Lease string 71 } 72 73 // Info holds substrate-independent information about a lease. 74 type Info struct { 75 // Holder is the name of the current leaseholder. 76 Holder string 77 78 // Expiry is the latest time at which it's possible the lease might still 79 // be valid. Attempting to expire the lease before this time will fail. 80 Expiry time.Time 81 } 82 83 // Request describes a lease request. 84 type Request struct { 85 86 // Holder identifies the lease holder. 87 Holder string 88 89 // Duration specifies the time for which the lease is required. 90 Duration time.Duration 91 } 92 93 // Validate returns an error if any fields are invalid or inconsistent. 94 func (request Request) Validate() error { 95 if err := ValidateString(request.Holder); err != nil { 96 return errors.Annotatef(err, "invalid holder") 97 } 98 if request.Duration <= 0 { 99 return errors.Errorf("invalid duration") 100 } 101 return nil 102 } 103 104 // ValidateString returns an error if the string is empty, or if it contains 105 // whitespace, or if it contains any character in `.#$`. Store implementations 106 // are expected to always reject invalid strings, and never to produce them. 107 func ValidateString(s string) error { 108 if s == "" { 109 return errors.New("string is empty") 110 } 111 if strings.ContainsAny(s, ".$# \t\r\n") { 112 return errors.New("string contains forbidden characters") 113 } 114 return nil 115 }