8
8
from .charm import Charm
9
9
from .feedback import Feedback
10
from .service import Service, ServiceUnitPlacement
10
from .service import Service, ServiceUnitPlacementV3, ServiceUnitPlacementV4
11
11
from .relation import Endpoint
12
from .utils import path_join, yaml_dump, ErrorExit, resolve_include
12
from .utils import path_join, yaml_dump, ErrorExit, resolve_include, x_in_y
15
15
class Deployment(object):
17
17
log = logging.getLogger("deployer.deploy")
19
def __init__(self, name, data, include_dirs, repo_path=""):
19
def __init__(self, name, data, include_dirs, repo_path="", version=3):
22
22
self.include_dirs = include_dirs
23
23
self.repo_path = repo_path
24
self.version = version
45
47
for name, svc_data in self.data.get('services', {}).items():
46
48
services.append(Service(name, svc_data))
47
services.sort(self._placement_sort)
50
# Sort unplaced units first, then sort by name for placed units.
51
services.sort(key=lambda svc: (bool(svc.unit_placement), svc.name))
53
services.sort(self._machines_placement_sort)
56
def set_machines(self, machines):
57
"""Set a dict of machines, mapping from the names in the machine spec
58
to the machine names in the environment status.
60
self.machines = machines
62
def get_machines(self):
63
"""Return a dict mapping machine names to machine options.
65
An empty dict is returned if no machines are defined in the
69
for key, machine in self.data.get('machines', {}).items():
70
machines[str(key)] = machine
50
73
def get_service_names(self):
51
74
"""Return a sequence of service names for this deployment."""
52
75
return self.data.get('services', {}).keys()
55
def _placement_sort(svc_a, svc_b):
78
def _machines_placement_sort(svc_a, svc_b):
79
"""Sort machines with machine placement in mind.
81
If svc_a is colocated alongside svc_b, svc_b needs to be deployed
82
first, so that it exists by the time svc_a is deployed, and vice
83
versa; this sorts first based on this fact, then secondly based on
84
whether or not the service has a unit placement, and then finally
85
based on the name of the service.
56
87
if svc_a.unit_placement:
57
88
if svc_b.unit_placement:
89
# Check for colocation. This naively assumes that there is no
90
# circularity in placements.
91
if x_in_y(svc_b, svc_a):
93
if x_in_y(svc_a, svc_b):
95
# If no colocation exists, simply compare names.
58
96
return cmp(svc_a.name, svc_b.name)
60
98
if svc_b.unit_placement:
64
102
def get_unit_placement(self, svc, status):
65
103
if isinstance(svc, (str, unicode)):
66
104
svc = self.get_service(svc)
67
return ServiceUnitPlacement(svc, self, status)
105
if self.version == 3:
106
return ServiceUnitPlacementV3(svc, self, status)
108
return ServiceUnitPlacementV4(svc, self, status,
109
machines_map=self.machines)
69
111
def get_relations(self):
70
112
if 'relations' not in self.data:
161
203
for svc_name, svc_data in self.data['services'].items():
162
204
charm = self.get_charm_for(svc_name)
163
205
if k in charm.config:
164
if 'options' not in svc_data:
206
if not svc_data.get('options'):
165
207
svc_data['options'] = {}
166
208
svc_data['options'][k] = v