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