github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/lease/bound.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package lease 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 11 "github.com/juju/juju/core/lease" 12 ) 13 14 // broker describes methods for manipulating and checking leases. 15 type broker interface { 16 lease.Checker 17 lease.Claimer 18 lease.Pinner 19 } 20 21 // boundManager implements the broker interface. 22 // It represents a lease manager for a specific namespace and model. 23 type boundManager struct { 24 manager *Manager 25 secretary Secretary 26 namespace string 27 modelUUID string 28 } 29 30 // Claim is part of the lease.Claimer interface. 31 func (b *boundManager) Claim(leaseName, holderName string, duration time.Duration) error { 32 key := b.leaseKey(leaseName) 33 if err := b.secretary.CheckLease(key); err != nil { 34 return errors.Annotatef(err, "cannot claim lease %q", leaseName) 35 } 36 if err := b.secretary.CheckHolder(holderName); err != nil { 37 return errors.Annotatef(err, "cannot claim lease for holder %q", holderName) 38 } 39 if err := b.secretary.CheckDuration(duration); err != nil { 40 return errors.Annotatef(err, "cannot claim lease for %s", duration) 41 } 42 43 return claim{ 44 leaseKey: key, 45 holderName: holderName, 46 duration: duration, 47 response: make(chan error), 48 stop: b.manager.catacomb.Dying(), 49 }.invoke(b.manager.claims) 50 } 51 52 // WaitUntilExpired is part of the lease.Claimer interface. 53 func (b *boundManager) WaitUntilExpired(leaseName string, cancel <-chan struct{}) error { 54 key := b.leaseKey(leaseName) 55 if err := b.secretary.CheckLease(key); err != nil { 56 return errors.Annotatef(err, "cannot wait for lease %q expiry", leaseName) 57 } 58 59 return block{ 60 leaseKey: key, 61 unblock: make(chan struct{}), 62 stop: b.manager.catacomb.Dying(), 63 cancel: cancel, 64 }.invoke(b.manager.blocks) 65 } 66 67 // Token is part of the lease.Checker interface. 68 func (b *boundManager) Token(leaseName, holderName string) lease.Token { 69 return token{ 70 leaseKey: b.leaseKey(leaseName), 71 holderName: holderName, 72 secretary: b.secretary, 73 checks: b.manager.checks, 74 stop: b.manager.catacomb.Dying(), 75 } 76 } 77 78 // Pinned (lease.Pinner) returns applications and the entities requiring their 79 // pinned behaviour, for pinned leases in the bound namespace/model. 80 func (b *boundManager) Pinned() map[string][]string { 81 return b.manager.pinned(b.namespace, b.modelUUID) 82 } 83 84 // Pin (lease.Pinner) sends a pin message to the worker loop. 85 func (b *boundManager) Pin(leaseName string, entity string) error { 86 return errors.Trace(b.pinOp(leaseName, entity, b.manager.pins)) 87 } 88 89 // Unpin (lease.Pinner) sends an unpin message to the worker loop. 90 func (b *boundManager) Unpin(leaseName string, entity string) error { 91 return errors.Trace(b.pinOp(leaseName, entity, b.manager.unpins)) 92 } 93 94 // pinOp creates a pin instance from the input lease name, 95 // then sends it on the input channel. 96 func (b *boundManager) pinOp(leaseName string, entity string, ch chan pin) error { 97 return errors.Trace(pin{ 98 leaseKey: b.leaseKey(leaseName), 99 entity: entity, 100 response: make(chan error), 101 stop: b.manager.catacomb.Dying(), 102 }.invoke(ch)) 103 } 104 105 // leaseKey returns a key for the manager's binding and the input lease name. 106 func (b *boundManager) leaseKey(leaseName string) lease.Key { 107 return lease.Key{ 108 Namespace: b.namespace, 109 ModelUUID: b.modelUUID, 110 Lease: leaseName, 111 } 112 }