github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/upgrader/upgrader_test.go (about) 1 // Copyright 2012, 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package upgrader_test 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 stdtesting "testing" 11 "time" 12 13 "github.com/juju/errors" 14 "github.com/juju/names" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/utils" 17 "github.com/juju/utils/symlink" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/agent" 21 agenttools "github.com/juju/juju/agent/tools" 22 "github.com/juju/juju/api" 23 envtesting "github.com/juju/juju/environs/testing" 24 envtools "github.com/juju/juju/environs/tools" 25 jujutesting "github.com/juju/juju/juju/testing" 26 "github.com/juju/juju/provider/dummy" 27 "github.com/juju/juju/state" 28 statetesting "github.com/juju/juju/state/testing" 29 coretesting "github.com/juju/juju/testing" 30 coretools "github.com/juju/juju/tools" 31 "github.com/juju/juju/version" 32 "github.com/juju/juju/worker/upgrader" 33 ) 34 35 func TestPackage(t *stdtesting.T) { 36 coretesting.MgoTestPackage(t) 37 } 38 39 type UpgraderSuite struct { 40 jujutesting.JujuConnSuite 41 42 machine *state.Machine 43 state api.Connection 44 oldRetryAfter func() <-chan time.Time 45 confVersion version.Number 46 upgradeRunning bool 47 agentUpgradeComplete chan struct{} 48 } 49 50 type AllowedTargetVersionSuite struct{} 51 52 var _ = gc.Suite(&UpgraderSuite{}) 53 var _ = gc.Suite(&AllowedTargetVersionSuite{}) 54 55 func (s *UpgraderSuite) SetUpTest(c *gc.C) { 56 s.JujuConnSuite.SetUpTest(c) 57 // s.machine needs to have IsManager() so that it can get the actual 58 // current revision to upgrade to. 59 s.state, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageEnviron) 60 // Capture the value of RetryAfter, and use that captured 61 // value in the cleanup lambda. 62 oldRetryAfter := *upgrader.RetryAfter 63 s.AddCleanup(func(*gc.C) { 64 *upgrader.RetryAfter = oldRetryAfter 65 }) 66 s.agentUpgradeComplete = make(chan struct{}) 67 } 68 69 type mockConfig struct { 70 agent.Config 71 tag names.Tag 72 datadir string 73 version version.Number 74 } 75 76 func (mock *mockConfig) Tag() names.Tag { 77 return mock.tag 78 } 79 80 func (mock *mockConfig) DataDir() string { 81 return mock.datadir 82 } 83 84 func agentConfig(tag names.Tag, datadir string) agent.Config { 85 return &mockConfig{ 86 tag: tag, 87 datadir: datadir, 88 } 89 } 90 91 func (s *UpgraderSuite) makeUpgrader(c *gc.C) *upgrader.Upgrader { 92 return upgrader.NewAgentUpgrader( 93 s.state.Upgrader(), 94 agentConfig(s.machine.Tag(), s.DataDir()), 95 s.confVersion, 96 func() bool { return s.upgradeRunning }, 97 s.agentUpgradeComplete, 98 ) 99 } 100 101 func (s *UpgraderSuite) TestUpgraderSetsTools(c *gc.C) { 102 vers := version.MustParseBinary("5.4.3-precise-amd64") 103 err := statetesting.SetAgentVersion(s.State, vers.Number) 104 c.Assert(err, jc.ErrorIsNil) 105 stor := s.DefaultToolsStorage 106 agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), vers) 107 s.PatchValue(&version.Current, agentTools.Version) 108 err = envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{agentTools}, envtools.DoNotWriteMirrors) 109 _, err = s.machine.AgentTools() 110 c.Assert(err, jc.Satisfies, errors.IsNotFound) 111 112 u := s.makeUpgrader(c) 113 statetesting.AssertStop(c, u) 114 s.expectUpgradeChannelClosed(c) 115 s.machine.Refresh() 116 gotTools, err := s.machine.AgentTools() 117 c.Assert(err, jc.ErrorIsNil) 118 envtesting.CheckTools(c, gotTools, agentTools) 119 } 120 121 func (s *UpgraderSuite) TestUpgraderSetVersion(c *gc.C) { 122 vers := version.MustParseBinary("5.4.3-precise-amd64") 123 agentTools := envtesting.PrimeTools(c, s.DefaultToolsStorage, s.DataDir(), s.Environ.Config().AgentStream(), vers) 124 s.PatchValue(&version.Current, agentTools.Version) 125 err := os.RemoveAll(filepath.Join(s.DataDir(), "tools")) 126 c.Assert(err, jc.ErrorIsNil) 127 128 _, err = s.machine.AgentTools() 129 c.Assert(err, jc.Satisfies, errors.IsNotFound) 130 err = statetesting.SetAgentVersion(s.State, vers.Number) 131 c.Assert(err, jc.ErrorIsNil) 132 133 u := s.makeUpgrader(c) 134 statetesting.AssertStop(c, u) 135 s.expectUpgradeChannelClosed(c) 136 s.machine.Refresh() 137 gotTools, err := s.machine.AgentTools() 138 c.Assert(err, jc.ErrorIsNil) 139 c.Assert(gotTools, gc.DeepEquals, &coretools.Tools{Version: version.Current}) 140 } 141 142 func (s *UpgraderSuite) expectUpgradeChannelClosed(c *gc.C) { 143 select { 144 case <-s.agentUpgradeComplete: 145 default: 146 c.Fail() 147 } 148 } 149 150 func (s *UpgraderSuite) expectUpgradeChannelNotClosed(c *gc.C) { 151 select { 152 case <-s.agentUpgradeComplete: 153 c.Fail() 154 default: 155 } 156 } 157 158 func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { 159 stor := s.DefaultToolsStorage 160 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 161 s.PatchValue(&version.Current, oldTools.Version) 162 newTools := envtesting.AssertUploadFakeToolsVersions( 163 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] 164 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 165 c.Assert(err, jc.ErrorIsNil) 166 167 // Make the download take a while so that we verify that 168 // the download happens before the upgrader checks if 169 // it's been stopped. 170 dummy.SetStorageDelay(coretesting.ShortWait) 171 172 u := s.makeUpgrader(c) 173 err = u.Stop() 174 s.expectUpgradeChannelNotClosed(c) 175 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 176 AgentName: s.machine.Tag().String(), 177 OldTools: oldTools.Version, 178 NewTools: newTools.Version, 179 DataDir: s.DataDir(), 180 }) 181 foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) 182 c.Assert(err, jc.ErrorIsNil) 183 newTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.5-precise-amd64", 184 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 185 envtesting.CheckTools(c, foundTools, newTools) 186 } 187 188 func (s *UpgraderSuite) TestUpgraderRetryAndChanged(c *gc.C) { 189 stor := s.DefaultToolsStorage 190 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 191 s.PatchValue(&version.Current, oldTools.Version) 192 newTools := envtesting.AssertUploadFakeToolsVersions( 193 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] 194 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 195 c.Assert(err, jc.ErrorIsNil) 196 197 retryc := make(chan time.Time) 198 *upgrader.RetryAfter = func() <-chan time.Time { 199 c.Logf("replacement retry after") 200 return retryc 201 } 202 err = stor.Remove(envtools.StorageName(newTools.Version, "released")) 203 c.Assert(err, jc.ErrorIsNil) 204 u := s.makeUpgrader(c) 205 defer u.Stop() 206 s.expectUpgradeChannelNotClosed(c) 207 208 for i := 0; i < 3; i++ { 209 select { 210 case retryc <- time.Now(): 211 case <-time.After(coretesting.LongWait): 212 c.Fatalf("upgrader did not retry (attempt %d)", i) 213 } 214 } 215 216 // Make it upgrade to some newer tools that can be 217 // downloaded ok; it should stop retrying, download 218 // the newer tools and exit. 219 newerTools := envtesting.AssertUploadFakeToolsVersions( 220 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.6-precise-amd64"))[0] 221 222 err = statetesting.SetAgentVersion(s.State, newerTools.Version.Number) 223 c.Assert(err, jc.ErrorIsNil) 224 225 s.BackingState.StartSync() 226 done := make(chan error) 227 go func() { 228 done <- u.Wait() 229 }() 230 select { 231 case err := <-done: 232 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 233 AgentName: s.machine.Tag().String(), 234 OldTools: oldTools.Version, 235 NewTools: newerTools.Version, 236 DataDir: s.DataDir(), 237 }) 238 case <-time.After(coretesting.LongWait): 239 c.Fatalf("upgrader did not quit after upgrading") 240 } 241 } 242 243 func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) { 244 oldTools := &coretools.Tools{ 245 Version: version.MustParseBinary("1.2.3-quantal-amd64"), 246 } 247 stor := s.DefaultToolsStorage 248 newToolsBinary := "5.4.3-precise-amd64" 249 newTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary(newToolsBinary)) 250 s.PatchValue(&version.Current, newTools.Version) 251 err := envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{newTools}, envtools.DoNotWriteMirrors) 252 c.Assert(err, jc.ErrorIsNil) 253 ugErr := &upgrader.UpgradeReadyError{ 254 AgentName: "anAgent", 255 OldTools: oldTools.Version, 256 NewTools: newTools.Version, 257 DataDir: s.DataDir(), 258 } 259 err = ugErr.ChangeAgentTools() 260 c.Assert(err, jc.ErrorIsNil) 261 target := agenttools.ToolsDir(s.DataDir(), newToolsBinary) 262 link, err := symlink.Read(agenttools.ToolsDir(s.DataDir(), "anAgent")) 263 c.Assert(err, jc.ErrorIsNil) 264 c.Assert(link, jc.SamePath, target) 265 } 266 267 func (s *UpgraderSuite) TestUsesAlreadyDownloadedToolsIfAvailable(c *gc.C) { 268 oldVersion := version.MustParseBinary("1.2.3-quantal-amd64") 269 s.PatchValue(&version.Current, oldVersion) 270 271 newVersion := version.MustParseBinary("5.4.3-quantal-amd64") 272 err := statetesting.SetAgentVersion(s.State, newVersion.Number) 273 c.Assert(err, jc.ErrorIsNil) 274 275 // Install tools matching the new version in the data directory 276 // but *not* in environment storage. The upgrader should find the 277 // downloaded tools without looking in environment storage. 278 envtesting.InstallFakeDownloadedTools(c, s.DataDir(), newVersion) 279 280 u := s.makeUpgrader(c) 281 err = u.Stop() 282 s.expectUpgradeChannelNotClosed(c) 283 284 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 285 AgentName: s.machine.Tag().String(), 286 OldTools: oldVersion, 287 NewTools: newVersion, 288 DataDir: s.DataDir(), 289 }) 290 } 291 292 func (s *UpgraderSuite) TestUpgraderRefusesToDowngradeMinorVersions(c *gc.C) { 293 stor := s.DefaultToolsStorage 294 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 295 s.PatchValue(&version.Current, origTools.Version) 296 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 297 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.3.3-precise-amd64"))[0] 298 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 299 c.Assert(err, jc.ErrorIsNil) 300 301 u := s.makeUpgrader(c) 302 err = u.Stop() 303 s.expectUpgradeChannelClosed(c) 304 // If the upgrade would have triggered, we would have gotten an 305 // UpgradeReadyError, since it was skipped, we get no error 306 c.Check(err, jc.ErrorIsNil) 307 _, err = agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 308 // TODO: ReadTools *should* be returning some form of errors.NotFound, 309 // however, it just passes back a fmt.Errorf so we live with it 310 // c.Assert(err, jc.Satisfies, errors.IsNotFound) 311 c.Check(err, gc.ErrorMatches, "cannot read tools metadata in tools directory.*"+utils.NoSuchFileErrRegexp) 312 } 313 314 func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) { 315 stor := s.DefaultToolsStorage 316 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 317 s.PatchValue(&version.Current, origTools.Version) 318 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 319 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.2-precise-amd64"))[0] 320 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 321 c.Assert(err, jc.ErrorIsNil) 322 323 dummy.SetStorageDelay(coretesting.ShortWait) 324 325 u := s.makeUpgrader(c) 326 err = u.Stop() 327 s.expectUpgradeChannelNotClosed(c) 328 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 329 AgentName: s.machine.Tag().String(), 330 OldTools: origTools.Version, 331 NewTools: downgradeTools.Version, 332 DataDir: s.DataDir(), 333 }) 334 foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 335 c.Assert(err, jc.ErrorIsNil) 336 downgradeTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.2-precise-amd64", 337 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 338 envtesting.CheckTools(c, foundTools, downgradeTools) 339 } 340 341 func (s *UpgraderSuite) TestUpgraderAllowsDowngradeToOrigVersionIfUpgradeInProgress(c *gc.C) { 342 // note: otherwise illegal version jump 343 downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64") 344 s.confVersion = downgradeVersion.Number 345 s.upgradeRunning = true 346 347 stor := s.DefaultToolsStorage 348 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 349 s.PatchValue(&version.Current, origTools.Version) 350 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 351 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion)[0] 352 err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number) 353 c.Assert(err, jc.ErrorIsNil) 354 355 dummy.SetStorageDelay(coretesting.ShortWait) 356 357 u := s.makeUpgrader(c) 358 err = u.Stop() 359 s.expectUpgradeChannelNotClosed(c) 360 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 361 AgentName: s.machine.Tag().String(), 362 OldTools: origTools.Version, 363 NewTools: downgradeVersion, 364 DataDir: s.DataDir(), 365 }) 366 foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 367 c.Assert(err, jc.ErrorIsNil) 368 downgradeTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.3.0-precise-amd64", 369 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 370 envtesting.CheckTools(c, foundTools, downgradeTools) 371 } 372 373 func (s *UpgraderSuite) TestUpgraderRefusesDowngradeToOrigVersionIfUpgradeNotInProgress(c *gc.C) { 374 downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64") 375 s.confVersion = downgradeVersion.Number 376 s.upgradeRunning = false 377 378 stor := s.DefaultToolsStorage 379 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 380 s.PatchValue(&version.Current, origTools.Version) 381 envtesting.AssertUploadFakeToolsVersions( 382 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion) 383 err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number) 384 c.Assert(err, jc.ErrorIsNil) 385 386 dummy.SetStorageDelay(coretesting.ShortWait) 387 388 u := s.makeUpgrader(c) 389 err = u.Stop() 390 s.expectUpgradeChannelClosed(c) 391 392 // If the upgrade would have triggered, we would have gotten an 393 // UpgradeReadyError, since it was skipped, we get no error 394 c.Check(err, jc.ErrorIsNil) 395 } 396 397 type allowedTest struct { 398 original string 399 current string 400 target string 401 upgradeRunning bool 402 allowed bool 403 } 404 405 func (s *AllowedTargetVersionSuite) TestAllowedTargetVersionSuite(c *gc.C) { 406 cases := []allowedTest{ 407 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.3.3", allowed: true}, 408 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.3", allowed: true}, 409 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "2.2.3", allowed: true}, 410 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.1.3", allowed: false}, 411 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.2", allowed: true}, // downgrade between builds 412 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false}, 413 {original: "0.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false}, 414 {original: "0.2.3", current: "1.2.3", upgradeRunning: true, target: "0.2.3", allowed: true}, // downgrade during upgrade 415 } 416 for i, test := range cases { 417 c.Logf("test case %d, %#v", i, test) 418 original := version.MustParse(test.original) 419 current := version.MustParse(test.current) 420 target := version.MustParse(test.target) 421 result := upgrader.AllowedTargetVersion(original, current, test.upgradeRunning, target) 422 c.Check(result, gc.Equals, test.allowed) 423 } 424 }