github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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.State 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 err := s.machine.SetAgentVersion(version.Current) 93 c.Assert(err, jc.ErrorIsNil) 94 return upgrader.NewAgentUpgrader( 95 s.state.Upgrader(), 96 agentConfig(s.machine.Tag(), s.DataDir()), 97 s.confVersion, 98 func() bool { return s.upgradeRunning }, 99 s.agentUpgradeComplete, 100 ) 101 } 102 103 func (s *UpgraderSuite) TestUpgraderSetsTools(c *gc.C) { 104 vers := version.MustParseBinary("5.4.3-precise-amd64") 105 err := statetesting.SetAgentVersion(s.State, vers.Number) 106 c.Assert(err, jc.ErrorIsNil) 107 stor := s.DefaultToolsStorage 108 agentTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), vers) 109 s.PatchValue(&version.Current, agentTools.Version) 110 err = envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{agentTools}, envtools.DoNotWriteMirrors) 111 _, err = s.machine.AgentTools() 112 c.Assert(err, jc.Satisfies, errors.IsNotFound) 113 114 u := s.makeUpgrader(c) 115 statetesting.AssertStop(c, u) 116 s.expectUpgradeChannelClosed(c) 117 s.machine.Refresh() 118 gotTools, err := s.machine.AgentTools() 119 c.Assert(err, jc.ErrorIsNil) 120 envtesting.CheckTools(c, gotTools, agentTools) 121 } 122 123 func (s *UpgraderSuite) TestUpgraderSetVersion(c *gc.C) { 124 vers := version.MustParseBinary("5.4.3-precise-amd64") 125 agentTools := envtesting.PrimeTools(c, s.DefaultToolsStorage, s.DataDir(), s.Environ.Config().AgentStream(), vers) 126 s.PatchValue(&version.Current, agentTools.Version) 127 err := os.RemoveAll(filepath.Join(s.DataDir(), "tools")) 128 c.Assert(err, jc.ErrorIsNil) 129 130 _, err = s.machine.AgentTools() 131 c.Assert(err, jc.Satisfies, errors.IsNotFound) 132 err = statetesting.SetAgentVersion(s.State, vers.Number) 133 c.Assert(err, jc.ErrorIsNil) 134 135 u := s.makeUpgrader(c) 136 statetesting.AssertStop(c, u) 137 s.expectUpgradeChannelClosed(c) 138 s.machine.Refresh() 139 gotTools, err := s.machine.AgentTools() 140 c.Assert(err, jc.ErrorIsNil) 141 c.Assert(gotTools, gc.DeepEquals, &coretools.Tools{Version: version.Current}) 142 } 143 144 func (s *UpgraderSuite) expectUpgradeChannelClosed(c *gc.C) { 145 select { 146 case <-s.agentUpgradeComplete: 147 default: 148 c.Fail() 149 } 150 } 151 152 func (s *UpgraderSuite) expectUpgradeChannelNotClosed(c *gc.C) { 153 select { 154 case <-s.agentUpgradeComplete: 155 c.Fail() 156 default: 157 } 158 } 159 160 func (s *UpgraderSuite) TestUpgraderUpgradesImmediately(c *gc.C) { 161 stor := s.DefaultToolsStorage 162 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 163 s.PatchValue(&version.Current, oldTools.Version) 164 newTools := envtesting.AssertUploadFakeToolsVersions( 165 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] 166 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 167 c.Assert(err, jc.ErrorIsNil) 168 169 // Make the download take a while so that we verify that 170 // the download happens before the upgrader checks if 171 // it's been stopped. 172 dummy.SetStorageDelay(coretesting.ShortWait) 173 174 u := s.makeUpgrader(c) 175 err = u.Stop() 176 s.expectUpgradeChannelNotClosed(c) 177 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 178 AgentName: s.machine.Tag().String(), 179 OldTools: oldTools.Version, 180 NewTools: newTools.Version, 181 DataDir: s.DataDir(), 182 }) 183 foundTools, err := agenttools.ReadTools(s.DataDir(), newTools.Version) 184 c.Assert(err, jc.ErrorIsNil) 185 newTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.5-precise-amd64", 186 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 187 envtesting.CheckTools(c, foundTools, newTools) 188 } 189 190 func (s *UpgraderSuite) TestUpgraderRetryAndChanged(c *gc.C) { 191 stor := s.DefaultToolsStorage 192 oldTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 193 s.PatchValue(&version.Current, oldTools.Version) 194 newTools := envtesting.AssertUploadFakeToolsVersions( 195 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.5-precise-amd64"))[0] 196 err := statetesting.SetAgentVersion(s.State, newTools.Version.Number) 197 c.Assert(err, jc.ErrorIsNil) 198 199 retryc := make(chan time.Time) 200 *upgrader.RetryAfter = func() <-chan time.Time { 201 c.Logf("replacement retry after") 202 return retryc 203 } 204 err = stor.Remove(envtools.StorageName(newTools.Version, "released")) 205 c.Assert(err, jc.ErrorIsNil) 206 u := s.makeUpgrader(c) 207 defer u.Stop() 208 s.expectUpgradeChannelNotClosed(c) 209 210 for i := 0; i < 3; i++ { 211 select { 212 case retryc <- time.Now(): 213 case <-time.After(coretesting.LongWait): 214 c.Fatalf("upgrader did not retry (attempt %d)", i) 215 } 216 } 217 218 // Make it upgrade to some newer tools that can be 219 // downloaded ok; it should stop retrying, download 220 // the newer tools and exit. 221 newerTools := envtesting.AssertUploadFakeToolsVersions( 222 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.6-precise-amd64"))[0] 223 224 err = statetesting.SetAgentVersion(s.State, newerTools.Version.Number) 225 c.Assert(err, jc.ErrorIsNil) 226 227 s.BackingState.StartSync() 228 done := make(chan error) 229 go func() { 230 done <- u.Wait() 231 }() 232 select { 233 case err := <-done: 234 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 235 AgentName: s.machine.Tag().String(), 236 OldTools: oldTools.Version, 237 NewTools: newerTools.Version, 238 DataDir: s.DataDir(), 239 }) 240 case <-time.After(coretesting.LongWait): 241 c.Fatalf("upgrader did not quit after upgrading") 242 } 243 } 244 245 func (s *UpgraderSuite) TestChangeAgentTools(c *gc.C) { 246 oldTools := &coretools.Tools{ 247 Version: version.MustParseBinary("1.2.3-quantal-amd64"), 248 } 249 stor := s.DefaultToolsStorage 250 newToolsBinary := "5.4.3-precise-amd64" 251 newTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary(newToolsBinary)) 252 s.PatchValue(&version.Current, newTools.Version) 253 err := envtools.MergeAndWriteMetadata(stor, "released", "released", coretools.List{newTools}, envtools.DoNotWriteMirrors) 254 c.Assert(err, jc.ErrorIsNil) 255 ugErr := &upgrader.UpgradeReadyError{ 256 AgentName: "anAgent", 257 OldTools: oldTools.Version, 258 NewTools: newTools.Version, 259 DataDir: s.DataDir(), 260 } 261 err = ugErr.ChangeAgentTools() 262 c.Assert(err, jc.ErrorIsNil) 263 target := agenttools.ToolsDir(s.DataDir(), newToolsBinary) 264 link, err := symlink.Read(agenttools.ToolsDir(s.DataDir(), "anAgent")) 265 c.Assert(err, jc.ErrorIsNil) 266 c.Assert(link, jc.SamePath, target) 267 } 268 269 func (s *UpgraderSuite) TestUsesAlreadyDownloadedToolsIfAvailable(c *gc.C) { 270 oldVersion := version.MustParseBinary("1.2.3-quantal-amd64") 271 s.PatchValue(&version.Current, oldVersion) 272 273 newVersion := version.MustParseBinary("5.4.3-quantal-amd64") 274 err := statetesting.SetAgentVersion(s.State, newVersion.Number) 275 c.Assert(err, jc.ErrorIsNil) 276 277 // Install tools matching the new version in the data directory 278 // but *not* in environment storage. The upgrader should find the 279 // downloaded tools without looking in environment storage. 280 envtesting.InstallFakeDownloadedTools(c, s.DataDir(), newVersion) 281 282 u := s.makeUpgrader(c) 283 err = u.Stop() 284 s.expectUpgradeChannelNotClosed(c) 285 286 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 287 AgentName: s.machine.Tag().String(), 288 OldTools: oldVersion, 289 NewTools: newVersion, 290 DataDir: s.DataDir(), 291 }) 292 } 293 294 func (s *UpgraderSuite) TestUpgraderRefusesToDowngradeMinorVersions(c *gc.C) { 295 stor := s.DefaultToolsStorage 296 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 297 s.PatchValue(&version.Current, origTools.Version) 298 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 299 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.3.3-precise-amd64"))[0] 300 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 301 c.Assert(err, jc.ErrorIsNil) 302 303 u := s.makeUpgrader(c) 304 err = u.Stop() 305 s.expectUpgradeChannelClosed(c) 306 // If the upgrade would have triggered, we would have gotten an 307 // UpgradeReadyError, since it was skipped, we get no error 308 c.Check(err, jc.ErrorIsNil) 309 _, err = agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 310 // TODO: ReadTools *should* be returning some form of errors.NotFound, 311 // however, it just passes back a fmt.Errorf so we live with it 312 // c.Assert(err, jc.Satisfies, errors.IsNotFound) 313 c.Check(err, gc.ErrorMatches, "cannot read tools metadata in tools directory.*"+utils.NoSuchFileErrRegexp) 314 } 315 316 func (s *UpgraderSuite) TestUpgraderAllowsDowngradingPatchVersions(c *gc.C) { 317 stor := s.DefaultToolsStorage 318 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 319 s.PatchValue(&version.Current, origTools.Version) 320 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 321 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.2-precise-amd64"))[0] 322 err := statetesting.SetAgentVersion(s.State, downgradeTools.Version.Number) 323 c.Assert(err, jc.ErrorIsNil) 324 325 dummy.SetStorageDelay(coretesting.ShortWait) 326 327 u := s.makeUpgrader(c) 328 err = u.Stop() 329 s.expectUpgradeChannelNotClosed(c) 330 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 331 AgentName: s.machine.Tag().String(), 332 OldTools: origTools.Version, 333 NewTools: downgradeTools.Version, 334 DataDir: s.DataDir(), 335 }) 336 foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 337 c.Assert(err, jc.ErrorIsNil) 338 downgradeTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.4.2-precise-amd64", 339 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 340 envtesting.CheckTools(c, foundTools, downgradeTools) 341 } 342 343 func (s *UpgraderSuite) TestUpgraderAllowsDowngradeToOrigVersionIfUpgradeInProgress(c *gc.C) { 344 // note: otherwise illegal version jump 345 downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64") 346 s.confVersion = downgradeVersion.Number 347 s.upgradeRunning = true 348 349 stor := s.DefaultToolsStorage 350 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 351 s.PatchValue(&version.Current, origTools.Version) 352 downgradeTools := envtesting.AssertUploadFakeToolsVersions( 353 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion)[0] 354 err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number) 355 c.Assert(err, jc.ErrorIsNil) 356 357 dummy.SetStorageDelay(coretesting.ShortWait) 358 359 u := s.makeUpgrader(c) 360 err = u.Stop() 361 s.expectUpgradeChannelNotClosed(c) 362 envtesting.CheckUpgraderReadyError(c, err, &upgrader.UpgradeReadyError{ 363 AgentName: s.machine.Tag().String(), 364 OldTools: origTools.Version, 365 NewTools: downgradeVersion, 366 DataDir: s.DataDir(), 367 }) 368 foundTools, err := agenttools.ReadTools(s.DataDir(), downgradeTools.Version) 369 c.Assert(err, jc.ErrorIsNil) 370 downgradeTools.URL = fmt.Sprintf("https://%s/environment/%s/tools/5.3.0-precise-amd64", 371 s.APIState.Addr(), coretesting.EnvironmentTag.Id()) 372 envtesting.CheckTools(c, foundTools, downgradeTools) 373 } 374 375 func (s *UpgraderSuite) TestUpgraderRefusesDowngradeToOrigVersionIfUpgradeNotInProgress(c *gc.C) { 376 downgradeVersion := version.MustParseBinary("5.3.0-precise-amd64") 377 s.confVersion = downgradeVersion.Number 378 s.upgradeRunning = false 379 380 stor := s.DefaultToolsStorage 381 origTools := envtesting.PrimeTools(c, stor, s.DataDir(), s.Environ.Config().AgentStream(), version.MustParseBinary("5.4.3-precise-amd64")) 382 s.PatchValue(&version.Current, origTools.Version) 383 envtesting.AssertUploadFakeToolsVersions( 384 c, stor, s.Environ.Config().AgentStream(), s.Environ.Config().AgentStream(), downgradeVersion) 385 err := statetesting.SetAgentVersion(s.State, downgradeVersion.Number) 386 c.Assert(err, jc.ErrorIsNil) 387 388 dummy.SetStorageDelay(coretesting.ShortWait) 389 390 u := s.makeUpgrader(c) 391 err = u.Stop() 392 s.expectUpgradeChannelClosed(c) 393 394 // If the upgrade would have triggered, we would have gotten an 395 // UpgradeReadyError, since it was skipped, we get no error 396 c.Check(err, jc.ErrorIsNil) 397 } 398 399 type allowedTest struct { 400 original string 401 current string 402 target string 403 upgradeRunning bool 404 allowed bool 405 } 406 407 func (s *AllowedTargetVersionSuite) TestAllowedTargetVersionSuite(c *gc.C) { 408 cases := []allowedTest{ 409 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.3.3", allowed: true}, 410 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.3", allowed: true}, 411 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "2.2.3", allowed: true}, 412 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.1.3", allowed: false}, 413 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "1.2.2", allowed: true}, // downgrade between builds 414 {original: "1.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false}, 415 {original: "0.2.3", current: "1.2.3", upgradeRunning: false, target: "0.2.3", allowed: false}, 416 {original: "0.2.3", current: "1.2.3", upgradeRunning: true, target: "0.2.3", allowed: true}, // downgrade during upgrade 417 } 418 for i, test := range cases { 419 c.Logf("test case %d, %#v", i, test) 420 original := version.MustParse(test.original) 421 current := version.MustParse(test.current) 422 target := version.MustParse(test.target) 423 result := upgrader.AllowedTargetVersion(original, current, test.upgradeRunning, target) 424 c.Check(result, gc.Equals, test.allowed) 425 } 426 }