~juju-deployers/juju-deployer/darwin

« back to all changes in this revision

Viewing changes to deployer/action/diff.py

  • Committer: Adam Gandelman
  • Date: 2013-09-03 20:44:14 UTC
  • mfrom: (114 darwin)
  • mto: This revision was merged to the branch mainline in revision 119.
  • Revision ID: adamg@canonical.com-20130903204414-xsqqz2gp83dp5d2o
MergeĀ lp:juju-deployer/darwin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import logging
 
2
import time
 
3
 
 
4
from .base import BaseAction
 
5
from ..relation import EndpointPair
 
6
from ..utils import _parse_constraints, yaml_dump
 
7
 
 
8
 
 
9
class Diff(BaseAction):
 
10
 
 
11
    log = logging.getLogger("deployer.diff")
 
12
 
 
13
    def __init__(self, env, deployment, options):
 
14
        self.options = options
 
15
        self.env = env
 
16
        self.deployment = deployment
 
17
        self.env_status = None
 
18
        self.env_state = {'services': {}, 'relations': []}
 
19
 
 
20
    def load_env(self):
 
21
        """
 
22
        """
 
23
        rels = set()
 
24
        for svc_name in self.env_status['services']:
 
25
            if not svc_name in self.env_status['services']:
 
26
                self.env_state['services'][svc_name] = 'missing'
 
27
            self.env_state['services'].setdefault(svc_name, {})[
 
28
                'options'] = self.env.get_config(svc_name)
 
29
            self.env_state['services'][svc_name][
 
30
                'constraints'] = self.env.get_constraints(svc_name)
 
31
            self.env_state['services'][svc_name][
 
32
                'unit_count'] = len(self.env_status[
 
33
                    'services'][svc_name]['units'])
 
34
            rels.update(self._load_rels(svc_name))
 
35
        self.env_state['relations'] = sorted(rels)
 
36
 
 
37
    def _load_rels(self, svc_name):
 
38
        rels = set()
 
39
        svc_rels = self.env_status['services'][svc_name].get(
 
40
            'relations', {})
 
41
        # There is ambiguity here for multiple rels between two
 
42
        # services without the relation id, which we need support
 
43
        # from core for.
 
44
        for r_name, r_svcs in svc_rels.items():
 
45
            for r_svc in r_svcs:
 
46
                # Skip peer relations
 
47
                if r_svc == svc_name:
 
48
                    continue
 
49
                rr_name = self._get_rel_name(svc_name, r_svc)
 
50
                rels.add(
 
51
                    tuple(sorted([
 
52
                        "%s:%s" % (svc_name, r_name),
 
53
                        "%s:%s" % (r_svc, rr_name)])))
 
54
        return rels
 
55
 
 
56
    def _get_rel_name(self, src, tgt):
 
57
        svc_rels = self.env_status['services'][tgt]['relations']
 
58
        found = None
 
59
        for r, eps in svc_rels.items():
 
60
            if src in eps:
 
61
                if found:
 
62
                    raise ValueError("Ambigious relations for service")
 
63
                found = r
 
64
        return found
 
65
 
 
66
    def get_delta(self):
 
67
        delta = {}
 
68
        rels_delta = self._get_relations_delta()
 
69
        if rels_delta:
 
70
            delta['relations'] = rels_delta
 
71
        svc_delta = self._get_services_delta()
 
72
        if svc_delta:
 
73
            delta['services'] = svc_delta
 
74
        return delta
 
75
 
 
76
    def _get_relations_delta(self):
 
77
        # Simple endpoint diff, no qualified endpoint checking.
 
78
 
 
79
        # Env relations are always qualified (at least in go).
 
80
        delta = {}
 
81
        env_rels = set(
 
82
            EndpointPair(*x) for x in self.env_state.get('relations', ()))
 
83
        dep_rels = set(
 
84
            [EndpointPair(*y) for y in self.deployment.get_relations()])
 
85
 
 
86
        for r in dep_rels.difference(env_rels):
 
87
            delta.setdefault('missing', []).append(r)
 
88
 
 
89
        for r in env_rels.difference(dep_rels):
 
90
            delta.setdefault('unknown', []).append(r)
 
91
 
 
92
        return delta
 
93
 
 
94
    def _get_services_delta(self):
 
95
        delta = {}
 
96
        env_svcs = set(self.env_status['services'].keys())
 
97
        dep_svcs = set([s.name for s in self.deployment.get_services()])
 
98
 
 
99
        missing = dep_svcs - env_svcs
 
100
        if missing:
 
101
            delta['missing'] = {}
 
102
        for a in missing:
 
103
            delta['missing'][a] = self.deployment.get_service(
 
104
                a).svc_data
 
105
        unknown = env_svcs - dep_svcs
 
106
        if unknown:
 
107
            delta['unknown'] = {}
 
108
        for r in unknown:
 
109
            delta['unknown'][r] = self.env_state.get(r)
 
110
 
 
111
        for cs in env_svcs.intersection(dep_svcs):
 
112
            d_s = self.deployment.get_service(cs).svc_data
 
113
            e_s = self.env_state['services'][cs]
 
114
            mod = self._diff_service(e_s, d_s)
 
115
            if not mod:
 
116
                continue
 
117
            if not 'modified' in delta:
 
118
                delta['modified'] = {}
 
119
            delta['modified'][cs] = mod
 
120
        return delta
 
121
 
 
122
    def _diff_service(self, e_s, d_s):
 
123
        mod = {}
 
124
        if 'constraints' in d_s:
 
125
            d_sc = _parse_constraints(d_s['constraints'])
 
126
            if d_sc != e_s['constraints']:
 
127
                mod['constraints'] = e_s['constraints']
 
128
        for k, v in d_s.get('options', {}).items():
 
129
            # Deploy options not known to the env may originate
 
130
            # from charm version delta or be an invalid config.
 
131
            if not k in e_s['options']:
 
132
                continue
 
133
            e_v = e_s['options'].get(k, {}).get('value')
 
134
            if e_v != v:
 
135
                mod['config'] = {k: e_v}
 
136
        if e_s['unit_count'] != d_s.get('num_units', 1):
 
137
            mod['num_units'] = e_s['num_units']
 
138
        return mod
 
139
 
 
140
    def run(self):
 
141
        self.start_time = time.time()
 
142
        self.env.connect()
 
143
        self.env_status = self.env.status()
 
144
        self.load_env()
 
145
        delta = self.get_delta()
 
146
        if delta:
 
147
            print yaml_dump(delta)