~therve/pyjuju/validate-config-values

« back to all changes in this revision

Viewing changes to juju/unit/lifecycle.py

Subordinate support in unit agent lifecycle [r=kapil] [f=805585,963355]

This branch lands the support in the unit agent which allows it to deploy 
subordinate services in its own container.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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)
18
18
 
19
19
from juju.unit.charm import download_charm
 
20
from juju.unit.deploy import UnitDeployer
20
21
from juju.unit.workflow import RelationWorkflowState
21
22
 
22
23
 
367
368
        new_relations = dict(
368
369
            (service_relation.internal_relation_id, service_relation)
369
370
            for service_relation in new_relations)
 
371
 
 
372
        if old_relations:
 
373
            old_relations = dict(
 
374
                (service_relation.internal_relation_id, service_relation)
 
375
                for service_relation in old_relations)
 
376
 
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())
372
381
 
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()
403
414
 
404
415
    @inlineCallbacks
405
416
    def _add_relation(self, service_relation):
422
433
            lifecycle, self._state_dir)
423
434
 
424
435
        self._relations[service_relation.internal_relation_id] = workflow
 
436
 
425
437
        with (yield workflow.lock()):
426
438
            yield workflow.synchronize()
427
439
 
 
440
    @inlineCallbacks
 
441
    def _do_unit_deploy(self, unit_name, machine_id, charm_dir):
 
442
        # this method exists to aid testing rather than being an
 
443
        # inline
 
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)
 
447
 
 
448
    @inlineCallbacks
 
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]
 
455
 
 
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()
 
461
 
 
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(
 
465
                                     "/", "-"))
 
466
        state_dir = os.path.join(charm_dir, "state")
 
467
        if not os.path.exists(state_dir):
 
468
                os.makedirs(state_dir)
 
469
 
 
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,
 
476
                                   machine_id,
 
477
                                   charm_dir)
 
478
 
428
479
    @property
429
480
    def _known_relations_path(self):
430
481
        return os.path.join(