github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/leadership/settings.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package leadership 5 6 import ( 7 "gopkg.in/juju/names.v2" 8 9 "github.com/juju/juju/apiserver/common" 10 "github.com/juju/juju/apiserver/facade" 11 "github.com/juju/juju/apiserver/params" 12 "github.com/juju/juju/core/leadership" 13 ) 14 15 // NewLeadershipSettingsAccessor creates a new 16 // LeadershipSettingsAccessor. 17 func NewLeadershipSettingsAccessor( 18 authorizer facade.Authorizer, 19 registerWatcherFn RegisterWatcherFn, 20 getSettingsFn GetSettingsFn, 21 leaderCheckFn LeaderCheckFn, 22 mergeSettingsChunkFn MergeSettingsChunkFn, 23 ) *LeadershipSettingsAccessor { 24 25 return &LeadershipSettingsAccessor{ 26 authorizer: authorizer, 27 registerWatcherFn: registerWatcherFn, 28 getSettingsFn: getSettingsFn, 29 leaderCheckFn: leaderCheckFn, 30 mergeSettingsChunkFn: mergeSettingsChunkFn, 31 } 32 } 33 34 // SettingsChangeNotifierFn declares a function-type which will return 35 // a channel that can be blocked on to be notified of setting changes 36 // for the provided document key. 37 type RegisterWatcherFn func(serviceId string) (watcherId string, _ error) 38 39 // GetSettingsFn declares a function-type which will return leadership 40 // settings for the given service ID. 41 type GetSettingsFn func(serviceId string) (map[string]string, error) 42 43 // LeaderCheckFn returns a Token whose Check method will return an error 44 // if the unit is not leader of the service. 45 type LeaderCheckFn func(serviceId, unitId string) leadership.Token 46 47 // MergeSettingsChunk declares a function-type which will write the 48 // provided settings chunk into the greater leadership settings for 49 // the provided service ID, so long as the supplied Token remains 50 // valid. 51 type MergeSettingsChunkFn func(token leadership.Token, serviceId string, settings map[string]string) error 52 53 // LeadershipSettingsAccessor provides a type which can read, write, 54 // and watch leadership settings. 55 type LeadershipSettingsAccessor struct { 56 authorizer facade.Authorizer 57 registerWatcherFn RegisterWatcherFn 58 getSettingsFn GetSettingsFn 59 leaderCheckFn LeaderCheckFn 60 mergeSettingsChunkFn MergeSettingsChunkFn 61 } 62 63 // Merge merges in the provided leadership settings. Only leaders for 64 // the given service may perform this operation. 65 func (lsa *LeadershipSettingsAccessor) Merge(bulkArgs params.MergeLeadershipSettingsBulkParams) (params.ErrorResults, error) { 66 67 callerUnitId := lsa.authorizer.GetAuthTag().Id() 68 requireServiceId, err := names.UnitApplication(callerUnitId) 69 if err != nil { 70 return params.ErrorResults{}, err 71 } 72 results := make([]params.ErrorResult, len(bulkArgs.Params)) 73 74 for i, arg := range bulkArgs.Params { 75 result := &results[i] 76 77 // TODO(fwereade): we shoudn't assume a ApplicationTag: we should 78 // use an actual auth func to determine permissions. 79 ApplicationTag, err := names.ParseApplicationTag(arg.ApplicationTag) 80 if err != nil { 81 result.Error = common.ServerError(err) 82 continue 83 } 84 85 serviceId := ApplicationTag.Id() 86 if serviceId != requireServiceId { 87 result.Error = common.ServerError(common.ErrPerm) 88 continue 89 } 90 91 token := lsa.leaderCheckFn(serviceId, callerUnitId) 92 err = lsa.mergeSettingsChunkFn(token, serviceId, arg.Settings) 93 if err != nil { 94 result.Error = common.ServerError(err) 95 } 96 } 97 98 return params.ErrorResults{Results: results}, nil 99 } 100 101 // Read reads leadership settings for the provided service ID. Any 102 // unit of the service may perform this operation. 103 func (lsa *LeadershipSettingsAccessor) Read(bulkArgs params.Entities) (params.GetLeadershipSettingsBulkResults, error) { 104 105 callerUnitId := lsa.authorizer.GetAuthTag().Id() 106 requireServiceId, err := names.UnitApplication(callerUnitId) 107 if err != nil { 108 return params.GetLeadershipSettingsBulkResults{}, err 109 } 110 results := make([]params.GetLeadershipSettingsResult, len(bulkArgs.Entities)) 111 112 for i, arg := range bulkArgs.Entities { 113 result := &results[i] 114 115 // TODO(fwereade): we shoudn't assume a ApplicationTag: we should 116 // use an actual auth func to determine permissions. 117 ApplicationTag, err := names.ParseApplicationTag(arg.Tag) 118 if err != nil { 119 result.Error = common.ServerError(err) 120 continue 121 } 122 123 serviceId := ApplicationTag.Id() 124 if serviceId != requireServiceId { 125 result.Error = common.ServerError(common.ErrPerm) 126 continue 127 } 128 129 settings, err := lsa.getSettingsFn(serviceId) 130 if err != nil { 131 result.Error = common.ServerError(err) 132 continue 133 } 134 135 result.Settings = settings 136 } 137 138 return params.GetLeadershipSettingsBulkResults{results}, nil 139 } 140 141 // WatchLeadershipSettings will block the caller until leadership settings 142 // for the given service ID change. 143 func (lsa *LeadershipSettingsAccessor) WatchLeadershipSettings(bulkArgs params.Entities) (params.NotifyWatchResults, error) { 144 145 callerUnitId := lsa.authorizer.GetAuthTag().Id() 146 requireServiceId, err := names.UnitApplication(callerUnitId) 147 if err != nil { 148 return params.NotifyWatchResults{}, err 149 } 150 results := make([]params.NotifyWatchResult, len(bulkArgs.Entities)) 151 152 for i, arg := range bulkArgs.Entities { 153 result := &results[i] 154 155 // TODO(fwereade): we shoudn't assume a ApplicationTag: we should 156 // use an actual auth func to determine permissions. 157 ApplicationTag, err := names.ParseApplicationTag(arg.Tag) 158 if err != nil { 159 result.Error = common.ServerError(err) 160 continue 161 } 162 163 serviceId := ApplicationTag.Id() 164 if serviceId != requireServiceId { 165 result.Error = common.ServerError(common.ErrPerm) 166 continue 167 } 168 169 watcherId, err := lsa.registerWatcherFn(serviceId) 170 if err != nil { 171 result.Error = common.ServerError(err) 172 continue 173 } 174 175 result.NotifyWatcherId = watcherId 176 } 177 return params.NotifyWatchResults{Results: results}, nil 178 }