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(¤tVersion, 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 }