github.com/cloudbase/juju-core@v0.0.0-20140504232958-a7271ac7912f/state/apiserver/common/tools.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"launchpad.net/juju-core/environs"
    10  	"launchpad.net/juju-core/environs/config"
    11  	envtools "launchpad.net/juju-core/environs/tools"
    12  	"launchpad.net/juju-core/state"
    13  	"launchpad.net/juju-core/state/api/params"
    14  	coretools "launchpad.net/juju-core/tools"
    15  	"launchpad.net/juju-core/version"
    16  )
    17  
    18  type EntityFinderEnvironConfigGetter interface {
    19  	state.EntityFinder
    20  	EnvironConfig() (*config.Config, error)
    21  }
    22  
    23  // ToolsGetter implements a common Tools method for use by various
    24  // facades.
    25  type ToolsGetter struct {
    26  	st         EntityFinderEnvironConfigGetter
    27  	getCanRead GetAuthFunc
    28  }
    29  
    30  // NewToolsGetter returns a new ToolsGetter. The GetAuthFunc will be
    31  // used on each invocation of Tools to determine current permissions.
    32  func NewToolsGetter(st EntityFinderEnvironConfigGetter, getCanRead GetAuthFunc) *ToolsGetter {
    33  	return &ToolsGetter{
    34  		st:         st,
    35  		getCanRead: getCanRead,
    36  	}
    37  }
    38  
    39  // Tools finds the tools necessary for the given agents.
    40  func (t *ToolsGetter) Tools(args params.Entities) (params.ToolsResults, error) {
    41  	result := params.ToolsResults{
    42  		Results: make([]params.ToolsResult, len(args.Entities)),
    43  	}
    44  	canRead, err := t.getCanRead()
    45  	if err != nil {
    46  		return result, err
    47  	}
    48  	agentVersion, cfg, err := t.getGlobalAgentVersion()
    49  	if err != nil {
    50  		return result, err
    51  	}
    52  	// SSLHostnameVerification defaults to true, so we need to
    53  	// invert that, for backwards-compatibility (older versions
    54  	// will have DisableSSLHostnameVerification: false by default).
    55  	disableSSLHostnameVerification := !cfg.SSLHostnameVerification()
    56  	env, err := environs.New(cfg)
    57  	if err != nil {
    58  		return result, err
    59  	}
    60  	for i, entity := range args.Entities {
    61  		agentTools, err := t.oneAgentTools(canRead, entity.Tag, agentVersion, env)
    62  		if err == nil {
    63  			result.Results[i].Tools = agentTools
    64  			result.Results[i].DisableSSLHostnameVerification = disableSSLHostnameVerification
    65  		}
    66  		result.Results[i].Error = ServerError(err)
    67  	}
    68  	return result, nil
    69  }
    70  
    71  func (t *ToolsGetter) getGlobalAgentVersion() (version.Number, *config.Config, error) {
    72  	// Get the Agent Version requested in the Environment Config
    73  	nothing := version.Number{}
    74  	cfg, err := t.st.EnvironConfig()
    75  	if err != nil {
    76  		return nothing, nil, err
    77  	}
    78  	agentVersion, ok := cfg.AgentVersion()
    79  	if !ok {
    80  		return nothing, nil, fmt.Errorf("agent version not set in environment config")
    81  	}
    82  	return agentVersion, cfg, nil
    83  }
    84  
    85  func (t *ToolsGetter) oneAgentTools(canRead AuthFunc, tag string, agentVersion version.Number, env environs.Environ) (*coretools.Tools, error) {
    86  	if !canRead(tag) {
    87  		return nil, ErrPerm
    88  	}
    89  	entity, err := t.st.FindEntity(tag)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	tooler, ok := entity.(state.AgentTooler)
    94  	if !ok {
    95  		return nil, NotSupportedError(tag, "agent tools")
    96  	}
    97  	existingTools, err := tooler.AgentTools()
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	// TODO(jam): Avoid searching the provider for every machine
   102  	// that wants to upgrade. The information could just be cached
   103  	// in state, or even in the API servers
   104  	return envtools.FindExactTools(env, agentVersion, existingTools.Version.Series, existingTools.Version.Arch)
   105  }
   106  
   107  // ToolsSetter implements a common Tools method for use by various
   108  // facades.
   109  type ToolsSetter struct {
   110  	st          state.EntityFinder
   111  	getCanWrite GetAuthFunc
   112  }
   113  
   114  // NewToolsGetter returns a new ToolsGetter. The GetAuthFunc will be
   115  // used on each invocation of Tools to determine current permissions.
   116  func NewToolsSetter(st state.EntityFinder, getCanWrite GetAuthFunc) *ToolsSetter {
   117  	return &ToolsSetter{
   118  		st:          st,
   119  		getCanWrite: getCanWrite,
   120  	}
   121  }
   122  
   123  // SetTools updates the recorded tools version for the agents.
   124  func (t *ToolsSetter) SetTools(args params.EntitiesVersion) (params.ErrorResults, error) {
   125  	results := params.ErrorResults{
   126  		Results: make([]params.ErrorResult, len(args.AgentTools)),
   127  	}
   128  	canWrite, err := t.getCanWrite()
   129  	if err != nil {
   130  		return results, err
   131  	}
   132  	for i, agentTools := range args.AgentTools {
   133  		err := t.setOneAgentVersion(agentTools.Tag, agentTools.Tools.Version, canWrite)
   134  		results.Results[i].Error = ServerError(err)
   135  	}
   136  	return results, nil
   137  }
   138  
   139  func (t *ToolsSetter) setOneAgentVersion(tag string, vers version.Binary, canWrite AuthFunc) error {
   140  	if !canWrite(tag) {
   141  		return ErrPerm
   142  	}
   143  	entity0, err := t.st.FindEntity(tag)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	entity, ok := entity0.(state.AgentTooler)
   148  	if !ok {
   149  		return NotSupportedError(tag, "agent tools")
   150  	}
   151  	return entity.SetAgentVersion(vers)
   152  }