github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/bootstrap/tools.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package bootstrap
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  
    10  	"github.com/juju/errors"
    11  	"github.com/juju/version/v2"
    12  
    13  	"github.com/juju/juju/core/arch"
    14  	corebase "github.com/juju/juju/core/base"
    15  	"github.com/juju/juju/core/constraints"
    16  	coreos "github.com/juju/juju/core/os"
    17  	"github.com/juju/juju/core/os/ostype"
    18  	"github.com/juju/juju/environs"
    19  	envtools "github.com/juju/juju/environs/tools"
    20  	coretools "github.com/juju/juju/tools"
    21  	jujuversion "github.com/juju/juju/version"
    22  )
    23  
    24  var (
    25  	findTools = envtools.FindTools
    26  )
    27  
    28  func localToolsArch() string {
    29  	toolsArch := os.Getenv("GOARCH")
    30  	if toolsArch == "" {
    31  		toolsArch = arch.HostArch()
    32  	}
    33  	return toolsArch
    34  }
    35  
    36  // validateUploadAllowed returns an error if an attempt to upload tools should
    37  // not be allowed.
    38  func validateUploadAllowed(env environs.ConfigGetter, toolsArch *string, toolsBase *corebase.Base, validator constraints.Validator) error {
    39  	// Now check that the architecture and series for which we are setting up an
    40  	// environment matches that from which we are bootstrapping.
    41  	hostArch := localToolsArch()
    42  	// We can't build tools for a different architecture if one is specified.
    43  	if toolsArch != nil && *toolsArch != hostArch {
    44  		return fmt.Errorf("cannot use agent built for %q using a machine running on %q", *toolsArch, hostArch)
    45  	}
    46  	hostOS := coreos.HostOS()
    47  	if toolsBase != nil {
    48  		if !ostype.OSTypeForName(toolsBase.OS).EquivalentTo(hostOS) {
    49  			return errors.Errorf("cannot use agent built for %q using a machine running %q", toolsBase.String(), hostOS)
    50  		}
    51  	}
    52  	// If no architecture is specified, ensure the target provider supports instances matching our architecture.
    53  	if _, err := validator.Validate(constraints.Value{Arch: &hostArch}); err != nil {
    54  		return errors.Errorf(
    55  			"model %q of type %s does not support instances running on %q",
    56  			env.Config().Name(), env.Config().Type(), hostArch,
    57  		)
    58  	}
    59  	return nil
    60  }
    61  
    62  // findPackagedTools returns a list of tools for in simplestreams.
    63  func findPackagedTools(
    64  	env environs.BootstrapEnviron,
    65  	ss envtools.SimplestreamsFetcher,
    66  	vers *version.Number,
    67  	arch *string, base *corebase.Base,
    68  ) (coretools.List, error) {
    69  	// Look for tools in the environment's simplestreams search paths
    70  	// for existing tools.
    71  
    72  	// If the user hasn't asked for a specified tools version, see if
    73  	// one is configured in the environment.
    74  	if vers == nil {
    75  		if agentVersion, ok := env.Config().AgentVersion(); ok {
    76  			vers = &agentVersion
    77  		}
    78  	}
    79  	logger.Infof("looking for bootstrap agent binaries: version=%v", vers)
    80  	toolsList, findToolsErr := findBootstrapTools(env, ss, vers, arch, base)
    81  	logger.Infof("found %d packaged agent binaries", len(toolsList))
    82  	if findToolsErr != nil {
    83  		return nil, findToolsErr
    84  	}
    85  	return toolsList, nil
    86  }
    87  
    88  // locallyBuildableTools returns the list of tools that
    89  // can be built locally.
    90  func locallyBuildableTools() (buildable coretools.List, _ version.Number, _ error) {
    91  	buildNumber := jujuversion.Current
    92  	// Increment the build number so we know it's a custom build.
    93  	buildNumber.Build++
    94  	if !coreos.HostOS().EquivalentTo(ostype.Ubuntu) {
    95  		return buildable, buildNumber, nil
    96  	}
    97  	binary := version.Binary{
    98  		Number:  buildNumber,
    99  		Release: "ubuntu",
   100  		Arch:    localToolsArch(),
   101  	}
   102  	buildable = append(buildable, &coretools.Tools{Version: binary})
   103  	return buildable, buildNumber, nil
   104  }
   105  
   106  // findBootstrapTools returns a tools.List containing only those tools with
   107  // which it would be reasonable to launch an environment's first machine,
   108  // given the supplied constraints. If a specific agent version is not requested,
   109  // all tools matching the current major.minor version are chosen.
   110  func findBootstrapTools(env environs.BootstrapEnviron, ss envtools.SimplestreamsFetcher, vers *version.Number, arch *string, base *corebase.Base) (list coretools.List, err error) {
   111  	// Construct a tools filter.
   112  	cliVersion := jujuversion.Current
   113  	var filter coretools.Filter
   114  	if arch != nil {
   115  		filter.Arch = *arch
   116  	}
   117  	if base != nil {
   118  		// We can use must here, because we've already validated the base.
   119  		filter.OSType = base.OS
   120  	}
   121  	if vers != nil {
   122  		filter.Number = *vers
   123  	}
   124  	streams := envtools.PreferredStreams(vers, env.Config().Development(), env.Config().AgentStream())
   125  	return findTools(ss, env, cliVersion.Major, cliVersion.Minor, streams, filter)
   126  }