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