github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/dependency/resource.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package dependency 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 11 "github.com/juju/juju/worker" 12 ) 13 14 // resourceGetter encapsulates a snapshot of workers and output funcs and exposes 15 // a getResource method that can be used as a GetResourceFunc. 16 type resourceGetter struct { 17 18 // clientName is the name of the manifold for whose convenience this exists. 19 clientName string 20 21 // expired is closed when the resourceGetter should no longer be used. 22 expired chan struct{} 23 24 // workers holds the snapshot of manifold workers. 25 workers map[string]worker.Worker 26 27 // outputs holds the snapshot of manifold output funcs. 28 outputs map[string]OutputFunc 29 30 // accessLog holds the names and types of resource requests, and any error 31 // encountered. It does not include requests made after expiry. 32 accessLog []resourceAccess 33 } 34 35 // expire closes the expired channel. Calling it more than once will panic. 36 func (rg *resourceGetter) expire() { 37 close(rg.expired) 38 } 39 40 // getResource is intended for use as the GetResourceFunc passed into the Start 41 // func of the client manifold. 42 func (rg *resourceGetter) getResource(resourceName string, out interface{}) error { 43 logger.Tracef("%q manifold requested %q resource", rg.clientName, resourceName) 44 select { 45 case <-rg.expired: 46 return errors.New("expired resourceGetter: cannot be used outside Start func") 47 default: 48 err := rg.rawAccess(resourceName, out) 49 rg.accessLog = append(rg.accessLog, resourceAccess{ 50 name: resourceName, 51 as: fmt.Sprintf("%T", out), 52 err: err, 53 }) 54 return err 55 } 56 } 57 58 // rawAccess is a GetResourceFunc that neither checks enpiry nor records access. 59 func (rg *resourceGetter) rawAccess(resourceName string, out interface{}) error { 60 input := rg.workers[resourceName] 61 if input == nil { 62 // No worker running (or not declared). 63 return ErrMissing 64 } 65 convert := rg.outputs[resourceName] 66 if convert == nil { 67 // No conversion func available... 68 if out != nil { 69 // ...and the caller wants a resource. 70 return ErrMissing 71 } 72 // ...but it's ok, because the caller depends on existence only. 73 return nil 74 } 75 return convert(input, out) 76 } 77 78 // resourceAccess describes a call made to (*resourceGetter).getResource. 79 type resourceAccess struct { 80 81 // name is the name of the resource requested. 82 name string 83 84 // as is the string representation of the type of the out param. 85 as string 86 87 // err is any error returned from rawAccess. 88 err error 89 } 90 91 // report returns a convenient representation of ra. 92 func (ra resourceAccess) report() map[string]interface{} { 93 return map[string]interface{}{ 94 KeyName: ra.name, 95 KeyType: ra.as, 96 KeyError: ra.err, 97 } 98 } 99 100 // resourceLogReport returns a convenient representation of accessLog. 101 func resourceLogReport(accessLog []resourceAccess) []map[string]interface{} { 102 result := make([]map[string]interface{}, len(accessLog)) 103 for i, access := range accessLog { 104 result[i] = access.report() 105 } 106 return result 107 }