github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/environs/testing/tools.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package testing 5 6 import ( 7 "bytes" 8 "fmt" 9 "os" 10 "path/filepath" 11 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils" 14 "github.com/juju/utils/set" 15 gc "gopkg.in/check.v1" 16 17 agenttools "github.com/juju/juju/agent/tools" 18 "github.com/juju/juju/environs/filestorage" 19 "github.com/juju/juju/environs/storage" 20 envtools "github.com/juju/juju/environs/tools" 21 "github.com/juju/juju/juju/names" 22 "github.com/juju/juju/state" 23 coretesting "github.com/juju/juju/testing" 24 coretools "github.com/juju/juju/tools" 25 "github.com/juju/juju/version" 26 "github.com/juju/juju/worker/upgrader" 27 ) 28 29 // toolsLtsSeries records the known Ubuntu LTS series. 30 var toolsLtsSeries = []string{"precise", "trusty"} 31 32 // ToolsFixture is used as a fixture to stub out the default tools URL so we 33 // don't hit the real internet during tests. 34 type ToolsFixture struct { 35 origDefaultURL string 36 DefaultBaseURL string 37 38 // UploadArches holds the architectures of tools to 39 // upload in UploadFakeTools. If empty, it will default 40 // to just version.Current.Arch. 41 UploadArches []string 42 } 43 44 func (s *ToolsFixture) SetUpTest(c *gc.C) { 45 s.origDefaultURL = envtools.DefaultBaseURL 46 envtools.DefaultBaseURL = s.DefaultBaseURL 47 } 48 49 func (s *ToolsFixture) TearDownTest(c *gc.C) { 50 envtools.DefaultBaseURL = s.origDefaultURL 51 } 52 53 // UploadFakeToolsToDirectory uploads fake tools of the architectures in 54 // s.UploadArches for each LTS release to the specified directory. 55 func (s *ToolsFixture) UploadFakeToolsToDirectory(c *gc.C, dir, toolsDir, stream string) { 56 stor, err := filestorage.NewFileStorageWriter(dir) 57 c.Assert(err, jc.ErrorIsNil) 58 s.UploadFakeTools(c, stor, toolsDir, stream) 59 } 60 61 // UploadFakeTools uploads fake tools of the architectures in 62 // s.UploadArches for each LTS release to the specified storage. 63 func (s *ToolsFixture) UploadFakeTools(c *gc.C, stor storage.Storage, toolsDir, stream string) { 64 arches := s.UploadArches 65 if len(arches) == 0 { 66 arches = []string{version.Current.Arch} 67 } 68 var versions []version.Binary 69 for _, arch := range arches { 70 v := version.Current 71 v.Arch = arch 72 for _, series := range toolsLtsSeries { 73 v.Series = series 74 versions = append(versions, v) 75 } 76 } 77 _, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...) 78 c.Assert(err, jc.ErrorIsNil) 79 } 80 81 // RemoveFakeToolsMetadata deletes the fake simplestreams tools metadata from the supplied storage. 82 func RemoveFakeToolsMetadata(c *gc.C, stor storage.Storage) { 83 files, err := stor.List("tools/streams") 84 c.Assert(err, jc.ErrorIsNil) 85 for _, file := range files { 86 err = stor.Remove(file) 87 c.Check(err, jc.ErrorIsNil) 88 } 89 } 90 91 // CheckTools ensures the obtained and expected tools are equal, allowing for the fact that 92 // the obtained tools may not have size and checksum set. 93 func CheckTools(c *gc.C, obtained, expected *coretools.Tools) { 94 c.Assert(obtained.Version, gc.Equals, expected.Version) 95 // TODO(dimitern) 2013-10-02 bug #1234217 96 // Are these used at at all? If not we should drop them. 97 if obtained.URL != "" { 98 c.Assert(obtained.URL, gc.Equals, expected.URL) 99 } 100 if obtained.Size > 0 { 101 c.Assert(obtained.Size, gc.Equals, expected.Size) 102 c.Assert(obtained.SHA256, gc.Equals, expected.SHA256) 103 } 104 } 105 106 // CheckUpgraderReadyError ensures the obtained and expected errors are equal. 107 func CheckUpgraderReadyError(c *gc.C, obtained error, expected *upgrader.UpgradeReadyError) { 108 c.Assert(obtained, gc.FitsTypeOf, &upgrader.UpgradeReadyError{}) 109 err := obtained.(*upgrader.UpgradeReadyError) 110 c.Assert(err.AgentName, gc.Equals, expected.AgentName) 111 c.Assert(err.DataDir, gc.Equals, expected.DataDir) 112 c.Assert(err.OldTools, gc.Equals, expected.OldTools) 113 c.Assert(err.NewTools, gc.Equals, expected.NewTools) 114 } 115 116 // PrimeTools sets up the current version of the tools to vers and 117 // makes sure that they're available in the dataDir. 118 func PrimeTools(c *gc.C, stor storage.Storage, dataDir, toolsDir string, vers version.Binary) *coretools.Tools { 119 err := os.RemoveAll(filepath.Join(dataDir, "tools")) 120 c.Assert(err, jc.ErrorIsNil) 121 agentTools, err := uploadFakeToolsVersion(stor, toolsDir, vers) 122 c.Assert(err, jc.ErrorIsNil) 123 resp, err := utils.GetValidatingHTTPClient().Get(agentTools.URL) 124 c.Assert(err, jc.ErrorIsNil) 125 defer resp.Body.Close() 126 err = agenttools.UnpackTools(dataDir, agentTools, resp.Body) 127 c.Assert(err, jc.ErrorIsNil) 128 return agentTools 129 } 130 131 func uploadFakeToolsVersion(stor storage.Storage, toolsDir string, vers version.Binary) (*coretools.Tools, error) { 132 logger.Infof("uploading FAKE tools %s", vers) 133 tgz, checksum := makeFakeTools(vers) 134 size := int64(len(tgz)) 135 name := envtools.StorageName(vers, toolsDir) 136 if err := stor.Put(name, bytes.NewReader(tgz), size); err != nil { 137 return nil, err 138 } 139 url, err := stor.URL(name) 140 if err != nil { 141 return nil, err 142 } 143 return &coretools.Tools{URL: url, Version: vers, Size: size, SHA256: checksum}, nil 144 } 145 146 // InstallFakeDownloadedTools creates and unpacks fake tools of the 147 // given version into the data directory specified. 148 func InstallFakeDownloadedTools(c *gc.C, dataDir string, vers version.Binary) *coretools.Tools { 149 tgz, checksum := makeFakeTools(vers) 150 agentTools := &coretools.Tools{ 151 Version: vers, 152 Size: int64(len(tgz)), 153 SHA256: checksum, 154 } 155 err := agenttools.UnpackTools(dataDir, agentTools, bytes.NewReader(tgz)) 156 c.Assert(err, jc.ErrorIsNil) 157 return agentTools 158 } 159 160 func makeFakeTools(vers version.Binary) ([]byte, string) { 161 return coretesting.TarGz( 162 coretesting.NewTarFile(names.Jujud, 0777, "jujud contents "+vers.String())) 163 } 164 165 // UploadFakeToolsVersions puts fake tools in the supplied storage for the supplied versions. 166 func UploadFakeToolsVersions(stor storage.Storage, toolsDir, stream string, versions ...version.Binary) ([]*coretools.Tools, error) { 167 // Leave existing tools alone. 168 existingTools := make(map[version.Binary]*coretools.Tools) 169 existing, _ := envtools.ReadList(stor, toolsDir, 1, -1) 170 for _, tools := range existing { 171 existingTools[tools.Version] = tools 172 } 173 var agentTools coretools.List = make(coretools.List, len(versions)) 174 for i, version := range versions { 175 if tools, ok := existingTools[version]; ok { 176 agentTools[i] = tools 177 } else { 178 t, err := uploadFakeToolsVersion(stor, toolsDir, version) 179 if err != nil { 180 return nil, err 181 } 182 agentTools[i] = t 183 } 184 } 185 if err := envtools.MergeAndWriteMetadata(stor, toolsDir, stream, agentTools, envtools.DoNotWriteMirrors); err != nil { 186 return nil, err 187 } 188 return agentTools, nil 189 } 190 191 // AssertUploadFakeToolsVersions puts fake tools in the supplied storage for the supplied versions. 192 func AssertUploadFakeToolsVersions(c *gc.C, stor storage.Storage, toolsDir, stream string, versions ...version.Binary) []*coretools.Tools { 193 agentTools, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...) 194 c.Assert(err, jc.ErrorIsNil) 195 err = envtools.MergeAndWriteMetadata(stor, toolsDir, stream, agentTools, envtools.DoNotWriteMirrors) 196 c.Assert(err, jc.ErrorIsNil) 197 return agentTools 198 } 199 200 // MustUploadFakeToolsVersions acts as UploadFakeToolsVersions, but panics on failure. 201 func MustUploadFakeToolsVersions(stor storage.Storage, stream string, versions ...version.Binary) []*coretools.Tools { 202 var agentTools coretools.List = make(coretools.List, len(versions)) 203 for i, version := range versions { 204 t, err := uploadFakeToolsVersion(stor, stream, version) 205 if err != nil { 206 panic(err) 207 } 208 agentTools[i] = t 209 } 210 err := envtools.MergeAndWriteMetadata(stor, stream, stream, agentTools, envtools.DoNotWriteMirrors) 211 if err != nil { 212 panic(err) 213 } 214 return agentTools 215 } 216 217 func uploadFakeTools(stor storage.Storage, toolsDir, stream string) error { 218 toolsSeries := set.NewStrings(toolsLtsSeries...) 219 toolsSeries.Add(version.Current.Series) 220 var versions []version.Binary 221 for _, series := range toolsSeries.Values() { 222 vers := version.Current 223 vers.Series = series 224 versions = append(versions, vers) 225 } 226 if _, err := UploadFakeToolsVersions(stor, toolsDir, stream, versions...); err != nil { 227 return err 228 } 229 return nil 230 } 231 232 // UploadFakeTools puts fake tools into the supplied storage with a binary 233 // version matching version.Current; if version.Current's series is different 234 // to coretesting.FakeDefaultSeries, matching fake tools will be uploaded for that 235 // series. This is useful for tests that are kinda casual about specifying 236 // their environment. 237 func UploadFakeTools(c *gc.C, stor storage.Storage, toolsDir, stream string) { 238 c.Assert(uploadFakeTools(stor, toolsDir, stream), gc.IsNil) 239 } 240 241 // MustUploadFakeTools acts as UploadFakeTools, but panics on failure. 242 func MustUploadFakeTools(stor storage.Storage, toolsDir, stream string) { 243 if err := uploadFakeTools(stor, toolsDir, stream); err != nil { 244 panic(err) 245 } 246 } 247 248 // RemoveFakeTools deletes the fake tools from the supplied storage. 249 func RemoveFakeTools(c *gc.C, stor storage.Storage, toolsDir string) { 250 c.Logf("removing fake tools") 251 toolsVersion := version.Current 252 name := envtools.StorageName(toolsVersion, toolsDir) 253 err := stor.Remove(name) 254 c.Check(err, jc.ErrorIsNil) 255 defaultSeries := coretesting.FakeDefaultSeries 256 if version.Current.Series != defaultSeries { 257 toolsVersion.Series = defaultSeries 258 name := envtools.StorageName(toolsVersion, toolsDir) 259 err := stor.Remove(name) 260 c.Check(err, jc.ErrorIsNil) 261 } 262 RemoveFakeToolsMetadata(c, stor) 263 } 264 265 // RemoveTools deletes all tools from the supplied storage. 266 func RemoveTools(c *gc.C, stor storage.Storage, toolsDir string) { 267 names, err := storage.List(stor, fmt.Sprintf("tools/%s/juju-", toolsDir)) 268 c.Assert(err, jc.ErrorIsNil) 269 c.Logf("removing files: %v", names) 270 for _, name := range names { 271 err = stor.Remove(name) 272 c.Check(err, jc.ErrorIsNil) 273 } 274 RemoveFakeToolsMetadata(c, stor) 275 } 276 277 var ( 278 V100 = version.MustParse("1.0.0") 279 V100p64 = version.MustParseBinary("1.0.0-precise-amd64") 280 V100p32 = version.MustParseBinary("1.0.0-precise-i386") 281 V100p = []version.Binary{V100p64, V100p32} 282 283 V100q64 = version.MustParseBinary("1.0.0-quantal-amd64") 284 V100q32 = version.MustParseBinary("1.0.0-quantal-i386") 285 V100q = []version.Binary{V100q64, V100q32} 286 V100all = append(V100p, V100q...) 287 288 V1001 = version.MustParse("1.0.0.1") 289 V1001p64 = version.MustParseBinary("1.0.0.1-precise-amd64") 290 V100Xall = append(V100all, V1001p64) 291 292 V110 = version.MustParse("1.1.0") 293 V110p64 = version.MustParseBinary("1.1.0-precise-amd64") 294 V110p32 = version.MustParseBinary("1.1.0-precise-i386") 295 V110p = []version.Binary{V110p64, V110p32} 296 297 V110q64 = version.MustParseBinary("1.1.0-quantal-amd64") 298 V110q32 = version.MustParseBinary("1.1.0-quantal-i386") 299 V110q = []version.Binary{V110q64, V110q32} 300 V110all = append(V110p, V110q...) 301 302 V1101p64 = version.MustParseBinary("1.1.0.1-precise-amd64") 303 V110Xall = append(V110all, V1101p64) 304 305 V120 = version.MustParse("1.2.0") 306 V120p64 = version.MustParseBinary("1.2.0-precise-amd64") 307 V120p32 = version.MustParseBinary("1.2.0-precise-i386") 308 V120p = []version.Binary{V120p64, V120p32} 309 310 V120q64 = version.MustParseBinary("1.2.0-quantal-amd64") 311 V120q32 = version.MustParseBinary("1.2.0-quantal-i386") 312 V120q = []version.Binary{V120q64, V120q32} 313 314 V120t64 = version.MustParseBinary("1.2.0-trusty-amd64") 315 V120t32 = version.MustParseBinary("1.2.0-trusty-i386") 316 V120t = []version.Binary{V120t64, V120t32} 317 318 V120all = append(append(V120p, V120q...), V120t...) 319 V1all = append(V100Xall, append(V110all, V120all...)...) 320 321 V220 = version.MustParse("2.2.0") 322 V220p32 = version.MustParseBinary("2.2.0-precise-i386") 323 V220p64 = version.MustParseBinary("2.2.0-precise-amd64") 324 V220q32 = version.MustParseBinary("2.2.0-quantal-i386") 325 V220q64 = version.MustParseBinary("2.2.0-quantal-amd64") 326 V220all = []version.Binary{V220p64, V220p32, V220q64, V220q32} 327 VAll = append(V1all, V220all...) 328 329 V31d0qppc64 = version.MustParseBinary("3.1-dev0-quantal-ppc64el") 330 V31d01qppc64 = version.MustParseBinary("3.1-dev0.1-quantal-ppc64el") 331 ) 332 333 type BootstrapToolsTest struct { 334 Info string 335 Available []version.Binary 336 CliVersion version.Binary 337 DefaultSeries string 338 AgentVersion version.Number 339 Development bool 340 Arch string 341 Expect []version.Binary 342 Err string 343 } 344 345 var noToolsMessage = "Juju cannot bootstrap because no tools are available for your environment.*" 346 347 var BootstrapToolsTests = []BootstrapToolsTest{ 348 { 349 Info: "no tools at all", 350 CliVersion: V100p64, 351 DefaultSeries: "precise", 352 Err: noToolsMessage, 353 }, { 354 Info: "released cli: use newest compatible release version", 355 Available: VAll, 356 CliVersion: V100p64, 357 DefaultSeries: "precise", 358 Expect: V100p, 359 }, { 360 Info: "released cli: cli Arch ignored", 361 Available: VAll, 362 CliVersion: V100p32, 363 DefaultSeries: "precise", 364 Expect: V100p, 365 }, { 366 Info: "released cli: cli series ignored", 367 Available: VAll, 368 CliVersion: V100q64, 369 DefaultSeries: "precise", 370 Expect: V100p, 371 }, { 372 Info: "released cli: series taken from default-series", 373 Available: V120all, 374 CliVersion: V120p64, 375 DefaultSeries: "quantal", 376 Expect: V120q, 377 }, { 378 Info: "released cli: ignore close dev match", 379 Available: V100Xall, 380 CliVersion: V100p64, 381 DefaultSeries: "precise", 382 Expect: V100p, 383 }, { 384 Info: "released cli: filter by arch constraints", 385 Available: V120all, 386 CliVersion: V120p64, 387 DefaultSeries: "precise", 388 Arch: "i386", 389 Expect: []version.Binary{V120p32}, 390 }, { 391 Info: "released cli: specific released version", 392 Available: VAll, 393 CliVersion: V100p64, 394 AgentVersion: V100, 395 DefaultSeries: "precise", 396 Expect: V100p, 397 }, { 398 Info: "released cli: specific dev version", 399 Available: VAll, 400 CliVersion: V110p64, 401 AgentVersion: V110, 402 DefaultSeries: "precise", 403 Expect: V110p, 404 }, { 405 Info: "released cli: major upgrades bad", 406 Available: V220all, 407 CliVersion: V100p64, 408 DefaultSeries: "precise", 409 Err: noToolsMessage, 410 }, { 411 Info: "released cli: minor upgrades bad", 412 Available: V120all, 413 CliVersion: V100p64, 414 DefaultSeries: "precise", 415 Err: noToolsMessage, 416 }, { 417 Info: "released cli: major downgrades bad", 418 Available: V100Xall, 419 CliVersion: V220p64, 420 DefaultSeries: "precise", 421 Err: noToolsMessage, 422 }, { 423 Info: "released cli: minor downgrades bad", 424 Available: V100Xall, 425 CliVersion: V120p64, 426 DefaultSeries: "quantal", 427 Err: noToolsMessage, 428 }, { 429 Info: "released cli: no matching series", 430 Available: VAll, 431 CliVersion: V100p64, 432 DefaultSeries: "raring", 433 Err: noToolsMessage, 434 }, { 435 Info: "released cli: no matching arches", 436 Available: VAll, 437 CliVersion: V100p64, 438 DefaultSeries: "precise", 439 Arch: "armhf", 440 Err: noToolsMessage, 441 }, { 442 Info: "released cli: specific bad major 1", 443 Available: VAll, 444 CliVersion: V220p64, 445 AgentVersion: V120, 446 DefaultSeries: "precise", 447 Err: noToolsMessage, 448 }, { 449 Info: "released cli: specific bad major 2", 450 Available: VAll, 451 CliVersion: V120p64, 452 AgentVersion: V220, 453 DefaultSeries: "precise", 454 Err: noToolsMessage, 455 }, { 456 Info: "released cli: ignore dev tools 1", 457 Available: V110all, 458 CliVersion: V100p64, 459 DefaultSeries: "precise", 460 Err: noToolsMessage, 461 }, { 462 Info: "released cli: ignore dev tools 2", 463 Available: V110all, 464 CliVersion: V120p64, 465 DefaultSeries: "precise", 466 Err: noToolsMessage, 467 }, { 468 Info: "released cli: ignore dev tools 3", 469 Available: []version.Binary{V1001p64}, 470 CliVersion: V100p64, 471 DefaultSeries: "precise", 472 Err: noToolsMessage, 473 }, { 474 Info: "released cli with dev setting respects agent-version", 475 Available: VAll, 476 CliVersion: V100q32, 477 AgentVersion: V1001, 478 DefaultSeries: "precise", 479 Development: true, 480 Expect: []version.Binary{V1001p64}, 481 }, { 482 Info: "dev cli respects agent-version", 483 Available: VAll, 484 CliVersion: V100q32, 485 AgentVersion: V1001, 486 DefaultSeries: "precise", 487 Expect: []version.Binary{V1001p64}, 488 }, { 489 Info: "released cli with dev setting respects agent-version", 490 Available: V1all, 491 CliVersion: V100q32, 492 AgentVersion: V1001, 493 DefaultSeries: "precise", 494 Development: true, 495 Expect: []version.Binary{V1001p64}, 496 }, { 497 Info: "dev cli respects agent-version", 498 Available: V1all, 499 CliVersion: V100q32, 500 AgentVersion: V1001, 501 DefaultSeries: "precise", 502 Expect: []version.Binary{V1001p64}, 503 }} 504 505 func SetSSLHostnameVerification(c *gc.C, st *state.State, SSLHostnameVerification bool) { 506 err := st.UpdateEnvironConfig(map[string]interface{}{"ssl-hostname-verification": SSLHostnameVerification}, nil, nil) 507 c.Assert(err, jc.ErrorIsNil) 508 }