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

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package bootstrap_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	jc "github.com/juju/testing/checkers"
     9  	"github.com/juju/version/v2"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/core/arch"
    13  	corebase "github.com/juju/juju/core/base"
    14  	"github.com/juju/juju/core/os"
    15  	"github.com/juju/juju/core/os/ostype"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/bootstrap"
    18  	"github.com/juju/juju/environs/context"
    19  	"github.com/juju/juju/environs/simplestreams"
    20  	sstesting "github.com/juju/juju/environs/simplestreams/testing"
    21  	envtools "github.com/juju/juju/environs/tools"
    22  	coretesting "github.com/juju/juju/testing"
    23  	"github.com/juju/juju/tools"
    24  	jujuversion "github.com/juju/juju/version"
    25  )
    26  
    27  type toolsSuite struct {
    28  	coretesting.BaseSuite
    29  }
    30  
    31  var _ = gc.Suite(&toolsSuite{})
    32  
    33  func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostArch(c *gc.C) {
    34  	// Host runs amd64, want ppc64 tools.
    35  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
    36  	// Force a dev version by having a non zero build number.
    37  	// This is because we have not uploaded any tools and auto
    38  	// upload is only enabled for dev versions.
    39  	devVersion := jujuversion.Current
    40  	devVersion.Build = 1234
    41  	s.PatchValue(&jujuversion.Current, devVersion)
    42  	env := newEnviron("foo", useDefaultKeys, nil)
    43  	arch := arch.PPC64EL
    44  	validator, err := env.ConstraintsValidator(context.NewEmptyCloudCallContext())
    45  	c.Assert(err, jc.ErrorIsNil)
    46  	err = bootstrap.ValidateUploadAllowed(env, &arch, nil, validator)
    47  	c.Assert(err, gc.ErrorMatches, `cannot use agent built for "ppc64el" using a machine running on "amd64"`)
    48  }
    49  
    50  func (s *toolsSuite) TestValidateUploadAllowedIncompatibleTargetArch(c *gc.C) {
    51  	// Host runs ppc64el, environment only supports amd64, arm64.
    52  	s.PatchValue(&arch.HostArch, func() string { return arch.PPC64EL })
    53  	// Force a dev version by having a non zero build number.
    54  	// This is because we have not uploaded any tools and auto
    55  	// upload is only enabled for dev versions.
    56  	devVersion := jujuversion.Current
    57  	devVersion.Build = 1234
    58  	s.PatchValue(&jujuversion.Current, devVersion)
    59  	env := newEnviron("foo", useDefaultKeys, nil)
    60  	validator, err := env.ConstraintsValidator(context.NewEmptyCloudCallContext())
    61  	c.Assert(err, jc.ErrorIsNil)
    62  	err = bootstrap.ValidateUploadAllowed(env, nil, nil, validator)
    63  	c.Assert(err, gc.ErrorMatches, `model "foo" of type dummy does not support instances running on "ppc64el"`)
    64  }
    65  
    66  func (s *toolsSuite) TestValidateUploadAllowed(c *gc.C) {
    67  	env := newEnviron("foo", useDefaultKeys, nil)
    68  	// Host runs arm64, environment supports arm64.
    69  	arm64 := "arm64"
    70  	ubuntuFocal := corebase.MustParseBaseFromString("ubuntu@20.04")
    71  	s.PatchValue(&arch.HostArch, func() string { return arm64 })
    72  	s.PatchValue(&os.HostOS, func() ostype.OSType { return ostype.Ubuntu })
    73  	validator, err := env.ConstraintsValidator(context.NewEmptyCloudCallContext())
    74  	c.Assert(err, jc.ErrorIsNil)
    75  	err = bootstrap.ValidateUploadAllowed(env, &arm64, &ubuntuFocal, validator)
    76  	c.Assert(err, jc.ErrorIsNil)
    77  }
    78  
    79  func (s *toolsSuite) TestFindBootstrapTools(c *gc.C) {
    80  	var called int
    81  	var filter tools.Filter
    82  	var findStreams []string
    83  	s.PatchValue(bootstrap.FindTools, func(_ envtools.SimplestreamsFetcher, _ environs.BootstrapEnviron, major, minor int, streams []string, f tools.Filter) (tools.List, error) {
    84  		called++
    85  		c.Check(major, gc.Equals, jujuversion.Current.Major)
    86  		c.Check(minor, gc.Equals, jujuversion.Current.Minor)
    87  		findStreams = streams
    88  		filter = f
    89  		return nil, nil
    90  	})
    91  
    92  	vers := version.MustParse("1.2.1")
    93  	devVers := version.MustParse("1.2-beta1")
    94  	arm64 := "arm64"
    95  
    96  	type test struct {
    97  		version *version.Number
    98  		arch    *string
    99  		base    *corebase.Base
   100  		dev     bool
   101  		filter  tools.Filter
   102  		streams []string
   103  	}
   104  	tests := []test{{
   105  		version: nil,
   106  		arch:    nil,
   107  		base:    nil,
   108  		dev:     true,
   109  		filter:  tools.Filter{},
   110  	}, {
   111  		version: &vers,
   112  		arch:    nil,
   113  		base:    nil,
   114  		dev:     false,
   115  		filter:  tools.Filter{Number: vers},
   116  	}, {
   117  		version: &vers,
   118  		arch:    &arm64,
   119  		base:    nil,
   120  		filter:  tools.Filter{Arch: arm64, Number: vers},
   121  	}, {
   122  		version: &vers,
   123  		arch:    &arm64,
   124  		base:    nil,
   125  		dev:     true,
   126  		filter:  tools.Filter{Arch: arm64, Number: vers},
   127  	}, {
   128  		version: &devVers,
   129  		arch:    &arm64,
   130  		base:    nil,
   131  		filter:  tools.Filter{Arch: arm64, Number: devVers},
   132  	}, {
   133  		version: &devVers,
   134  		arch:    &arm64,
   135  		base:    nil,
   136  		filter:  tools.Filter{Arch: arm64, Number: devVers},
   137  		streams: []string{"devel", "proposed", "released"},
   138  	}}
   139  
   140  	ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
   141  	for i, test := range tests {
   142  		c.Logf("test %d: %#v", i, test)
   143  		extra := map[string]interface{}{"development": test.dev}
   144  		if test.streams != nil {
   145  			extra["agent-stream"] = test.streams[0]
   146  		}
   147  		env := newEnviron("foo", useDefaultKeys, extra)
   148  		bootstrap.FindBootstrapTools(env, ss, test.version, test.arch, test.base)
   149  		c.Assert(called, gc.Equals, i+1)
   150  		c.Assert(filter, gc.Equals, test.filter)
   151  		if test.streams != nil {
   152  			c.Check(findStreams, gc.DeepEquals, test.streams)
   153  		} else {
   154  			if test.dev || jujuversion.IsDev(*test.version) {
   155  				c.Check(findStreams, gc.DeepEquals, []string{"devel", "proposed", "released"})
   156  			} else {
   157  				c.Check(findStreams, gc.DeepEquals, []string{"released"})
   158  			}
   159  		}
   160  	}
   161  }
   162  
   163  func (s *toolsSuite) TestFindAvailableToolsError(c *gc.C) {
   164  	// TODO (stickupkid): Remove the patch and pass in a valid mock.
   165  	s.PatchValue(bootstrap.FindTools, func(_ envtools.SimplestreamsFetcher, _ environs.BootstrapEnviron, major, minor int, streams []string, f tools.Filter) (tools.List, error) {
   166  		return nil, errors.New("splat")
   167  	})
   168  	env := newEnviron("foo", useDefaultKeys, nil)
   169  	ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
   170  	_, err := bootstrap.FindPackagedTools(env, ss, nil, nil, nil)
   171  	c.Assert(err, gc.ErrorMatches, "splat")
   172  }
   173  
   174  func (s *toolsSuite) TestFindAvailableToolsNoUpload(c *gc.C) {
   175  	s.PatchValue(bootstrap.FindTools, func(_ envtools.SimplestreamsFetcher, _ environs.BootstrapEnviron, major, minor int, streams []string, f tools.Filter) (tools.List, error) {
   176  		return nil, errors.NotFoundf("tools")
   177  	})
   178  	env := newEnviron("foo", useDefaultKeys, map[string]interface{}{
   179  		"agent-version": "1.17.1",
   180  	})
   181  	ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
   182  	_, err := bootstrap.FindPackagedTools(env, ss, nil, nil, nil)
   183  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   184  }
   185  
   186  func (s *toolsSuite) TestFindAvailableToolsSpecificVersion(c *gc.C) {
   187  	currentVersion := coretesting.CurrentVersion()
   188  	currentVersion.Major = 2
   189  	currentVersion.Minor = 3
   190  	s.PatchValue(&jujuversion.Current, currentVersion.Number)
   191  	var findToolsCalled int
   192  	s.PatchValue(bootstrap.FindTools, func(_ envtools.SimplestreamsFetcher, _ environs.BootstrapEnviron, major, minor int, streams []string, f tools.Filter) (tools.List, error) {
   193  		c.Assert(f.Number.Major, gc.Equals, 10)
   194  		c.Assert(f.Number.Minor, gc.Equals, 11)
   195  		c.Assert(f.Number.Patch, gc.Equals, 12)
   196  		c.Assert(streams, gc.DeepEquals, []string{"released"})
   197  		findToolsCalled++
   198  		return []*tools.Tools{
   199  			{
   200  				Version: currentVersion,
   201  				URL:     "http://testing.invalid/tools.tar.gz",
   202  			},
   203  		}, nil
   204  	})
   205  	env := newEnviron("foo", useDefaultKeys, nil)
   206  	toolsVersion := version.MustParse("10.11.12")
   207  	ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
   208  	result, err := bootstrap.FindPackagedTools(env, ss, &toolsVersion, nil, nil)
   209  	c.Assert(err, jc.ErrorIsNil)
   210  	c.Assert(findToolsCalled, gc.Equals, 1)
   211  	c.Assert(result, jc.DeepEquals, tools.List{
   212  		&tools.Tools{
   213  			Version: currentVersion,
   214  			URL:     "http://testing.invalid/tools.tar.gz",
   215  		},
   216  	})
   217  }
   218  
   219  func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) {
   220  	s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 })
   221  	s.PatchValue(&corebase.UbuntuDistroInfo, "/path/notexists")
   222  
   223  	allTools := tools.List{
   224  		&tools.Tools{
   225  			Version: version.Binary{
   226  				Number:  jujuversion.Current,
   227  				Release: "ubuntu",
   228  				Arch:    arch.HostArch(),
   229  			},
   230  			URL: "http://testing.invalid/tools.tar.gz",
   231  		},
   232  	}
   233  
   234  	s.PatchValue(bootstrap.FindTools, func(_ envtools.SimplestreamsFetcher, _ environs.BootstrapEnviron, major, minor int, streams []string, f tools.Filter) (tools.List, error) {
   235  		return allTools, nil
   236  	})
   237  	env := newEnviron("foo", useDefaultKeys, nil)
   238  	ss := simplestreams.NewSimpleStreams(sstesting.TestDataSourceFactory())
   239  	availableTools, err := bootstrap.FindPackagedTools(env, ss, nil, nil, nil)
   240  	c.Assert(err, jc.ErrorIsNil)
   241  	c.Assert(availableTools, gc.HasLen, len(allTools))
   242  	c.Assert(env.constraintsValidatorCount, gc.Equals, 0)
   243  }