~cf-charmers/charms/trusty/etcd/trunk

« back to all changes in this revision

Viewing changes to hooks/charmhelpers/contrib/hahelpers/cluster.py

  • Committer: Alexander Prismakov
  • Date: 2014-05-30 12:51:24 UTC
  • Revision ID: prismakov@gmail.com-20140530125124-2l3jn9isfi1d7hjl
new charmchelpers

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#
2
 
# Copyright 2012 Canonical Ltd.
3
 
#
4
 
# Authors:
5
 
#  James Page <james.page@ubuntu.com>
6
 
#  Adam Gandelman <adamg@ubuntu.com>
7
 
#
8
 
 
9
 
import subprocess
10
 
import os
11
 
 
12
 
from socket import gethostname as get_unit_hostname
13
 
 
14
 
from charmhelpers.core.hookenv import (
15
 
    log,
16
 
    relation_ids,
17
 
    related_units as relation_list,
18
 
    relation_get,
19
 
    config as config_get,
20
 
    INFO,
21
 
    ERROR,
22
 
    unit_get,
23
 
)
24
 
 
25
 
 
26
 
class HAIncompleteConfig(Exception):
27
 
    pass
28
 
 
29
 
 
30
 
def is_clustered():
31
 
    for r_id in (relation_ids('ha') or []):
32
 
        for unit in (relation_list(r_id) or []):
33
 
            clustered = relation_get('clustered',
34
 
                                     rid=r_id,
35
 
                                     unit=unit)
36
 
            if clustered:
37
 
                return True
38
 
    return False
39
 
 
40
 
 
41
 
def is_leader(resource):
42
 
    cmd = [
43
 
        "crm", "resource",
44
 
        "show", resource
45
 
    ]
46
 
    try:
47
 
        status = subprocess.check_output(cmd)
48
 
    except subprocess.CalledProcessError:
49
 
        return False
50
 
    else:
51
 
        if get_unit_hostname() in status:
52
 
            return True
53
 
        else:
54
 
            return False
55
 
 
56
 
 
57
 
def peer_units():
58
 
    peers = []
59
 
    for r_id in (relation_ids('cluster') or []):
60
 
        for unit in (relation_list(r_id) or []):
61
 
            peers.append(unit)
62
 
    return peers
63
 
 
64
 
 
65
 
def oldest_peer(peers):
66
 
    local_unit_no = int(os.getenv('JUJU_UNIT_NAME').split('/')[1])
67
 
    for peer in peers:
68
 
        remote_unit_no = int(peer.split('/')[1])
69
 
        if remote_unit_no < local_unit_no:
70
 
            return False
71
 
    return True
72
 
 
73
 
 
74
 
def eligible_leader(resource):
75
 
    if is_clustered():
76
 
        if not is_leader(resource):
77
 
            log('Deferring action to CRM leader.', level=INFO)
78
 
            return False
79
 
    else:
80
 
        peers = peer_units()
81
 
        if peers and not oldest_peer(peers):
82
 
            log('Deferring action to oldest service unit.', level=INFO)
83
 
            return False
84
 
    return True
85
 
 
86
 
 
87
 
def https():
88
 
    '''
89
 
    Determines whether enough data has been provided in configuration
90
 
    or relation data to configure HTTPS
91
 
    .
92
 
    returns: boolean
93
 
    '''
94
 
    if config_get('use-https') == "yes":
95
 
        return True
96
 
    if config_get('ssl_cert') and config_get('ssl_key'):
97
 
        return True
98
 
    for r_id in relation_ids('identity-service'):
99
 
        for unit in relation_list(r_id):
100
 
            rel_state = [
101
 
                relation_get('https_keystone', rid=r_id, unit=unit),
102
 
                relation_get('ssl_cert', rid=r_id, unit=unit),
103
 
                relation_get('ssl_key', rid=r_id, unit=unit),
104
 
                relation_get('ca_cert', rid=r_id, unit=unit),
105
 
            ]
106
 
            # NOTE: works around (LP: #1203241)
107
 
            if (None not in rel_state) and ('' not in rel_state):
108
 
                return True
109
 
    return False
110
 
 
111
 
 
112
 
def determine_api_port(public_port):
113
 
    '''
114
 
    Determine correct API server listening port based on
115
 
    existence of HTTPS reverse proxy and/or haproxy.
116
 
 
117
 
    public_port: int: standard public port for given service
118
 
 
119
 
    returns: int: the correct listening port for the API service
120
 
    '''
121
 
    i = 0
122
 
    if len(peer_units()) > 0 or is_clustered():
123
 
        i += 1
124
 
    if https():
125
 
        i += 1
126
 
    return public_port - (i * 10)
127
 
 
128
 
 
129
 
def determine_apache_port(public_port):
130
 
    '''
131
 
    Description: Determine correct apache listening port based on public IP +
132
 
    state of the cluster.
133
 
 
134
 
    public_port: int: standard public port for given service
135
 
 
136
 
    returns: int: the correct listening port for the HAProxy service
137
 
    '''
138
 
    i = 0
139
 
    if len(peer_units()) > 0 or is_clustered():
140
 
        i += 1
141
 
    return public_port - (i * 10)
142
 
 
143
 
 
144
 
def get_hacluster_config():
145
 
    '''
146
 
    Obtains all relevant configuration from charm configuration required
147
 
    for initiating a relation to hacluster:
148
 
 
149
 
        ha-bindiface, ha-mcastport, vip, vip_iface, vip_cidr
150
 
 
151
 
    returns: dict: A dict containing settings keyed by setting name.
152
 
    raises: HAIncompleteConfig if settings are missing.
153
 
    '''
154
 
    settings = ['ha-bindiface', 'ha-mcastport', 'vip', 'vip_iface', 'vip_cidr']
155
 
    conf = {}
156
 
    for setting in settings:
157
 
        conf[setting] = config_get(setting)
158
 
    missing = []
159
 
    [missing.append(s) for s, v in conf.iteritems() if v is None]
160
 
    if missing:
161
 
        log('Insufficient config data to configure hacluster.', level=ERROR)
162
 
        raise HAIncompleteConfig
163
 
    return conf
164
 
 
165
 
 
166
 
def canonical_url(configs, vip_setting='vip'):
167
 
    '''
168
 
    Returns the correct HTTP URL to this host given the state of HTTPS
169
 
    configuration and hacluster.
170
 
 
171
 
    :configs    : OSTemplateRenderer: A config tempating object to inspect for
172
 
                                      a complete https context.
173
 
    :vip_setting:                str: Setting in charm config that specifies
174
 
                                      VIP address.
175
 
    '''
176
 
    scheme = 'http'
177
 
    if 'https' in configs.complete_contexts():
178
 
        scheme = 'https'
179
 
    if is_clustered():
180
 
        addr = config_get(vip_setting)
181
 
    else:
182
 
        addr = unit_get('private-address')
183
 
    return '%s://%s' % (scheme, addr)