def terminate_machine(config, environment, verbose, log, machine_ids): """Terminates the machines in `machine_ids`. Like the underlying code in MachineStateManager, it's permissible if the machine ID is already terminated or even never running. If we determine this is not desired behavior, presumably propagate that back to the state manager. XXX However, we currently special case support of not terminating the "root" machine, that is the one running the provisioning agent. At some point, this will be managed like any other service, but until then it seems best to ensure it's not terminated at this level. """ provider = environment.get_machine_provider() client = yield provider.connect() terminated_machine_ids = [] try: machine_state_manager = MachineStateManager(client) for machine_id in machine_ids: if machine_id == 0: raise CannotTerminateMachine(0, "environment would be destroyed") removed = yield machine_state_manager.remove_machine_state( machine_id) if not removed: raise MachineStateNotFound(machine_id) terminated_machine_ids.append(machine_id) finally: yield client.close() if terminated_machine_ids: log.info("Machines terminated: %s", ", ".join(str(id) for id in terminated_machine_ids))
def terminate_machine(config, environment, verbose, log, machine_ids): """Terminates the machines in `machine_ids`. Like the underlying code in MachineStateManager, it's permissible if the machine ID is already terminated or even never running. If we determine this is not desired behavior, presumably propagate that back to the state manager. XXX However, we currently special case support of not terminating the "root" machine, that is the one running the provisioning agent. At some point, this will be managed like any other service, but until then it seems best to ensure it's not terminated at this level. """ provider = environment.get_machine_provider() client = yield provider.connect() terminated_machine_ids = [] try: machine_state_manager = MachineStateManager(client) for machine_id in machine_ids: if machine_id == 0: raise CannotTerminateMachine( 0, "environment would be destroyed") removed = yield machine_state_manager.remove_machine_state( machine_id) if not removed: raise MachineStateNotFound(machine_id) terminated_machine_ids.append(machine_id) finally: yield client.close() if terminated_machine_ids: log.info( "Machines terminated: %s", ", ".join(str(id) for id in terminated_machine_ids))
class MachineStateManagerTest(StateTestBase): @inlineCallbacks def setUp(self): yield super(MachineStateManagerTest, self).setUp() self.charm_state_manager = CharmStateManager(self.client) self.machine_state_manager = MachineStateManager(self.client) self.service_state_manager = ServiceStateManager(self.client) self.charm_state = yield self.charm_state_manager.add_charm_state( local_charm_id(self.charm), self.charm, "") @inlineCallbacks def add_service(self, service_name): service_state = yield self.service_state_manager.add_service_state( service_name, self.charm_state) returnValue(service_state) @inlineCallbacks def test_add_machine(self): """ Adding a machine state should register it in zookeeper. """ machine_state1 = yield self.machine_state_manager.add_machine_state() machine_state2 = yield self.machine_state_manager.add_machine_state() self.assertEquals(machine_state1.id, 0) self.assertEquals(machine_state1.internal_id, "machine-0000000000") self.assertEquals(machine_state2.id, 1) self.assertEquals(machine_state2.internal_id, "machine-0000000001") children = yield self.client.get_children("/machines") self.assertEquals(sorted(children), ["machine-0000000000", "machine-0000000001"]) topology = yield self.get_topology() self.assertTrue(topology.has_machine("machine-0000000000")) self.assertTrue(topology.has_machine("machine-0000000001")) @inlineCallbacks def test_machine_str_representation(self): """The str(machine) value includes the machine id. """ machine_state1 = yield self.machine_state_manager.add_machine_state() self.assertEqual( str(machine_state1), "<MachineState id:machine-%010d>" % (0)) @inlineCallbacks def test_remove_machine(self): """ Adding a machine state should register it in zookeeper. """ machine_state1 = yield self.machine_state_manager.add_machine_state() yield self.machine_state_manager.add_machine_state() removed = yield self.machine_state_manager.remove_machine_state( machine_state1.id) self.assertTrue(removed) children = yield self.client.get_children("/machines") self.assertEquals(sorted(children), ["machine-0000000001"]) topology = yield self.get_topology() self.assertFalse(topology.has_machine("machine-0000000000")) self.assertTrue(topology.has_machine("machine-0000000001")) # Removing a non-existing machine again won't fail, since the end # intention is preserved. This makes dealing with concurrency easier. # However, False will be returned in this case. removed = yield self.machine_state_manager.remove_machine_state( machine_state1.id) self.assertFalse(removed) @inlineCallbacks def test_remove_machine_with_agent(self): """Removing a machine with a connected machine agent should succeed. The removal signals intent to remove a working machine (with an agent) with the provisioning agent to remove it subsequently. """ # Add two machines. machine_state1 = yield self.machine_state_manager.add_machine_state() yield self.machine_state_manager.add_machine_state() # Connect an agent yield machine_state1.connect_agent() # Remove a machine removed = yield self.machine_state_manager.remove_machine_state( machine_state1.id) self.assertTrue(removed) # Verify the second one is still present children = yield self.client.get_children("/machines") self.assertEquals(sorted(children), ["machine-0000000001"]) # Verify the topology state. topology = yield self.get_topology() self.assertFalse(topology.has_machine("machine-0000000000")) self.assertTrue(topology.has_machine("machine-0000000001")) @inlineCallbacks def test_get_machine_and_check_attributes(self): """ Getting a machine state should be possible using both the user-oriented id and the internal id. """ yield self.machine_state_manager.add_machine_state() yield self.machine_state_manager.add_machine_state() machine_state = yield self.machine_state_manager.get_machine_state(0) self.assertEquals(machine_state.id, 0) machine_state = yield self.machine_state_manager.get_machine_state("0") self.assertEquals(machine_state.id, 0) yield self.assertFailure( self.machine_state_manager.get_machine_state("a"), MachineStateNotFound) @inlineCallbacks def test_get_machine_not_found(self): """ Getting a machine state which is not available should errback a meaningful error. """ # No state whatsoever. try: yield self.machine_state_manager.get_machine_state(0) except MachineStateNotFound, e: self.assertEquals(e.machine_id, 0) else: