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 }