14
14
DepartedRelationHookContext, HookContext, RelationChange)
15
15
from juju.state.errors import StopWatcher, UnitRelationStateNotFound
16
16
from juju.state.relation import (
17
RelationStateManager, ServiceRelationState, UnitRelationState)
17
RelationStateManager, UnitRelationState)
19
19
from juju.unit.charm import download_charm
20
from juju.unit.deploy import UnitDeployer
20
21
from juju.unit.workflow import RelationWorkflowState
367
368
new_relations = dict(
368
369
(service_relation.internal_relation_id, service_relation)
369
370
for service_relation in new_relations)
373
old_relations = dict(
374
(service_relation.internal_relation_id, service_relation)
375
for service_relation in old_relations)
370
377
added = set(new_relations.keys()) - set(self._relations.keys())
371
378
removed = set(self._relations.keys()) - set(new_relations.keys())
379
# Could this service be a principal container?
380
is_principal = not (yield self._service.is_subordinate())
373
382
# Once we know a relation is departed, *immediately* stop running
374
383
# its hooks. We can't really handle the case in which a hook is
399
408
for relation_id in added:
400
409
service_relation = new_relations[relation_id]
401
410
yield self._add_relation(service_relation)
402
self._store_relations()
411
if (is_principal and service_relation.relation_scope == "container"):
412
self._add_subordinate_unit(service_relation)
413
yield self._store_relations()
405
416
def _add_relation(self, service_relation):
422
433
lifecycle, self._state_dir)
424
435
self._relations[service_relation.internal_relation_id] = workflow
425
437
with (yield workflow.lock()):
426
438
yield workflow.synchronize()
441
def _do_unit_deploy(self, unit_name, machine_id, charm_dir):
442
# this method exists to aid testing rather than being an
444
unit_deployer = UnitDeployer(self._client, machine_id, charm_dir)
445
yield unit_deployer.start("subordinate")
446
yield unit_deployer.start_service_unit(unit_name)
449
def _add_subordinate_unit(self, service_relation):
450
"""Deploy a subordinate unit for service_relation remote endpoint."""
451
# Figure out the remote service state
452
service_states = yield service_relation.get_service_states()
453
subordinate_service = [s for s in service_states if
454
s.service_name != self._unit.service_name][0]
456
# add a unit state to service (using self._unit as the
457
# principal container)
458
subordinate_unit = yield subordinate_service.add_unit_state(
459
container=self._unit)
460
machine_id = yield self._unit.get_assigned_machine_id()
462
subordinate_unit_dir = os.path.dirname(self._unit_dir)
463
charm_dir = os.path.join(subordinate_unit_dir,
464
subordinate_unit.unit_name.replace(
466
state_dir = os.path.join(charm_dir, "state")
467
if not os.path.exists(state_dir):
468
os.makedirs(state_dir)
470
self._log.debug("deploying %s as subordinate of %s",
471
subordinate_unit.unit_name,
472
self._unit.unit_name)
473
# with the relation in place and the units added to the
474
# container we can start the unit agent
475
yield self._do_unit_deploy(subordinate_unit.unit_name,
429
480
def _known_relations_path(self):
430
481
return os.path.join(