OLD | NEW |
(Empty) | |
| 1 // Copyright 2012, 2013 Canonical Ltd. |
| 2 // Licensed under the AGPLv3, see LICENCE file for details. |
| 3 |
| 4 package main |
| 5 |
| 6 import ( |
| 7 "fmt" |
| 8 "time" |
| 9 |
| 10 gc "launchpad.net/gocheck" |
| 11 |
| 12 "launchpad.net/juju-core/agent" |
| 13 "launchpad.net/juju-core/constraints" |
| 14 "launchpad.net/juju-core/container/lxc" |
| 15 "launchpad.net/juju-core/state" |
| 16 "launchpad.net/juju-core/state/api" |
| 17 "launchpad.net/juju-core/testing" |
| 18 ) |
| 19 |
| 20 var _ = gc.Suite(&UpgradeValidationMachineSuite{}) |
| 21 |
| 22 type UpgradeValidationMachineSuite struct { |
| 23 agentSuite |
| 24 lxc.TestSuite |
| 25 } |
| 26 |
| 27 func (s *UpgradeValidationMachineSuite) SetUpSuite(c *gc.C) { |
| 28 s.agentSuite.SetUpSuite(c) |
| 29 s.TestSuite.SetUpSuite(c) |
| 30 } |
| 31 |
| 32 func (s *UpgradeValidationMachineSuite) TearDownSuite(c *gc.C) { |
| 33 s.TestSuite.TearDownSuite(c) |
| 34 s.agentSuite.TearDownSuite(c) |
| 35 } |
| 36 |
| 37 func (s *UpgradeValidationMachineSuite) SetUpTest(c *gc.C) { |
| 38 s.agentSuite.SetUpTest(c) |
| 39 s.TestSuite.SetUpTest(c) |
| 40 } |
| 41 |
| 42 func (s *UpgradeValidationMachineSuite) TearDownTest(c *gc.C) { |
| 43 s.TestSuite.TearDownTest(c) |
| 44 s.agentSuite.TearDownTest(c) |
| 45 } |
| 46 |
| 47 func (s *UpgradeValidationMachineSuite) Create1_10Machine(c *gc.C) (*state.Machi
ne, *agent.Conf) { |
| 48 // Given the current connection to state, create a new machine, and 'res
et' |
| 49 // the configuration so that it looks like how juju 1.10 would have |
| 50 // configured it |
| 51 m, err := s.State.InjectMachine("series", constraints.Value{}, "ardbeg-0
", state.JobHostUnits) |
| 52 c.Assert(err, gc.IsNil) |
| 53 err = m.SetMongoPassword("machine-password") |
| 54 c.Assert(err, gc.IsNil) |
| 55 // We intentionally do *not* call m.SetPassword here, as it was not |
| 56 // done in 1.10, we also intentionally set the APIInfo.Password back to |
| 57 // the empty string. |
| 58 conf, _ := s.agentSuite.primeAgent(c, m.Tag(), "machine-password") |
| 59 conf.MachineNonce = state.BootstrapNonce |
| 60 conf.APIInfo.Password = "" |
| 61 conf.Write() |
| 62 c.Assert(conf.StateInfo.Tag, gc.Equals, m.Tag()) |
| 63 c.Assert(conf.StateInfo.Password, gc.Equals, "machine-password") |
| 64 c.Assert(err, gc.IsNil) |
| 65 return m, conf |
| 66 } |
| 67 |
| 68 func (s *UpgradeValidationMachineSuite) TestEnsureAPIInfo(c *gc.C) { |
| 69 m, conf := s.Create1_10Machine(c) |
| 70 // Opening the API should fail as is |
| 71 apiState, newPassword, err := conf.OpenAPI(api.DialOpts{}) |
| 72 c.Assert(apiState, gc.IsNil) |
| 73 c.Assert(newPassword, gc.Equals, "") |
| 74 c.Assert(err, gc.NotNil) |
| 75 c.Assert(err, gc.ErrorMatches, "invalid entity name or password") |
| 76 |
| 77 err = EnsureAPIInfo(conf, s.State, m) |
| 78 c.Assert(err, gc.IsNil) |
| 79 // After EnsureAPIInfo we should be able to connect |
| 80 apiState, newPassword, err = conf.OpenAPI(api.DialOpts{}) |
| 81 c.Assert(err, gc.IsNil) |
| 82 c.Assert(apiState, gc.NotNil) |
| 83 // We shouldn't need to set a new password |
| 84 c.Assert(newPassword, gc.Equals, "") |
| 85 } |
| 86 |
| 87 func (s *UpgradeValidationMachineSuite) TestEnsureAPIInfoNoOp(c *gc.C) { |
| 88 m, conf := s.Create1_10Machine(c) |
| 89 // Set the API password to something, and record it, ensure that |
| 90 // EnsureAPIInfo doesn't change it on us |
| 91 m.SetPassword("frobnizzle") |
| 92 conf.APIInfo.Password = "frobnizzle" |
| 93 // We matched them, so we should be able to open the API |
| 94 apiState, newPassword, err := conf.OpenAPI(api.DialOpts{}) |
| 95 c.Assert(apiState, gc.NotNil) |
| 96 c.Assert(newPassword, gc.Equals, "") |
| 97 c.Assert(err, gc.IsNil) |
| 98 apiState.Close() |
| 99 |
| 100 err = EnsureAPIInfo(conf, s.State, m) |
| 101 c.Assert(err, gc.IsNil) |
| 102 // After EnsureAPIInfo we should still be able to connect |
| 103 apiState, newPassword, err = conf.OpenAPI(api.DialOpts{}) |
| 104 c.Assert(err, gc.IsNil) |
| 105 c.Assert(apiState, gc.NotNil) |
| 106 // We shouldn't need to set a new password |
| 107 c.Assert(newPassword, gc.Equals, "") |
| 108 // The password hasn't been changed |
| 109 c.Assert(conf.APIInfo.Password, gc.Equals, "frobnizzle") |
| 110 } |
| 111 |
| 112 // Test that MachineAgent enforces the API password on startup |
| 113 func (s *UpgradeValidationMachineSuite) TestAgentEnsuresAPIInfo(c *gc.C) { |
| 114 m, _ := s.Create1_10Machine(c) |
| 115 // This is similar to assertJobWithState, however we need to control |
| 116 // how the machine is initialized, so it looks like a 1.10 upgrade |
| 117 a := &MachineAgent{} |
| 118 s.initAgent(c, a, "--machine-id", m.Id()) |
| 119 |
| 120 agentStates := make(chan *state.State, 1000) |
| 121 undo := sendOpenedStates(agentStates) |
| 122 defer undo() |
| 123 |
| 124 done := make(chan error) |
| 125 go func() { |
| 126 done <- a.Run(nil) |
| 127 }() |
| 128 |
| 129 select { |
| 130 case agentState := <-agentStates: |
| 131 c.Assert(agentState, gc.NotNil) |
| 132 c.Assert(a.Conf.Conf.APIInfo.Password, gc.Equals, "machine-passw
ord") |
| 133 case <-time.After(testing.LongWait): |
| 134 c.Fatalf("state not opened") |
| 135 } |
| 136 err := a.Stop() |
| 137 c.Assert(err, gc.IsNil) |
| 138 c.Assert(<-done, gc.IsNil) |
| 139 } |
| 140 |
| 141 // Test that MachineAgent enforces the API password on startup even for machine>
0 |
| 142 func (s *UpgradeValidationMachineSuite) TestAgentEnsuresAPIInfoOnWorkers(c *gc.C
) { |
| 143 // create a machine-0, then create a new machine-1 |
| 144 _, _ = s.Create1_10Machine(c) |
| 145 m1, _ := s.Create1_10Machine(c) |
| 146 |
| 147 a := &MachineAgent{} |
| 148 s.initAgent(c, a, "--machine-id", m1.Id()) |
| 149 |
| 150 agentStates := make(chan *state.State, 1000) |
| 151 undo := sendOpenedStates(agentStates) |
| 152 defer undo() |
| 153 |
| 154 done := make(chan error) |
| 155 go func() { |
| 156 done <- a.Run(nil) |
| 157 }() |
| 158 |
| 159 select { |
| 160 case agentState := <-agentStates: |
| 161 c.Assert(agentState, gc.NotNil) |
| 162 c.Assert(a.Conf.Conf.APIInfo.Password, gc.Equals, "machine-passw
ord") |
| 163 case <-time.After(testing.LongWait): |
| 164 c.Fatalf("state not opened") |
| 165 } |
| 166 err := a.Stop() |
| 167 c.Assert(err, gc.IsNil) |
| 168 c.Assert(<-done, gc.IsNil) |
| 169 } |
| 170 |
| 171 var _ = gc.Suite(&UpgradeValidationUnitSuite{}) |
| 172 |
| 173 type UpgradeValidationUnitSuite struct { |
| 174 agentSuite |
| 175 testing.GitSuite |
| 176 } |
| 177 |
| 178 func (s *UpgradeValidationUnitSuite) SetUpTest(c *gc.C) { |
| 179 s.agentSuite.SetUpTest(c) |
| 180 s.GitSuite.SetUpTest(c) |
| 181 } |
| 182 |
| 183 func (s *UpgradeValidationUnitSuite) TearDownTest(c *gc.C) { |
| 184 s.GitSuite.SetUpTest(c) |
| 185 s.agentSuite.TearDownTest(c) |
| 186 } |
| 187 |
| 188 func (s *UpgradeValidationUnitSuite) Create1_10Unit(c *gc.C) (*state.Unit, *agen
t.Conf) { |
| 189 svc, err := s.State.AddService("wordpress", s.AddTestingCharm(c, "wordpr
ess")) |
| 190 c.Assert(err, gc.IsNil) |
| 191 unit, err := svc.AddUnit() |
| 192 c.Assert(err, gc.IsNil) |
| 193 err = unit.SetMongoPassword("unit-password") |
| 194 c.Assert(err, gc.IsNil) |
| 195 // We do not call SetPassword for the unit agent, and we force the |
| 196 // APIInfo to be empty |
| 197 conf, _ := s.agentSuite.primeAgent(c, unit.Tag(), "unit-password") |
| 198 conf.APIInfo = nil |
| 199 c.Assert(conf.Write(), gc.IsNil) |
| 200 return unit, conf |
| 201 } |
| 202 |
| 203 func (s *UpgradeValidationUnitSuite) TestEnsureAPIInfo(c *gc.C) { |
| 204 u, conf := s.Create1_10Unit(c) |
| 205 // Opening the API should fail as is |
| 206 c.Assert(func() { conf.OpenAPI(api.DialOpts{}) }, gc.PanicMatches, ".*ni
l pointer dereference") |
| 207 |
| 208 err := EnsureAPIInfo(conf, s.State, u) |
| 209 c.Assert(err, gc.IsNil) |
| 210 // The test suite runs the API on non-standard ports. Fix it |
| 211 apiAddresses, err := s.State.APIAddresses() |
| 212 c.Assert(err, gc.IsNil) |
| 213 c.Assert(conf.APIInfo.Addrs, gc.DeepEquals, apiAddresses) |
| 214 conf.APIInfo.Addrs = s.APIInfo(c).Addrs |
| 215 apiState, newPassword, err := conf.OpenAPI(api.DialOpts{}) |
| 216 c.Assert(err, gc.IsNil) |
| 217 c.Assert(apiState, gc.NotNil) |
| 218 // We shouldn't need to set a new password |
| 219 c.Assert(newPassword, gc.Equals, "") |
| 220 } |
| 221 |
| 222 func (s *UpgradeValidationUnitSuite) TestEnsureAPIInfo1_11(c *gc.C) { |
| 223 // In 1.11 State.Password is actually "", and the valid password is |
| 224 // OldPassword. This is because in 1.11 we only change the password in |
| 225 // OpenAPI which we don't call until we actually have agent workers |
| 226 // But we don't want to set the actual entity password to the empty stri
ng |
| 227 u, conf := s.Create1_10Unit(c) |
| 228 conf.OldPassword = conf.StateInfo.Password |
| 229 conf.StateInfo.Password = "" |
| 230 |
| 231 err := EnsureAPIInfo(conf, s.State, u) |
| 232 c.Assert(err, gc.IsNil) |
| 233 // The test suite runs the API on non-standard ports. Fix it |
| 234 apiAddresses, err := s.State.APIAddresses() |
| 235 c.Assert(err, gc.IsNil) |
| 236 c.Assert(conf.APIInfo.Addrs, gc.DeepEquals, apiAddresses) |
| 237 conf.APIInfo.Addrs = s.APIInfo(c).Addrs |
| 238 apiState, newPassword, err := conf.OpenAPI(api.DialOpts{}) |
| 239 c.Assert(err, gc.IsNil) |
| 240 c.Assert(apiState, gc.NotNil) |
| 241 // It should want to set a new Password |
| 242 c.Assert(newPassword, gc.Not(gc.Equals), "") |
| 243 } |
| 244 |
| 245 func (s *UpgradeValidationUnitSuite) TestEnsureAPIInfo1_11Noop(c *gc.C) { |
| 246 // We should notice if APIInfo is 'valid' in that it matches StateInfo |
| 247 // even though in 1.1 both Password fields are empty. |
| 248 u, conf := s.Create1_10Unit(c) |
| 249 conf.OldPassword = conf.StateInfo.Password |
| 250 conf.StateInfo.Password = "" |
| 251 u.SetPassword(conf.OldPassword) |
| 252 testAPIInfo := s.APIInfo(c) |
| 253 conf.APIInfo = &api.Info{ |
| 254 Addrs: testAPIInfo.Addrs, |
| 255 Tag: u.Tag(), |
| 256 Password: "", |
| 257 CACert: testAPIInfo.CACert, |
| 258 } |
| 259 |
| 260 err := EnsureAPIInfo(conf, s.State, u) |
| 261 c.Assert(err, gc.IsNil) |
| 262 // We should not have changed the API Addrs or Password |
| 263 c.Assert(conf.APIInfo.Password, gc.Equals, "") |
| 264 c.Assert(conf.APIInfo.Addrs, gc.DeepEquals, testAPIInfo.Addrs) |
| 265 apiState, newPassword, err := conf.OpenAPI(api.DialOpts{}) |
| 266 c.Assert(err, gc.IsNil) |
| 267 c.Assert(apiState, gc.NotNil) |
| 268 // It should want to set a new Password |
| 269 c.Assert(newPassword, gc.Not(gc.Equals), "") |
| 270 } |
| 271 |
| 272 // Test that UnitAgent enforces the API password on startup |
| 273 func (s *UpgradeValidationUnitSuite) TestAgentEnsuresAPIInfo(c *gc.C) { |
| 274 unit, _ := s.Create1_10Unit(c) |
| 275 a := &UnitAgent{} |
| 276 s.initAgent(c, a, "--unit-name", unit.Name()) |
| 277 go func() { c.Check(a.Run(nil), gc.IsNil) }() |
| 278 waitForUnitStarted(s.State, unit, c) |
| 279 c.Check(a.Stop(), gc.IsNil) |
| 280 c.Check(a.Conf.APIInfo.Password, gc.Equals, "unit-password") |
| 281 } |
| 282 |
| 283 var _ = gc.Suite(&UpgradeValidationSuite{}) |
| 284 |
| 285 type UpgradeValidationSuite struct { |
| 286 testing.LoggingSuite |
| 287 } |
| 288 |
| 289 type mockAddresser struct { |
| 290 Addrs []string |
| 291 Err error |
| 292 } |
| 293 |
| 294 func (m *mockAddresser) APIAddresses() ([]string, error) { |
| 295 return m.Addrs, m.Err |
| 296 } |
| 297 |
| 298 func (s *UpgradeValidationSuite) TestapiInfoFromStateInfo(c *gc.C) { |
| 299 cert := []byte("stuff") |
| 300 stInfo := &state.Info{ |
| 301 Addrs: []string{"example.invalid:37070"}, |
| 302 CACert: cert, |
| 303 Tag: "machine-0", |
| 304 Password: "abcdefh", |
| 305 } |
| 306 apiAddresses := []string{"example.invalid:17070", "another.invalid:1234"
} |
| 307 apiInfo := apiInfoFromStateInfo(stInfo, &mockAddresser{Addrs: apiAddress
es}) |
| 308 c.Assert(*apiInfo, gc.DeepEquals, api.Info{ |
| 309 Addrs: apiAddresses, |
| 310 CACert: cert, |
| 311 Tag: "machine-0", |
| 312 Password: "abcdefh", |
| 313 }) |
| 314 |
| 315 } |
| 316 |
| 317 func (s *UpgradeValidationSuite) TestapiInfoFromStateInfoSwallowsError(c *gc.C)
{ |
| 318 // No reason for it to die just because of this |
| 319 cert := []byte("stuff") |
| 320 stInfo := &state.Info{ |
| 321 Addrs: []string{"example.invalid:37070"}, |
| 322 CACert: cert, |
| 323 Tag: "machine-0", |
| 324 Password: "abcdefh", |
| 325 } |
| 326 apiAddresses := []string{} |
| 327 apiInfo := apiInfoFromStateInfo(stInfo, &mockAddresser{Addrs: apiAddress
es, Err: fmt.Errorf("bad")}) |
| 328 c.Assert(*apiInfo, gc.DeepEquals, api.Info{ |
| 329 Addrs: []string{}, |
| 330 CACert: cert, |
| 331 Tag: "machine-0", |
| 332 Password: "abcdefh", |
| 333 }) |
| 334 |
| 335 } |
OLD | NEW |