github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/apiserver/agenttools/agenttools.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package agenttools
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/loggo"
     9  	"github.com/juju/version"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/environs/tools"
    15  	"github.com/juju/juju/state"
    16  	coretools "github.com/juju/juju/tools"
    17  )
    18  
    19  func init() {
    20  	common.RegisterStandardFacade("AgentTools", 1, NewAgentToolsAPI)
    21  }
    22  
    23  var logger = loggo.GetLogger("juju.apiserver.model")
    24  
    25  var (
    26  	findTools = tools.FindTools
    27  )
    28  
    29  // AgentToolsAPI implements the API used by the machine model worker.
    30  type AgentToolsAPI struct {
    31  	st         EnvironGetter
    32  	authorizer common.Authorizer
    33  	// tools lookup
    34  	findTools        toolsFinder
    35  	envVersionUpdate envVersionUpdater
    36  }
    37  
    38  // NewAgentToolsAPI creates a new instance of the Model API.
    39  func NewAgentToolsAPI(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*AgentToolsAPI, error) {
    40  	return &AgentToolsAPI{
    41  		st:               st,
    42  		authorizer:       authorizer,
    43  		findTools:        findTools,
    44  		envVersionUpdate: envVersionUpdate,
    45  	}, nil
    46  }
    47  
    48  // EnvironGetter represents a struct that can provide a state.Environment.
    49  type EnvironGetter interface {
    50  	Model() (*state.Model, error)
    51  }
    52  
    53  type toolsFinder func(environs.Environ, int, int, string, coretools.Filter) (coretools.List, error)
    54  type envVersionUpdater func(*state.Model, version.Number) error
    55  
    56  var newEnvirons = environs.New
    57  
    58  func checkToolsAvailability(cfg *config.Config, finder toolsFinder) (version.Number, error) {
    59  	currentVersion, ok := cfg.AgentVersion()
    60  	if !ok || currentVersion == version.Zero {
    61  		return version.Zero, nil
    62  	}
    63  
    64  	env, err := newEnvirons(cfg)
    65  	if err != nil {
    66  		return version.Zero, errors.Annotatef(err, "cannot make model")
    67  	}
    68  
    69  	// finder receives major and minor as parameters as it uses them to filter versions and
    70  	// only return patches for the passed major.minor (from major.minor.patch).
    71  	// We'll try the released stream first, then fall back to the current configured stream
    72  	// if no released tools are found.
    73  	vers, err := finder(env, currentVersion.Major, currentVersion.Minor, tools.ReleasedStream, coretools.Filter{})
    74  	preferredStream := tools.PreferredStream(&currentVersion, cfg.Development(), cfg.AgentStream())
    75  	if preferredStream != tools.ReleasedStream && errors.Cause(err) == coretools.ErrNoMatches {
    76  		vers, err = finder(env, currentVersion.Major, currentVersion.Minor, preferredStream, coretools.Filter{})
    77  	}
    78  	if err != nil {
    79  		return version.Zero, errors.Annotatef(err, "cannot find available tools")
    80  	}
    81  	// Newest also returns a list of the items in this list matching with the
    82  	// newest version.
    83  	newest, _ := vers.Newest()
    84  	return newest, nil
    85  }
    86  
    87  var envConfig = func(e *state.Model) (*config.Config, error) {
    88  	return e.Config()
    89  }
    90  
    91  // Base implementation of envVersionUpdater
    92  func envVersionUpdate(env *state.Model, ver version.Number) error {
    93  	return env.UpdateLatestToolsVersion(ver)
    94  }
    95  
    96  func updateToolsAvailability(st EnvironGetter, finder toolsFinder, update envVersionUpdater) error {
    97  	env, err := st.Model()
    98  	if err != nil {
    99  		return errors.Annotate(err, "cannot get model")
   100  	}
   101  	cfg, err := envConfig(env)
   102  	if err != nil {
   103  		return errors.Annotate(err, "cannot get config")
   104  	}
   105  	ver, err := checkToolsAvailability(cfg, finder)
   106  	if err != nil {
   107  		if errors.IsNotFound(err) {
   108  			// No newer tools, so exit silently.
   109  			return nil
   110  		}
   111  		return errors.Annotate(err, "cannot get latest version")
   112  	}
   113  	if ver == version.Zero {
   114  		logger.Debugf("tools lookup returned version Zero, this should only happen during bootstrap.")
   115  		return nil
   116  	}
   117  	return update(env, ver)
   118  }
   119  
   120  // UpdateToolsAvailable invokes a lookup and further update in environ
   121  // for new patches of the current tool versions.
   122  func (api *AgentToolsAPI) UpdateToolsAvailable() error {
   123  	if !api.authorizer.AuthModelManager() {
   124  		return common.ErrPerm
   125  	}
   126  	return updateToolsAvailability(api.st, api.findTools, api.envVersionUpdate)
   127  }