github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/proxyupdater/proxyupdater.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package proxyupdater 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/proxy" 9 "gopkg.in/juju/names.v2" 10 11 "github.com/juju/juju/apiserver/common" 12 "github.com/juju/juju/apiserver/facade" 13 "github.com/juju/juju/apiserver/params" 14 "github.com/juju/juju/environs/config" 15 "github.com/juju/juju/network" 16 "github.com/juju/juju/state" 17 "github.com/juju/juju/state/watcher" 18 ) 19 20 // ProxyUpdaterV1 defines the pubic methods for the v1 facade. 21 type ProxyUpdaterV1 interface { 22 ProxyConfig(args params.Entities) params.ProxyConfigResultsV1 23 WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults 24 } 25 26 var _ ProxyUpdaterV1 = (*APIv1)(nil) 27 28 // ProxyUpdaterV2 defines the pubic methods for the v2 facade. 29 type ProxyUpdaterV2 interface { 30 ProxyConfig(args params.Entities) params.ProxyConfigResults 31 WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults 32 } 33 34 var _ ProxyUpdaterV2 = (*APIv2)(nil) 35 36 // NewFacadeV1 provides the signature required for facade registration 37 // and creates a v1 facade. 38 func NewFacadeV1(ctx facade.Context) (*APIv1, error) { 39 api, err := NewFacadeV2(ctx) 40 if err != nil { 41 return nil, errors.Trace(err) 42 } 43 return &APIv1{api}, nil 44 } 45 46 // NewFacadeV2 provides the signature required for facade registration 47 // and creates a v2 facade. 48 func NewFacadeV2(ctx facade.Context) (*APIv2, error) { 49 api, err := newFacadeBase(ctx) 50 if err != nil { 51 return nil, errors.Trace(err) 52 } 53 return &APIv2{api}, nil 54 } 55 56 func newFacadeBase(ctx facade.Context) (*APIBase, error) { 57 st := ctx.State() 58 m, err := st.Model() 59 if err != nil { 60 return nil, err 61 } 62 return NewAPIBase( 63 &stateShim{st: st, m: m}, 64 ctx.Resources(), 65 ctx.Auth(), 66 ) 67 } 68 69 // APIv1 provides the ProxyUpdater version 1 facade. 70 type APIv1 struct { 71 *APIv2 72 } 73 74 // APIv2 provides the ProxyUpdater version 2 facade. 75 type APIv2 struct { 76 *APIBase 77 } 78 79 type APIBase struct { 80 backend Backend 81 resources facade.Resources 82 authorizer facade.Authorizer 83 } 84 85 // Backend defines the state methods this facade needs, so they can be 86 // mocked for testing. 87 type Backend interface { 88 ModelConfig() (*config.Config, error) 89 APIHostPortsForAgents() ([][]network.HostPort, error) 90 WatchAPIHostPortsForAgents() state.NotifyWatcher 91 WatchForModelConfigChanges() state.NotifyWatcher 92 } 93 94 // NewAPIBase creates a new server-side API facade with the given Backing. 95 func NewAPIBase(backend Backend, resources facade.Resources, authorizer facade.Authorizer) (*APIBase, error) { 96 if !(authorizer.AuthMachineAgent() || authorizer.AuthUnitAgent()) { 97 return nil, common.ErrPerm 98 } 99 return &APIBase{ 100 backend: backend, 101 resources: resources, 102 authorizer: authorizer, 103 }, nil 104 } 105 106 func (api *APIBase) oneWatch() params.NotifyWatchResult { 107 var result params.NotifyWatchResult 108 109 watch := common.NewMultiNotifyWatcher( 110 api.backend.WatchForModelConfigChanges(), 111 api.backend.WatchAPIHostPortsForAgents()) 112 113 if _, ok := <-watch.Changes(); ok { 114 result = params.NotifyWatchResult{ 115 NotifyWatcherId: api.resources.Register(watch), 116 } 117 } else { 118 result.Error = common.ServerError(watcher.EnsureErr(watch)) 119 } 120 return result 121 } 122 123 // WatchForProxyConfigAndAPIHostPortChanges watches for cleanups to be perfomed in state 124 func (api *APIBase) WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults { 125 results := params.NotifyWatchResults{ 126 Results: make([]params.NotifyWatchResult, len(args.Entities)), 127 } 128 errors, _ := api.authEntities(args) 129 130 for i := range args.Entities { 131 if errors.Results[i].Error == nil { 132 results.Results[i] = api.oneWatch() 133 } else { 134 results.Results[i].Error = errors.Results[i].Error 135 } 136 } 137 138 return results 139 } 140 141 func toParams(settings proxy.Settings) params.ProxyConfig { 142 return params.ProxyConfig{ 143 HTTP: settings.Http, 144 HTTPS: settings.Https, 145 FTP: settings.Ftp, 146 NoProxy: settings.FullNoProxy(), 147 } 148 } 149 150 func (api *APIBase) authEntities(args params.Entities) (params.ErrorResults, bool) { 151 result := params.ErrorResults{ 152 Results: make([]params.ErrorResult, len(args.Entities)), 153 } 154 155 var ok bool 156 157 for i, entity := range args.Entities { 158 tag, err := names.ParseTag(entity.Tag) 159 if err != nil { 160 result.Results[i].Error = common.ServerError(common.ErrPerm) 161 continue 162 } 163 err = common.ErrPerm 164 if !api.authorizer.AuthOwner(tag) { 165 result.Results[i].Error = common.ServerError(err) 166 continue 167 } 168 ok = true 169 } 170 return result, ok 171 } 172 173 func (api *APIBase) proxyConfig() params.ProxyConfigResult { 174 var result params.ProxyConfigResult 175 config, err := api.backend.ModelConfig() 176 if err != nil { 177 result.Error = common.ServerError(err) 178 return result 179 } 180 181 apiHostPorts, err := api.backend.APIHostPortsForAgents() 182 if err != nil { 183 result.Error = common.ServerError(err) 184 return result 185 } 186 187 jujuProxySettings := config.JujuProxySettings() 188 legacyProxySettings := config.LegacyProxySettings() 189 190 if jujuProxySettings.HasProxySet() { 191 jujuProxySettings.AutoNoProxy = network.APIHostPortsToNoProxyString(apiHostPorts) 192 } else { 193 legacyProxySettings.AutoNoProxy = network.APIHostPortsToNoProxyString(apiHostPorts) 194 } 195 result.JujuProxySettings = toParams(jujuProxySettings) 196 result.LegacyProxySettings = toParams(legacyProxySettings) 197 198 result.APTProxySettings = toParams(config.AptProxySettings()) 199 200 result.SnapProxySettings = toParams(config.SnapProxySettings()) 201 result.SnapStoreProxyId = config.SnapStoreProxy() 202 result.SnapStoreProxyAssertions = config.SnapStoreAssertions() 203 204 return result 205 } 206 207 // ProxyConfig returns the proxy settings for the current model. 208 func (api *APIBase) ProxyConfig(args params.Entities) params.ProxyConfigResults { 209 var result params.ProxyConfigResult 210 errors, ok := api.authEntities(args) 211 212 if ok { 213 result = api.proxyConfig() 214 } 215 216 results := params.ProxyConfigResults{ 217 Results: make([]params.ProxyConfigResult, len(args.Entities)), 218 } 219 for i := range args.Entities { 220 if errors.Results[i].Error == nil { 221 results.Results[i] = result 222 } 223 results.Results[i].Error = errors.Results[i].Error 224 } 225 226 return results 227 } 228 229 // ProxyConfig returns the proxy settings for the current model. 230 func (api *APIv1) ProxyConfig(args params.Entities) params.ProxyConfigResultsV1 { 231 var result params.ProxyConfigResultV1 232 errors, ok := api.authEntities(args) 233 234 if ok { 235 v2 := api.proxyConfig() 236 result = params.ProxyConfigResultV1{ 237 ProxySettings: v2.LegacyProxySettings, 238 APTProxySettings: v2.APTProxySettings, 239 } 240 } 241 242 results := params.ProxyConfigResultsV1{ 243 Results: make([]params.ProxyConfigResultV1, len(args.Entities)), 244 } 245 for i := range args.Entities { 246 if errors.Results[i].Error == nil { 247 results.Results[i] = result 248 } 249 results.Results[i].Error = errors.Results[i].Error 250 } 251 252 return results 253 }