~xianghui/charms/trusty/nova-cloud-controller/live_migration

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/peerstorage/__init__.py

  • Committer: james.page at ubuntu
  • Date: 2015-06-09 09:59:06 UTC
  • mfrom: (143.1.18 nova-cloud-controller)
  • Revision ID: james.page@ubuntu.com-20150609095906-o300u1j0rtk92aem
Add support for leader-election

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU Lesser General Public License
15
15
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
 
17
import json
17
18
import six
 
19
 
18
20
from charmhelpers.core.hookenv import relation_id as current_relation_id
19
21
from charmhelpers.core.hookenv import (
20
22
    is_relation_made,
21
23
    relation_ids,
22
 
    relation_get,
 
24
    relation_get as _relation_get,
23
25
    local_unit,
24
 
    relation_set,
 
26
    relation_set as _relation_set,
 
27
    leader_get as _leader_get,
 
28
    leader_set,
 
29
    is_leader,
25
30
)
26
31
 
27
32
 
54
59
"""
55
60
 
56
61
 
 
62
def leader_get(attribute=None):
 
63
    """Wrapper to ensure that settings are migrated from the peer relation.
 
64
 
 
65
    This is to support upgrading an environment that does not support
 
66
    Juju leadership election to one that does.
 
67
 
 
68
    If a setting is not extant in the leader-get but is on the relation-get
 
69
    peer rel, it is migrated and marked as such so that it is not re-migrated.
 
70
    """
 
71
    migration_key = '__leader_get_migrated_settings__'
 
72
    if not is_leader():
 
73
        return _leader_get(attribute=attribute)
 
74
 
 
75
    settings_migrated = False
 
76
    leader_settings = _leader_get(attribute=attribute)
 
77
    previously_migrated = _leader_get(attribute=migration_key)
 
78
 
 
79
    if previously_migrated:
 
80
        migrated = set(json.loads(previously_migrated))
 
81
    else:
 
82
        migrated = set([])
 
83
 
 
84
    try:
 
85
        if migration_key in leader_settings:
 
86
            del leader_settings[migration_key]
 
87
    except TypeError:
 
88
        pass
 
89
 
 
90
    if attribute:
 
91
        if attribute in migrated:
 
92
            return leader_settings
 
93
 
 
94
        # If attribute not present in leader db, check if this unit has set
 
95
        # the attribute in the peer relation
 
96
        if not leader_settings:
 
97
            peer_setting = relation_get(attribute=attribute, unit=local_unit())
 
98
            if peer_setting:
 
99
                leader_set(settings={attribute: peer_setting})
 
100
                leader_settings = peer_setting
 
101
 
 
102
        if leader_settings:
 
103
            settings_migrated = True
 
104
            migrated.add(attribute)
 
105
    else:
 
106
        r_settings = relation_get(unit=local_unit())
 
107
        if r_settings:
 
108
            for key in set(r_settings.keys()).difference(migrated):
 
109
                # Leader setting wins
 
110
                if not leader_settings.get(key):
 
111
                    leader_settings[key] = r_settings[key]
 
112
 
 
113
                settings_migrated = True
 
114
                migrated.add(key)
 
115
 
 
116
            if settings_migrated:
 
117
                leader_set(**leader_settings)
 
118
 
 
119
    if migrated and settings_migrated:
 
120
        migrated = json.dumps(list(migrated))
 
121
        leader_set(settings={migration_key: migrated})
 
122
 
 
123
    return leader_settings
 
124
 
 
125
 
 
126
def relation_set(relation_id=None, relation_settings=None, **kwargs):
 
127
    """Attempt to use leader-set if supported in the current version of Juju,
 
128
    otherwise falls back on relation-set.
 
129
 
 
130
    Note that we only attempt to use leader-set if the provided relation_id is
 
131
    a peer relation id or no relation id is provided (in which case we assume
 
132
    we are within the peer relation context).
 
133
    """
 
134
    try:
 
135
        if relation_id in relation_ids('cluster'):
 
136
            return leader_set(settings=relation_settings, **kwargs)
 
137
        else:
 
138
            raise NotImplementedError
 
139
    except NotImplementedError:
 
140
        return _relation_set(relation_id=relation_id,
 
141
                             relation_settings=relation_settings, **kwargs)
 
142
 
 
143
 
 
144
def relation_get(attribute=None, unit=None, rid=None):
 
145
    """Attempt to use leader-get if supported in the current version of Juju,
 
146
    otherwise falls back on relation-get.
 
147
 
 
148
    Note that we only attempt to use leader-get if the provided rid is a peer
 
149
    relation id or no relation id is provided (in which case we assume we are
 
150
    within the peer relation context).
 
151
    """
 
152
    try:
 
153
        if rid in relation_ids('cluster'):
 
154
            return leader_get(attribute)
 
155
        else:
 
156
            raise NotImplementedError
 
157
    except NotImplementedError:
 
158
        return _relation_get(attribute=attribute, rid=rid, unit=unit)
 
159
 
 
160
 
57
161
def peer_retrieve(key, relation_name='cluster'):
58
162
    """Retrieve a named key from peer relation `relation_name`."""
59
163
    cluster_rels = relation_ids(relation_name)
73
177
    exc_list = exc_list if exc_list else []
74
178
    peerdb_settings = peer_retrieve('-', relation_name=relation_name)
75
179
    matched = {}
 
180
    if peerdb_settings is None:
 
181
        return matched
76
182
    for k, v in peerdb_settings.items():
77
183
        full_prefix = prefix + delimiter
78
184
        if k.startswith(full_prefix):
96
202
                         'peer relation {}'.format(relation_name))
97
203
 
98
204
 
99
 
def peer_echo(includes=None):
 
205
def peer_echo(includes=None, force=False):
100
206
    """Echo filtered attributes back onto the same relation for storage.
101
207
 
102
208
    This is a requirement to use the peerstorage module - it needs to be called
103
209
    from the peer relation's changed hook.
 
210
 
 
211
    If Juju leader support exists this will be a noop unless force is True.
104
212
    """
 
213
    try:
 
214
        is_leader()
 
215
    except NotImplementedError:
 
216
        pass
 
217
    else:
 
218
        if not force:
 
219
            return  # NOOP if leader-election is supported
 
220
 
 
221
    # Use original non-leader calls
 
222
    relation_get = _relation_get
 
223
    relation_set = _relation_set
 
224
 
105
225
    rdata = relation_get()
106
226
    echo_data = {}
107
227
    if includes is None: