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