5
"launchpad.net/juju-core/constraints"
6
"launchpad.net/juju-core/environs/tools"
7
"launchpad.net/juju-core/log"
8
"launchpad.net/juju-core/state"
9
"launchpad.net/juju-core/version"
12
// FindAvailableTools returns a tools.List containing all tools with a given
13
// major version number available in the environment.
14
// If *any* tools are present in private storage, *only* tools from private
15
// storage are available.
16
// If *no* tools are present in private storage, *only* tools from public
17
// storage are available.
18
// If no *available* tools have the supplied major version number, the function
19
// returns a *NotFoundError.
20
func FindAvailableTools(environ Environ, majorVersion int) (list tools.List, err error) {
21
log.Infof("environs: reading tools with major version %d", majorVersion)
22
defer convertToolsError(&err)
23
list, err = tools.ReadList(environ.Storage(), majorVersion)
24
if err == tools.ErrNoTools {
25
log.Infof("environs: falling back to public bucket")
26
list, err = tools.ReadList(environ.PublicStorage(), majorVersion)
31
// FindBootstrapTools returns a ToolsList containing only those tools with
32
// which it would be reasonable to launch an environment's first machine,
33
// given the supplied constraints.
34
// If the environment was not already configured to use a specific agent
35
// version, the newest available version will be chosen and set in the
36
// environment's configuration.
37
func FindBootstrapTools(environ Environ, cons constraints.Value) (list tools.List, err error) {
38
defer convertToolsError(&err)
39
// Collect all possible compatible tools.
40
cliVersion := version.Current.Number
41
if list, err = FindAvailableTools(environ, cliVersion.Major); err != nil {
45
// Discard all that are known to be irrelevant.
46
cfg := environ.Config()
47
series := cfg.DefaultSeries()
48
log.Infof("environs: filtering tools by series: %s", series)
49
filter := tools.Filter{Series: series}
50
if cons.Arch != nil && *cons.Arch != "" {
51
log.Infof("environs: filtering tools by architecture: %s", *cons.Arch)
52
filter.Arch = *cons.Arch
54
if agentVersion, ok := cfg.AgentVersion(); ok {
55
// If we already have an explicit agent version set, we're done.
56
log.Infof("environs: filtering tools by version: %s", agentVersion)
57
filter.Number = agentVersion
58
return list.Match(filter)
60
if dev := cliVersion.IsDev() || cfg.Development(); !dev {
61
log.Infof("environs: filtering tools by released version")
62
filter.Released = true
64
if list, err = list.Match(filter); err != nil {
68
// We probably still have a mix of versions available; discard older ones
69
// and update environment configuration to use only those remaining.
70
agentVersion, list := list.Newest()
71
log.Infof("environs: picked newest version: %s", agentVersion)
72
cfg, err = cfg.Apply(map[string]interface{}{
73
"agent-version": agentVersion.String(),
76
err = environ.SetConfig(cfg)
79
return nil, fmt.Errorf("failed to update environment configuration: %v", err)
84
// FindInstanceTools returns a ToolsList containing only those tools with which
85
// it would be reasonable to start a new instance, given the supplied series and
87
// It is an error to call it with an environment not already configured to use
88
// a specific agent version.
89
func FindInstanceTools(environ Environ, series string, cons constraints.Value) (list tools.List, err error) {
90
defer convertToolsError(&err)
91
// Collect all possible compatible tools.
92
agentVersion, ok := environ.Config().AgentVersion()
94
return nil, fmt.Errorf("no agent version set in environment configuration")
96
if list, err = FindAvailableTools(environ, agentVersion.Major); err != nil {
100
// Discard all that are known to be irrelevant.
101
log.Infof("environs: filtering tools by version: %s", agentVersion)
102
log.Infof("environs: filtering tools by series: %s", series)
103
filter := tools.Filter{
104
Number: agentVersion,
107
if cons.Arch != nil && *cons.Arch != "" {
108
log.Infof("environs: filtering tools by architecture: %s", *cons.Arch)
109
filter.Arch = *cons.Arch
111
return list.Match(filter)
114
// FindExactTools returns only the tools that match the supplied version.
115
// TODO(fwereade) this should not exist: it's used by cmd/jujud/Upgrader,
116
// which needs to run on every agent and must absolutely *not* in general
117
// have access to an Environ.
118
func FindExactTools(environ Environ, vers version.Binary) (t *state.Tools, err error) {
119
defer convertToolsError(&err)
120
list, err := FindAvailableTools(environ, vers.Major)
124
log.Infof("environs: finding exact version %s", vers)
125
list, err = list.Match(tools.Filter{
136
func isToolsError(err error) bool {
138
case tools.ErrNoTools, tools.ErrNoMatches:
144
func convertToolsError(err *error) {
145
if isToolsError(*err) {
146
*err = &NotFoundError{*err}