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  }