github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 } 59 result.Error = common.ServerError(watcher.EnsureErr(watch)) 60 return result 61 } 62 63 // WatchChanges watches for cleanups to be perfomed in state 64 func (api *ProxyUpdaterAPI) WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults { 65 results := params.NotifyWatchResults{ 66 Results: make([]params.NotifyWatchResult, len(args.Entities)), 67 } 68 errors, _ := api.authEntities(args) 69 70 for i := range args.Entities { 71 if errors.Results[i].Error == nil { 72 results.Results[i] = api.oneWatch() 73 } 74 results.Results[i].Error = errors.Results[i].Error 75 } 76 77 return results 78 } 79 80 func proxyUtilsSettingsToProxySettingsParam(settings proxy.Settings) params.ProxyConfig { 81 return params.ProxyConfig{ 82 HTTP: settings.Http, 83 HTTPS: settings.Https, 84 FTP: settings.Ftp, 85 NoProxy: settings.NoProxy, 86 } 87 } 88 89 func (api *ProxyUpdaterAPI) authEntities(args params.Entities) (params.ErrorResults, bool) { 90 result := params.ErrorResults{ 91 Results: make([]params.ErrorResult, len(args.Entities)), 92 } 93 94 var ok bool 95 96 for i, entity := range args.Entities { 97 tag, err := names.ParseTag(entity.Tag) 98 if err != nil { 99 result.Results[i].Error = common.ServerError(common.ErrPerm) 100 continue 101 } 102 err = common.ErrPerm 103 if !api.authorizer.AuthOwner(tag) { 104 result.Results[i].Error = common.ServerError(err) 105 continue 106 } 107 ok = true 108 } 109 return result, ok 110 } 111 112 func (api *ProxyUpdaterAPI) proxyConfig() params.ProxyConfigResult { 113 var result params.ProxyConfigResult 114 env, err := api.backend.ModelConfig() 115 if err != nil { 116 result.Error = common.ServerError(err) 117 return result 118 } 119 120 apiHostPorts, err := api.backend.APIHostPorts() 121 if err != nil { 122 result.Error = common.ServerError(err) 123 return result 124 } 125 126 result.ProxySettings = proxyUtilsSettingsToProxySettingsParam(env.ProxySettings()) 127 result.APTProxySettings = proxyUtilsSettingsToProxySettingsParam(env.AptProxySettings()) 128 129 var noProxy []string 130 if result.ProxySettings.NoProxy != "" { 131 noProxy = strings.Split(result.ProxySettings.NoProxy, ",") 132 } 133 134 noProxySet := set.NewStrings(noProxy...) 135 for _, host := range apiHostPorts { 136 for _, hp := range host { 137 noProxySet.Add(hp.Address.Value) 138 } 139 } 140 result.ProxySettings.NoProxy = strings.Join(noProxySet.SortedValues(), ",") 141 142 return result 143 } 144 145 // ProxyConfig returns the proxy settings for the current environment 146 func (api *ProxyUpdaterAPI) ProxyConfig(args params.Entities) params.ProxyConfigResults { 147 var result params.ProxyConfigResult 148 errors, ok := api.authEntities(args) 149 150 if ok { 151 result = api.proxyConfig() 152 } 153 154 results := params.ProxyConfigResults{ 155 Results: make([]params.ProxyConfigResult, len(args.Entities)), 156 } 157 for i := range args.Entities { 158 if errors.Results[i].Error == nil { 159 results.Results[i] = result 160 } 161 results.Results[i].Error = errors.Results[i].Error 162 } 163 164 return results 165 }