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  }