github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/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 "strings" 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/environs/config" 13 "github.com/juju/juju/network" 14 "github.com/juju/juju/state" 15 "github.com/juju/juju/state/watcher" 16 "github.com/juju/utils/proxy" 17 "github.com/juju/utils/set" 18 "gopkg.in/juju/names.v2" 19 ) 20 21 // Backend defines the state methods this facade needs, so they can be 22 // mocked for testing. 23 type Backend interface { 24 ModelConfig() (*config.Config, error) 25 APIHostPorts() ([][]network.HostPort, error) 26 WatchAPIHostPorts() state.NotifyWatcher 27 WatchForModelConfigChanges() state.NotifyWatcher 28 } 29 30 type ProxyUpdaterAPI struct { 31 backend Backend 32 resources facade.Resources 33 authorizer facade.Authorizer 34 } 35 36 // NewAPIWithBacking creates a new server-side API facade with the given Backing. 37 func NewAPIWithBacking(st Backend, resources facade.Resources, authorizer facade.Authorizer) (*ProxyUpdaterAPI, error) { 38 if !(authorizer.AuthMachineAgent() || authorizer.AuthUnitAgent()) { 39 return &ProxyUpdaterAPI{}, common.ErrPerm 40 } 41 return &ProxyUpdaterAPI{ 42 backend: st, 43 resources: resources, 44 authorizer: authorizer, 45 }, nil 46 } 47 48 func (api *ProxyUpdaterAPI) oneWatch() params.NotifyWatchResult { 49 var result params.NotifyWatchResult 50 51 watch := common.NewMultiNotifyWatcher( 52 api.backend.WatchForModelConfigChanges(), 53 api.backend.WatchAPIHostPorts()) 54 55 if _, ok := <-watch.Changes(); ok { 56 result = params.NotifyWatchResult{ 57 NotifyWatcherId: api.resources.Register(watch), 58 } 59 } else { 60 result.Error = common.ServerError(watcher.EnsureErr(watch)) 61 } 62 return result 63 } 64 65 // WatchForProxyConfigAndAPIHostPortChanges watches for cleanups to be perfomed in state 66 func (api *ProxyUpdaterAPI) WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults { 67 results := params.NotifyWatchResults{ 68 Results: make([]params.NotifyWatchResult, len(args.Entities)), 69 } 70 errors, _ := api.authEntities(args) 71 72 for i := range args.Entities { 73 if errors.Results[i].Error == nil { 74 results.Results[i] = api.oneWatch() 75 } else { 76 results.Results[i].Error = errors.Results[i].Error 77 } 78 } 79 80 return results 81 } 82 83 func proxyUtilsSettingsToProxySettingsParam(settings proxy.Settings) params.ProxyConfig { 84 return params.ProxyConfig{ 85 HTTP: settings.Http, 86 HTTPS: settings.Https, 87 FTP: settings.Ftp, 88 NoProxy: settings.NoProxy, 89 } 90 } 91 92 func (api *ProxyUpdaterAPI) authEntities(args params.Entities) (params.ErrorResults, bool) { 93 result := params.ErrorResults{ 94 Results: make([]params.ErrorResult, len(args.Entities)), 95 } 96 97 var ok bool 98 99 for i, entity := range args.Entities { 100 tag, err := names.ParseTag(entity.Tag) 101 if err != nil { 102 result.Results[i].Error = common.ServerError(common.ErrPerm) 103 continue 104 } 105 err = common.ErrPerm 106 if !api.authorizer.AuthOwner(tag) { 107 result.Results[i].Error = common.ServerError(err) 108 continue 109 } 110 ok = true 111 } 112 return result, ok 113 } 114 115 func (api *ProxyUpdaterAPI) proxyConfig() params.ProxyConfigResult { 116 var result params.ProxyConfigResult 117 env, err := api.backend.ModelConfig() 118 if err != nil { 119 result.Error = common.ServerError(err) 120 return result 121 } 122 123 apiHostPorts, err := api.backend.APIHostPorts() 124 if err != nil { 125 result.Error = common.ServerError(err) 126 return result 127 } 128 129 result.ProxySettings = proxyUtilsSettingsToProxySettingsParam(env.ProxySettings()) 130 result.APTProxySettings = proxyUtilsSettingsToProxySettingsParam(env.AptProxySettings()) 131 132 var noProxy []string 133 if result.ProxySettings.NoProxy != "" { 134 noProxy = strings.Split(result.ProxySettings.NoProxy, ",") 135 } 136 137 noProxySet := set.NewStrings(noProxy...) 138 for _, host := range apiHostPorts { 139 for _, hp := range host { 140 noProxySet.Add(hp.Address.Value) 141 } 142 } 143 result.ProxySettings.NoProxy = strings.Join(noProxySet.SortedValues(), ",") 144 145 return result 146 } 147 148 // ProxyConfig returns the proxy settings for the current environment 149 func (api *ProxyUpdaterAPI) ProxyConfig(args params.Entities) params.ProxyConfigResults { 150 var result params.ProxyConfigResult 151 errors, ok := api.authEntities(args) 152 153 if ok { 154 result = api.proxyConfig() 155 } 156 157 results := params.ProxyConfigResults{ 158 Results: make([]params.ProxyConfigResult, len(args.Entities)), 159 } 160 for i := range args.Entities { 161 if errors.Results[i].Error == nil { 162 results.Results[i] = result 163 } 164 results.Results[i].Error = errors.Results[i].Error 165 } 166 167 return results 168 }