github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/uniter/leadership.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package uniter 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/params" 11 "github.com/juju/juju/core/watcher" 12 ) 13 14 // NewLeadershipSettingsAccessor returns a new LeadershipSettingsAccessor. 15 func NewLeadershipSettingsAccessor( 16 caller FacadeCallFn, 17 newWatcher NewNotifyWatcherFn, 18 checkAPIVersion CheckAPIVersionFn, 19 ) *LeadershipSettingsAccessor { 20 return &LeadershipSettingsAccessor{caller, newWatcher, checkAPIVersion} 21 } 22 23 type FacadeCallFn func(request string, params, response interface{}) error 24 type NewNotifyWatcherFn func(params.NotifyWatchResult) watcher.NotifyWatcher 25 type CheckAPIVersionFn func(functionName string) error 26 27 // LeadershipSettingsAccessor provides a type that can make RPC calls 28 // to a service which can read, write, and watch leadership settings. 29 type LeadershipSettingsAccessor struct { 30 facadeCaller FacadeCallFn 31 newNotifyWatcher NewNotifyWatcherFn 32 checkAPIVersion CheckAPIVersionFn 33 } 34 35 // Merge merges the provided settings into the leadership settings for 36 // the given application and unit. Only leaders of a given application may perform 37 // this operation. 38 func (lsa *LeadershipSettingsAccessor) Merge(appId, unitId string, settings map[string]string) error { 39 40 if err := lsa.checkAPIVersion("Merge"); err != nil { 41 return errors.Annotatef(err, "cannot access leadership api") 42 } 43 results, err := lsa.bulkMerge(lsa.prepareMerge(appId, unitId, settings)) 44 if err != nil { 45 return errors.Annotatef(err, "failed to call leadership api") 46 } 47 if count := len(results.Results); count != 1 { 48 return errors.Errorf("expected 1 result from leadership api, got %d", count) 49 } 50 if results.Results[0].Error != nil { 51 return errors.Annotatef(results.Results[0].Error, "failed to merge leadership settings") 52 } 53 return nil 54 } 55 56 // Read retrieves the leadership settings for the given application 57 // ID. Anyone may perform this operation. 58 func (lsa *LeadershipSettingsAccessor) Read(appId string) (map[string]string, error) { 59 60 if err := lsa.checkAPIVersion("Read"); err != nil { 61 return nil, errors.Annotatef(err, "cannot access leadership api") 62 } 63 64 results, err := lsa.bulkRead(lsa.prepareRead(appId)) 65 if err != nil { 66 return nil, errors.Annotatef(err, "failed to call leadership api") 67 } 68 if count := len(results.Results); count != 1 { 69 return nil, errors.Errorf("expected 1 result from leadership api, got %d", count) 70 } 71 if results.Results[0].Error != nil { 72 return nil, errors.Annotatef(results.Results[0].Error, "failed to read leadership settings") 73 } 74 return results.Results[0].Settings, nil 75 } 76 77 // WatchLeadershipSettings returns a watcher which can be used to wait 78 // for leadership settings changes to be made for a given application ID. 79 func (lsa *LeadershipSettingsAccessor) WatchLeadershipSettings(appId string) (watcher.NotifyWatcher, error) { 80 81 if err := lsa.checkAPIVersion("WatchLeadershipSettings"); err != nil { 82 return nil, errors.Annotatef(err, "cannot access leadership api") 83 } 84 var results params.NotifyWatchResults 85 if err := lsa.facadeCaller( 86 "WatchLeadershipSettings", 87 params.Entities{[]params.Entity{{names.NewApplicationTag(appId).String()}}}, 88 &results, 89 ); err != nil { 90 return nil, errors.Annotate(err, "failed to call leadership api") 91 } 92 if count := len(results.Results); count != 1 { 93 return nil, errors.Errorf("expected 1 result from leadership api, got %d", count) 94 } 95 if results.Results[0].Error != nil { 96 return nil, errors.Annotatef(results.Results[0].Error, "failed to watch leadership settings") 97 } 98 return lsa.newNotifyWatcher(results.Results[0]), nil 99 } 100 101 // 102 // Prepare functions for building bulk-calls. 103 // 104 105 func (lsa *LeadershipSettingsAccessor) prepareMerge(appId, unitId string, settings map[string]string) params.MergeLeadershipSettingsParam { 106 return params.MergeLeadershipSettingsParam{ 107 ApplicationTag: names.NewApplicationTag(appId).String(), 108 UnitTag: names.NewUnitTag(unitId).String(), 109 Settings: settings, 110 } 111 } 112 113 func (lsa *LeadershipSettingsAccessor) prepareRead(appId string) params.Entity { 114 return params.Entity{Tag: names.NewApplicationTag(appId).String()} 115 } 116 117 // 118 // Bulk calls. 119 // 120 121 func (lsa *LeadershipSettingsAccessor) bulkMerge(args ...params.MergeLeadershipSettingsParam) (*params.ErrorResults, error) { 122 // Don't make the jump over the network if we don't have to. 123 if len(args) <= 0 { 124 return ¶ms.ErrorResults{}, nil 125 } 126 127 bulkArgs := params.MergeLeadershipSettingsBulkParams{Params: args} 128 var results params.ErrorResults 129 return &results, lsa.facadeCaller("Merge", bulkArgs, &results) 130 } 131 132 func (lsa *LeadershipSettingsAccessor) bulkRead(args ...params.Entity) (*params.GetLeadershipSettingsBulkResults, error) { 133 134 // Don't make the jump over the network if we don't have to. 135 if len(args) <= 0 { 136 return ¶ms.GetLeadershipSettingsBulkResults{}, nil 137 } 138 139 bulkArgs := params.Entities{Entities: args} 140 var results params.GetLeadershipSettingsBulkResults 141 return &results, lsa.facadeCaller("Read", bulkArgs, &results) 142 }