github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/agent/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  	"github.com/juju/errors"
     8  	"github.com/juju/proxy"
     9  	"gopkg.in/juju/names.v2"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/facade"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/environs/config"
    15  	"github.com/juju/juju/network"
    16  	"github.com/juju/juju/state"
    17  	"github.com/juju/juju/state/watcher"
    18  )
    19  
    20  // ProxyUpdaterV1 defines the pubic methods for the v1 facade.
    21  type ProxyUpdaterV1 interface {
    22  	ProxyConfig(args params.Entities) params.ProxyConfigResultsV1
    23  	WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults
    24  }
    25  
    26  var _ ProxyUpdaterV1 = (*APIv1)(nil)
    27  
    28  // ProxyUpdaterV2 defines the pubic methods for the v2 facade.
    29  type ProxyUpdaterV2 interface {
    30  	ProxyConfig(args params.Entities) params.ProxyConfigResults
    31  	WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults
    32  }
    33  
    34  var _ ProxyUpdaterV2 = (*APIv2)(nil)
    35  
    36  // NewFacadeV1 provides the signature required for facade registration
    37  // and creates a v1 facade.
    38  func NewFacadeV1(ctx facade.Context) (*APIv1, error) {
    39  	api, err := NewFacadeV2(ctx)
    40  	if err != nil {
    41  		return nil, errors.Trace(err)
    42  	}
    43  	return &APIv1{api}, nil
    44  }
    45  
    46  // NewFacadeV2 provides the signature required for facade registration
    47  // and creates a v2 facade.
    48  func NewFacadeV2(ctx facade.Context) (*APIv2, error) {
    49  	api, err := newFacadeBase(ctx)
    50  	if err != nil {
    51  		return nil, errors.Trace(err)
    52  	}
    53  	return &APIv2{api}, nil
    54  }
    55  
    56  func newFacadeBase(ctx facade.Context) (*APIBase, error) {
    57  	st := ctx.State()
    58  	m, err := st.Model()
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return NewAPIBase(
    63  		&stateShim{st: st, m: m},
    64  		ctx.Resources(),
    65  		ctx.Auth(),
    66  	)
    67  }
    68  
    69  // APIv1 provides the ProxyUpdater version 1 facade.
    70  type APIv1 struct {
    71  	*APIv2
    72  }
    73  
    74  // APIv2 provides the ProxyUpdater version 2 facade.
    75  type APIv2 struct {
    76  	*APIBase
    77  }
    78  
    79  type APIBase struct {
    80  	backend    Backend
    81  	resources  facade.Resources
    82  	authorizer facade.Authorizer
    83  }
    84  
    85  // Backend defines the state methods this facade needs, so they can be
    86  // mocked for testing.
    87  type Backend interface {
    88  	ModelConfig() (*config.Config, error)
    89  	APIHostPortsForAgents() ([][]network.HostPort, error)
    90  	WatchAPIHostPortsForAgents() state.NotifyWatcher
    91  	WatchForModelConfigChanges() state.NotifyWatcher
    92  }
    93  
    94  // NewAPIBase creates a new server-side API facade with the given Backing.
    95  func NewAPIBase(backend Backend, resources facade.Resources, authorizer facade.Authorizer) (*APIBase, error) {
    96  	if !(authorizer.AuthMachineAgent() || authorizer.AuthUnitAgent()) {
    97  		return nil, common.ErrPerm
    98  	}
    99  	return &APIBase{
   100  		backend:    backend,
   101  		resources:  resources,
   102  		authorizer: authorizer,
   103  	}, nil
   104  }
   105  
   106  func (api *APIBase) oneWatch() params.NotifyWatchResult {
   107  	var result params.NotifyWatchResult
   108  
   109  	watch := common.NewMultiNotifyWatcher(
   110  		api.backend.WatchForModelConfigChanges(),
   111  		api.backend.WatchAPIHostPortsForAgents())
   112  
   113  	if _, ok := <-watch.Changes(); ok {
   114  		result = params.NotifyWatchResult{
   115  			NotifyWatcherId: api.resources.Register(watch),
   116  		}
   117  	} else {
   118  		result.Error = common.ServerError(watcher.EnsureErr(watch))
   119  	}
   120  	return result
   121  }
   122  
   123  // WatchForProxyConfigAndAPIHostPortChanges watches for cleanups to be perfomed in state
   124  func (api *APIBase) WatchForProxyConfigAndAPIHostPortChanges(args params.Entities) params.NotifyWatchResults {
   125  	results := params.NotifyWatchResults{
   126  		Results: make([]params.NotifyWatchResult, len(args.Entities)),
   127  	}
   128  	errors, _ := api.authEntities(args)
   129  
   130  	for i := range args.Entities {
   131  		if errors.Results[i].Error == nil {
   132  			results.Results[i] = api.oneWatch()
   133  		} else {
   134  			results.Results[i].Error = errors.Results[i].Error
   135  		}
   136  	}
   137  
   138  	return results
   139  }
   140  
   141  func toParams(settings proxy.Settings) params.ProxyConfig {
   142  	return params.ProxyConfig{
   143  		HTTP:    settings.Http,
   144  		HTTPS:   settings.Https,
   145  		FTP:     settings.Ftp,
   146  		NoProxy: settings.FullNoProxy(),
   147  	}
   148  }
   149  
   150  func (api *APIBase) authEntities(args params.Entities) (params.ErrorResults, bool) {
   151  	result := params.ErrorResults{
   152  		Results: make([]params.ErrorResult, len(args.Entities)),
   153  	}
   154  
   155  	var ok bool
   156  
   157  	for i, entity := range args.Entities {
   158  		tag, err := names.ParseTag(entity.Tag)
   159  		if err != nil {
   160  			result.Results[i].Error = common.ServerError(common.ErrPerm)
   161  			continue
   162  		}
   163  		err = common.ErrPerm
   164  		if !api.authorizer.AuthOwner(tag) {
   165  			result.Results[i].Error = common.ServerError(err)
   166  			continue
   167  		}
   168  		ok = true
   169  	}
   170  	return result, ok
   171  }
   172  
   173  func (api *APIBase) proxyConfig() params.ProxyConfigResult {
   174  	var result params.ProxyConfigResult
   175  	config, err := api.backend.ModelConfig()
   176  	if err != nil {
   177  		result.Error = common.ServerError(err)
   178  		return result
   179  	}
   180  
   181  	apiHostPorts, err := api.backend.APIHostPortsForAgents()
   182  	if err != nil {
   183  		result.Error = common.ServerError(err)
   184  		return result
   185  	}
   186  
   187  	jujuProxySettings := config.JujuProxySettings()
   188  	legacyProxySettings := config.LegacyProxySettings()
   189  
   190  	if jujuProxySettings.HasProxySet() {
   191  		jujuProxySettings.AutoNoProxy = network.APIHostPortsToNoProxyString(apiHostPorts)
   192  	} else {
   193  		legacyProxySettings.AutoNoProxy = network.APIHostPortsToNoProxyString(apiHostPorts)
   194  	}
   195  	result.JujuProxySettings = toParams(jujuProxySettings)
   196  	result.LegacyProxySettings = toParams(legacyProxySettings)
   197  
   198  	result.APTProxySettings = toParams(config.AptProxySettings())
   199  
   200  	result.SnapProxySettings = toParams(config.SnapProxySettings())
   201  	result.SnapStoreProxyId = config.SnapStoreProxy()
   202  	result.SnapStoreProxyAssertions = config.SnapStoreAssertions()
   203  
   204  	return result
   205  }
   206  
   207  // ProxyConfig returns the proxy settings for the current model.
   208  func (api *APIBase) ProxyConfig(args params.Entities) params.ProxyConfigResults {
   209  	var result params.ProxyConfigResult
   210  	errors, ok := api.authEntities(args)
   211  
   212  	if ok {
   213  		result = api.proxyConfig()
   214  	}
   215  
   216  	results := params.ProxyConfigResults{
   217  		Results: make([]params.ProxyConfigResult, len(args.Entities)),
   218  	}
   219  	for i := range args.Entities {
   220  		if errors.Results[i].Error == nil {
   221  			results.Results[i] = result
   222  		}
   223  		results.Results[i].Error = errors.Results[i].Error
   224  	}
   225  
   226  	return results
   227  }
   228  
   229  // ProxyConfig returns the proxy settings for the current model.
   230  func (api *APIv1) ProxyConfig(args params.Entities) params.ProxyConfigResultsV1 {
   231  	var result params.ProxyConfigResultV1
   232  	errors, ok := api.authEntities(args)
   233  
   234  	if ok {
   235  		v2 := api.proxyConfig()
   236  		result = params.ProxyConfigResultV1{
   237  			ProxySettings:    v2.LegacyProxySettings,
   238  			APTProxySettings: v2.APTProxySettings,
   239  		}
   240  	}
   241  
   242  	results := params.ProxyConfigResultsV1{
   243  		Results: make([]params.ProxyConfigResultV1, len(args.Entities)),
   244  	}
   245  	for i := range args.Entities {
   246  		if errors.Results[i].Error == nil {
   247  			results.Results[i] = result
   248  		}
   249  		results.Results[i].Error = errors.Results[i].Error
   250  	}
   251  
   252  	return results
   253  }