Block the current coro until the machine is actually removed
from the remote model. This follows the same pattern as other
operations, e.g. Model.deploy().
Also clean up tests, making each functional test run on its
own clean model.
for unit in application.units))
await application.remove()
for unit in application.units))
await application.remove()
- await machine3.destroy()
- await machine2.destroy()
- await machine1.destroy()
+
+ await machine3.destroy(force=True)
+ await machine2.destroy(force=True)
+ await machine1.destroy(force=True)
finally:
await model.disconnect()
finally:
await model.disconnect()
async def destroy(self, force=False):
"""Remove this machine from the model.
async def destroy(self, force=False):
"""Remove this machine from the model.
+ Blocks until the machine is actually removed.
+
"""
facade = client.ClientFacade()
facade.connect(self.connection)
"""
facade = client.ClientFacade()
facade.connect(self.connection)
log.debug(
'Destroying machine %s', self.id)
log.debug(
'Destroying machine %s', self.id)
- return await facade.DestroyMachines(force, [self.id])
+ await facade.DestroyMachines(force, [self.id])
+ return await self.model._wait(
+ 'machine', self.id, 'remove')
remove = destroy
def run(self, command, timeout=None):
remove = destroy
def run(self, command, timeout=None):
:param entity_type: The entity's type.
:param entity_id: The entity's id.
:param entity_type: The entity's type.
:param entity_id: The entity's id.
- :param action: the type of action (e.g., 'add' or 'change')
+ :param action: the type of action (e.g., 'add', 'change', or 'remove')
:param predicate: optional callable that must take as an
argument a delta, and must return a boolean, indicating
whether the delta contains the specific action we're looking
:param predicate: optional callable that must take as an
argument a delta, and must return a boolean, indicating
whether the delta contains the specific action we're looking
self.add_observer(callback, entity_type, action, entity_id, predicate)
entity_id = await q.get()
self.add_observer(callback, entity_type, action, entity_id, predicate)
entity_id = await q.get()
- return self.state._live_entity_map(entity_type)[entity_id]
+ # object might not be in the entity_map if we were waiting for a
+ # 'remove' action
+ return self.state._live_entity_map(entity_type).get(entity_id)
async def _wait_for_new(self, entity_type, entity_id=None, predicate=None):
"""Wait for a new object to appear in the Model and return it.
async def _wait_for_new(self, entity_type, entity_id=None, predicate=None):
"""Wait for a new object to appear in the Model and return it.
import subprocess
import pytest
import subprocess
import pytest
+from juju.controller import Controller
+
def is_bootstrapped():
result = subprocess.run(['juju', 'switch'], stdout=subprocess.PIPE)
def is_bootstrapped():
result = subprocess.run(['juju', 'switch'], stdout=subprocess.PIPE)
bootstrapped = pytest.mark.skipif(
not is_bootstrapped(),
reason='bootstrapped Juju environment required')
bootstrapped = pytest.mark.skipif(
not is_bootstrapped(),
reason='bootstrapped Juju environment required')
+
+
+class CleanModel():
+ def __init__(self):
+ self.controller = None
+ self.model = None
+
+ async def __aenter__(self):
+ self.controller = Controller()
+ await self.controller.connect_current()
+
+ model_name = 'model-{}'.format(uuid.uuid4())
+ self.model = await self.controller.add_model(model_name)
+
+ return self.model
+
+ async def __aexit__(self, exc_type, exc, tb):
+ await self.model.disconnect()
+ await self.controller.destroy_model(self.model.info.uuid)
+ await self.controller.disconnect()
-from juju.client.connection import Connection
from juju.client import client
from juju.client import client
-from ..base import bootstrapped
@pytest.mark.asyncio
async def test_user_info(event_loop):
@pytest.mark.asyncio
async def test_user_info(event_loop):
- conn = await Connection.connect_current()
- controller_conn = await conn.controller()
+ async with base.CleanModel() as model:
+ controller_conn = await model.connection.controller()
- um = client.UserManagerFacade()
- um.connect(controller_conn)
- result = await um.UserInfo(
- [client.Entity('user-admin')], True)
- await conn.close()
- await controller_conn.close()
+ um = client.UserManagerFacade()
+ um.connect(controller_conn)
+ result = await um.UserInfo(
+ [client.Entity('user-admin')], True)
+ await controller_conn.close()
- assert isinstance(result, client.UserInfoResults)
- for r in result.results:
- assert isinstance(r, client.UserInfoResult)
+ assert isinstance(result, client.UserInfoResults)
+ for r in result.results:
+ assert isinstance(r, client.UserInfoResult)
import pytest
from juju.client.connection import Connection
import pytest
from juju.client.connection import Connection
-from ..base import bootstrapped
@pytest.mark.asyncio
async def test_connect_current(event_loop):
@pytest.mark.asyncio
async def test_connect_current(event_loop):
- conn = await Connection.connect_current()
+ async with base.CleanModel():
+ conn = await Connection.connect_current()
- assert isinstance(conn, Connection)
- await conn.close()
+ assert isinstance(conn, Connection)
+ await conn.close()
-from juju.controller import Controller
-
-from ..base import bootstrapped
-class CleanModel():
- def __init__(self):
- self.controller = None
- self.model = None
-
- async def __aenter__(self):
- self.controller = Controller()
- await self.controller.connect_current()
-
- model_name = 'model-{}'.format(uuid.uuid4())
- self.model = await self.controller.add_model(model_name)
-
- return self.model
-
- async def __aexit__(self, exc_type, exc, tb):
- await self.model.disconnect()
- await self.controller.destroy_model(self.model.info.uuid)
- await self.controller.disconnect()
-
-
-@bootstrapped
@pytest.mark.asyncio
async def test_add_machine(event_loop):
from juju.machine import Machine
@pytest.mark.asyncio
async def test_add_machine(event_loop):
from juju.machine import Machine
- async with CleanModel() as model:
+ async with base.CleanModel() as model:
# add a new default machine
machine1 = await model.add_machine()
# add a new default machine
machine1 = await model.add_machine()
assert isinstance(m, Machine)
assert len(model.machines) == 3
assert isinstance(m, Machine)
assert len(model.machines) == 3
+
+ await machine3.destroy(force=True)
+ await machine2.destroy(force=True)
+ res = await machine1.destroy(force=True)
+
+ assert res is None
+ assert len(model.machines) == 0