github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/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/utils/arch" 10 "github.com/juju/utils/os" 11 "github.com/juju/utils/series" 12 "github.com/juju/version" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/environs" 16 "github.com/juju/juju/environs/bootstrap" 17 coretesting "github.com/juju/juju/testing" 18 "github.com/juju/juju/tools" 19 jujuversion "github.com/juju/juju/version" 20 ) 21 22 type toolsSuite struct { 23 coretesting.BaseSuite 24 } 25 26 var _ = gc.Suite(&toolsSuite{}) 27 28 func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostArch(c *gc.C) { 29 // Host runs amd64, want ppc64 tools. 30 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 31 // Force a dev version by having a non zero build number. 32 // This is because we have not uploaded any tools and auto 33 // upload is only enabled for dev versions. 34 devVersion := jujuversion.Current 35 devVersion.Build = 1234 36 s.PatchValue(&jujuversion.Current, devVersion) 37 env := newEnviron("foo", useDefaultKeys, nil) 38 arch := arch.PPC64EL 39 err := bootstrap.ValidateUploadAllowed(env, &arch, nil) 40 c.Assert(err, gc.ErrorMatches, `cannot build tools for "ppc64el" using a machine running on "amd64"`) 41 } 42 43 func (s *toolsSuite) TestValidateUploadAllowedIncompatibleHostOS(c *gc.C) { 44 // Host runs Ubuntu, want win2012 tools. 45 s.PatchValue(&os.HostOS, func() os.OSType { return os.Ubuntu }) 46 env := newEnviron("foo", useDefaultKeys, nil) 47 series := "win2012" 48 err := bootstrap.ValidateUploadAllowed(env, nil, &series) 49 c.Assert(err, gc.ErrorMatches, `cannot build tools for "win2012" using a machine running "Ubuntu"`) 50 } 51 52 func (s *toolsSuite) TestValidateUploadAllowedIncompatibleTargetArch(c *gc.C) { 53 // Host runs ppc64el, environment only supports amd64, arm64. 54 s.PatchValue(&arch.HostArch, func() string { return arch.PPC64EL }) 55 // Force a dev version by having a non zero build number. 56 // This is because we have not uploaded any tools and auto 57 // upload is only enabled for dev versions. 58 devVersion := jujuversion.Current 59 devVersion.Build = 1234 60 s.PatchValue(&jujuversion.Current, devVersion) 61 env := newEnviron("foo", useDefaultKeys, nil) 62 err := bootstrap.ValidateUploadAllowed(env, nil, nil) 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 centos7 := "centos7" 71 s.PatchValue(&arch.HostArch, func() string { return arm64 }) 72 s.PatchValue(&os.HostOS, func() os.OSType { return os.CentOS }) 73 err := bootstrap.ValidateUploadAllowed(env, &arm64, ¢os7) 74 c.Assert(err, jc.ErrorIsNil) 75 } 76 77 func (s *toolsSuite) TestFindBootstrapTools(c *gc.C) { 78 var called int 79 var filter tools.Filter 80 var findStream string 81 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 82 called++ 83 c.Check(major, gc.Equals, jujuversion.Current.Major) 84 c.Check(minor, gc.Equals, jujuversion.Current.Minor) 85 findStream = stream 86 filter = f 87 return nil, nil 88 }) 89 90 vers := version.MustParse("1.2.1") 91 devVers := version.MustParse("1.2-beta1") 92 arm64 := "arm64" 93 94 type test struct { 95 version *version.Number 96 arch *string 97 series *string 98 dev bool 99 filter tools.Filter 100 stream string 101 } 102 tests := []test{{ 103 version: nil, 104 arch: nil, 105 series: nil, 106 dev: true, 107 filter: tools.Filter{}, 108 }, { 109 version: &vers, 110 arch: nil, 111 series: nil, 112 dev: false, 113 filter: tools.Filter{Number: vers}, 114 }, { 115 version: &vers, 116 arch: &arm64, 117 series: nil, 118 filter: tools.Filter{Arch: arm64, Number: vers}, 119 }, { 120 version: &vers, 121 arch: &arm64, 122 series: nil, 123 dev: true, 124 filter: tools.Filter{Arch: arm64, Number: vers}, 125 }, { 126 version: &devVers, 127 arch: &arm64, 128 series: nil, 129 filter: tools.Filter{Arch: arm64, Number: devVers}, 130 }, { 131 version: &devVers, 132 arch: &arm64, 133 series: nil, 134 filter: tools.Filter{Arch: arm64, Number: devVers}, 135 stream: "devel", 136 }} 137 138 for i, test := range tests { 139 c.Logf("test %d: %#v", i, test) 140 extra := map[string]interface{}{"development": test.dev} 141 if test.stream != "" { 142 extra["agent-stream"] = test.stream 143 } 144 env := newEnviron("foo", useDefaultKeys, extra) 145 bootstrap.FindBootstrapTools(env, test.version, test.arch, test.series) 146 c.Assert(called, gc.Equals, i+1) 147 c.Assert(filter, gc.Equals, test.filter) 148 if test.stream != "" { 149 c.Check(findStream, gc.Equals, test.stream) 150 } else { 151 if test.dev || jujuversion.IsDev(*test.version) { 152 c.Check(findStream, gc.Equals, "devel") 153 } else { 154 c.Check(findStream, gc.Equals, "released") 155 } 156 } 157 } 158 } 159 160 func (s *toolsSuite) TestFindAvailableToolsError(c *gc.C) { 161 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 162 return nil, errors.New("splat") 163 }) 164 env := newEnviron("foo", useDefaultKeys, nil) 165 _, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false) 166 c.Assert(err, gc.ErrorMatches, "splat") 167 } 168 169 func (s *toolsSuite) TestFindAvailableToolsNoUpload(c *gc.C) { 170 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 171 return nil, errors.NotFoundf("tools") 172 }) 173 env := newEnviron("foo", useDefaultKeys, map[string]interface{}{ 174 "agent-version": "1.17.1", 175 }) 176 _, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false) 177 c.Assert(err, jc.Satisfies, errors.IsNotFound) 178 } 179 180 func (s *toolsSuite) TestFindAvailableToolsForceUpload(c *gc.C) { 181 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 182 var findToolsCalled int 183 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 184 findToolsCalled++ 185 return nil, errors.NotFoundf("tools") 186 }) 187 env := newEnviron("foo", useDefaultKeys, nil) 188 uploadedTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, true, true) 189 c.Assert(err, jc.ErrorIsNil) 190 c.Assert(uploadedTools, gc.Not(gc.HasLen), 0) 191 c.Assert(findToolsCalled, gc.Equals, 0) 192 expectedVersion := jujuversion.Current 193 expectedVersion.Build++ 194 for _, tools := range uploadedTools { 195 c.Assert(tools.Version.Number, gc.Equals, expectedVersion) 196 c.Assert(tools.URL, gc.Equals, "") 197 } 198 } 199 200 func (s *toolsSuite) TestFindAvailableToolsForceUploadInvalidArch(c *gc.C) { 201 s.PatchValue(&arch.HostArch, func() string { 202 return arch.I386 203 }) 204 var findToolsCalled int 205 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 206 findToolsCalled++ 207 return nil, errors.NotFoundf("tools") 208 }) 209 env := newEnviron("foo", useDefaultKeys, nil) 210 _, err := bootstrap.FindAvailableTools(env, nil, nil, nil, true, true) 211 c.Assert(err, gc.ErrorMatches, `model "foo" of type dummy does not support instances running on "i386"`) 212 c.Assert(findToolsCalled, gc.Equals, 0) 213 } 214 215 func (s *toolsSuite) TestFindAvailableToolsSpecificVersion(c *gc.C) { 216 currentVersion := version.Binary{ 217 Number: jujuversion.Current, 218 Arch: arch.HostArch(), 219 Series: series.HostSeries(), 220 } 221 currentVersion.Major = 2 222 currentVersion.Minor = 3 223 s.PatchValue(&jujuversion.Current, currentVersion.Number) 224 var findToolsCalled int 225 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 226 c.Assert(f.Number.Major, gc.Equals, 10) 227 c.Assert(f.Number.Minor, gc.Equals, 11) 228 c.Assert(f.Number.Patch, gc.Equals, 12) 229 c.Assert(stream, gc.Equals, "released") 230 findToolsCalled++ 231 return []*tools.Tools{ 232 &tools.Tools{ 233 Version: currentVersion, 234 URL: "http://testing.invalid/tools.tar.gz", 235 }, 236 }, nil 237 }) 238 env := newEnviron("foo", useDefaultKeys, nil) 239 toolsVersion := version.MustParse("10.11.12") 240 result, err := bootstrap.FindAvailableTools(env, &toolsVersion, nil, nil, false, false) 241 c.Assert(err, jc.ErrorIsNil) 242 c.Assert(findToolsCalled, gc.Equals, 1) 243 c.Assert(result, jc.DeepEquals, tools.List{ 244 &tools.Tools{ 245 Version: currentVersion, 246 URL: "http://testing.invalid/tools.tar.gz", 247 }, 248 }) 249 } 250 251 func (s *toolsSuite) TestFindAvailableToolsAutoUpload(c *gc.C) { 252 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 253 trustyTools := &tools.Tools{ 254 Version: version.MustParseBinary("1.2.3-trusty-amd64"), 255 URL: "http://testing.invalid/tools.tar.gz", 256 } 257 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 258 return tools.List{trustyTools}, nil 259 }) 260 env := newEnviron("foo", useDefaultKeys, map[string]interface{}{ 261 "agent-stream": "proposed"}) 262 availableTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, true) 263 c.Assert(err, jc.ErrorIsNil) 264 c.Assert(len(availableTools), jc.GreaterThan, 1) 265 c.Assert(env.supportedArchitecturesCount, gc.Equals, 1) 266 var trustyToolsFound int 267 expectedVersion := jujuversion.Current 268 expectedVersion.Build++ 269 for _, tools := range availableTools { 270 if tools == trustyTools { 271 trustyToolsFound++ 272 } else { 273 c.Assert(tools.Version.Number, gc.Equals, expectedVersion) 274 c.Assert(tools.Version.Series, gc.Not(gc.Equals), "trusty") 275 c.Assert(tools.URL, gc.Equals, "") 276 } 277 } 278 c.Assert(trustyToolsFound, gc.Equals, 1) 279 } 280 281 func (s *toolsSuite) TestFindAvailableToolsCompleteNoValidate(c *gc.C) { 282 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 283 284 var allTools tools.List 285 for _, series := range series.SupportedSeries() { 286 binary := version.Binary{ 287 Number: jujuversion.Current, 288 Series: series, 289 Arch: arch.HostArch(), 290 } 291 allTools = append(allTools, &tools.Tools{ 292 Version: binary, 293 URL: "http://testing.invalid/tools.tar.gz", 294 }) 295 } 296 297 s.PatchValue(bootstrap.FindTools, func(_ environs.Environ, major, minor int, stream string, f tools.Filter) (tools.List, error) { 298 return allTools, nil 299 }) 300 env := newEnviron("foo", useDefaultKeys, nil) 301 availableTools, err := bootstrap.FindAvailableTools(env, nil, nil, nil, false, false) 302 c.Assert(err, jc.ErrorIsNil) 303 c.Assert(availableTools, gc.HasLen, len(allTools)) 304 c.Assert(env.supportedArchitecturesCount, gc.Equals, 0) 305 }