Affected files (+35, -19 lines):
A [revision details]
M cmd/juju/destroymachine_test.go
M state/apiserver/client/client_test.go
M state/cleanup.go
M state/cleanup_test.go
Index: state/cleanup.go
=== modified file 'state/cleanup.go'
--- state/cleanup.go 2013-11-13 08:59:24 +0000
+++ state/cleanup.go 2013-12-10 09:52:04 +0000
@@ -151,14 +151,15 @@
// again -- which it *probably* will anyway -- the issue can be resolved
by
// force-destroying the machine again; that's better than adding layer
// upon layer of complication here.
- if err := machine.EnsureDead(); err != nil {
- return err
- }
- return machine.Remove()
+ return machine.EnsureDead()
+
+ // Note that we do *not* remove the machine entirely: we leave it for the
+ // provisioner to clean up, so that we don't end up with an unreferenced
+ // instance that would otherwise be ignored when in provisioner-safe-mode.
}
// cleanupContainers recursively calls cleanupMachine on the supplied
-// machine's containers.
+// machine's containers, and removes them from state entirely.
func (st *State) cleanupContainers(machine *Machine) error {
containerIds, err := machine.Containers()
if errors.IsNotFoundError(err) {
@@ -170,6 +171,15 @@
if err := st.cleanupMachine(containerId); err != nil {
return err
}
+ container, err := st.Machine(containerId)
+ if errors.IsNotFoundError(err) {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ if err := container.Remove(); err != nil {
+ return err
+ }
}
return nil
}
- // Clean up, and check that the machine has been removed...
+ // Clean up, and check that the unit has been removed...
s.assertCleanupRuns(c)
s.assertDoesNotNeedCleanup(c)
- err = machine.Refresh()
- c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
-
- // ...and so has the unit...
assertRemoved(c, pr.u0)
- // ...and the unit has departed relation scope.
+ // ...and the unit has departed relation scope...
assertNotInScope(c, pr.ru0)
+
+ // ...but that the machine remains, and is Dead, ready for removal by the
+ // provisioner.
+ assertLife(c, machine, state.Dead)
}
- // Clean up, and check that all the machines have been removed...
+ // Clean up, and check that the container has been removed...
s.assertCleanupRuns(c)
s.assertDoesNotNeedCleanup(c)
- err = machine.Refresh()
- c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
err = container.Refresh()
c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
- // ...and none of the units have left relation scopes occupied.
+ // ...and none of the units have left relation scopes occupied...
assertNotInScope(c, prr.pru0)
assertNotInScope(c, prr.pru1)
assertNotInScope(c, prr.rru0)
assertNotInScope(c, prr.rru1)
+
+ // ...but that the machine remains, and is Dead, ready for removal by the
+ // provisioner.
+ assertLife(c, machine, state.Dead)
}
func (s *CleanupSuite) TestNothingToCleanup(c *gc.C) {
Reviewers: mp+198361_ code.launchpad. net,
Message:
Please take a look.
Description:
state: don't remove force-destroyed machines
fixes lp:1259473
https:/ /code.launchpad .net/~fwereade/ juju-core/ force-dead- machine- for-1.16/ +merge/ 198361
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/37610044/
Affected files (+35, -19 lines): destroymachine_ test.go /client/ client_ test.go test.go
A [revision details]
M cmd/juju/
M state/apiserver
M state/cleanup.go
M state/cleanup_
Index: [revision details] 20131209105211- 4qnv0z07ivx7t9i g
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-
+New revision: <email address hidden>
Index: state/cleanup.go EnsureDead( ); err != nil { EnsureDead( ) safe-mode.
=== modified file 'state/cleanup.go'
--- state/cleanup.go 2013-11-13 08:59:24 +0000
+++ state/cleanup.go 2013-12-10 09:52:04 +0000
@@ -151,14 +151,15 @@
// again -- which it *probably* will anyway -- the issue can be resolved
by
// force-destroying the machine again; that's better than adding layer
// upon layer of complication here.
- if err := machine.
- return err
- }
- return machine.Remove()
+ return machine.
+
+ // Note that we do *not* remove the machine entirely: we leave it for the
+ // provisioner to clean up, so that we don't end up with an unreferenced
+ // instance that would otherwise be ignored when in provisioner-
}
// cleanupContainers recursively calls cleanupMachine on the supplied rs(machine *Machine) error { Containers( ) IsNotFoundError (err) { ne(containerId) ; err != nil { containerId) IsNotFoundError (err) {
-// machine's containers.
+// machine's containers, and removes them from state entirely.
func (st *State) cleanupContaine
containerIds, err := machine.
if errors.
@@ -170,6 +171,15 @@
if err := st.cleanupMachi
return err
}
+ container, err := st.Machine(
+ if errors.
+ return nil
+ } else if err != nil {
+ return err
+ }
+ if err := container.Remove(); err != nil {
+ return err
+ }
}
return nil
}
Index: state/cleanup_ test.go cleanup_ test.go' test.go 2013-11-13 09:07:28 +0000 test.go 2013-12-10 09:52:04 +0000 sCleanup( c)
=== modified file 'state/
--- state/cleanup_
+++ state/cleanup_
@@ -128,17 +128,17 @@
c.Assert(err, gc.IsNil)
s.assertNeed
- // Clean up, and check that the machine has been removed... nupRuns( c) NotNeedCleanup( c) IsNotFoundError )
+ // Clean up, and check that the unit has been removed...
s.assertClea
s.assertDoes
- err = machine.Refresh()
- c.Assert(err, jc.Satisfies, errors.
-
- // ...and so has the unit...
assertRemoved(c, pr.u0)
- // ...and the unit has departed relation scope. cope(c, pr.ru0)
+ // ...and the unit has departed relation scope...
assertNotInS
+
+ // ...but that the machine remains, and is Dead, ready for removal by the
+ // provisioner.
+ assertLife(c, machine, state.Dead)
}
func (s *CleanupSuite) TestCleanupForc eDestroyedMachi neWithContainer (c sCleanup( c)
*gc.C) {
@@ -184,11 +184,9 @@
c.Assert(err, gc.IsNil)
s.assertNeed
- // Clean up, and check that all the machines have been removed... nupRuns( c) NotNeedCleanup( c) IsNotFoundError ) IsNotFoundError )
+ // Clean up, and check that the container has been removed...
s.assertClea
s.assertDoes
- err = machine.Refresh()
- c.Assert(err, jc.Satisfies, errors.
err = container.Refresh()
c.Assert(err, jc.Satisfies, errors.
@@ -198,11 +196,15 @@
assertRemoved(c, prr.ru0)
assertRemoved(c, prr.ru1)
- // ...and none of the units have left relation scopes occupied. cope(c, prr.pru0) cope(c, prr.pru1) cope(c, prr.rru0) cope(c, prr.rru1)
+ // ...and none of the units have left relation scopes occupied...
assertNotInS
assertNotInS
assertNotInS
assertNotInS
+
+ // ...but that the machine remains, and is Dead, ready for removal by the
+ // provisioner.
+ assertLife(c, machine, state.Dead)
}
func (s *CleanupSuite) TestNothingToCl eanup(c *gc.C) {
Index: cmd/juju/ destroymachine_ test.go destroymachine_ test.go' destroymachine_ test.go 2013-11-27 12:14:31 +0000 destroymachine_ test.go 2013-12-10 09:52:04 +0000 IsNotFoundError ) IsNotFoundError ) m1.Life( ), gc.Equals, state.Alive)
=== modified file 'cmd/juju/
--- cmd/juju/
+++ cmd/juju/
@@ -103,10 +103,12 @@
// Clean up, check state.
err = s.State.Cleanup()
c.Assert(err, gc.IsNil)
- err = m0.Refresh()
- c.Assert(err, jc.Satisfies, errors.
err = u.Refresh()
c.Assert(err, jc.Satisfies, errors.
+ err = m0.Refresh()
+ c.Assert(err, gc.IsNil)
+ c.Assert(m0.Life(), gc.Equals, state.Dead)
+
err = m1.Refresh()
c.Assert(err, gc.IsNil)
c.Assert(
Index: state/apiserver /client/ client_ test.go apiserver/ client/ client_ test.go' /client/ client_ test.go 2013-11-27 12:14:31 +0000 /client/ client_ test.go 2013-12-10 09:52:04 +0000
=== modified file 'state/
--- state/apiserver
+++ state/apiserver
@@ -415,9 +415,9 @@
err = s.State.Cleanup()
c.Assert(err, gc.IsNil)
- assertRemoved(c, m0)
+ assertLife(c, m0, state.Dead)
assertLife(c, m1, state.Alive)
- assertRemoved(c, m2)
+ assertLife(c, m2, state.Dead)
assertRemoved(c, u)
}