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