~niedbalski/charms/trusty/percona-cluster/fix-lp1461669

« back to all changes in this revision

Viewing changes to hooks/percona_utils.py

  • Committer: Edward Hope-Morley
  • Date: 2014-11-25 17:46:13 UTC
  • mfrom: (35.3.57 ipv6)
  • Revision ID: edward.hope-morley@canonical.com-20141125174613-r5qu0bzpm0pcio8e
[hopem,r=james-page]

Adds IPv6 Support

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
import subprocess
3
3
from subprocess import Popen, PIPE
4
4
import socket
 
5
import tempfile
5
6
import os
6
7
from charmhelpers.core.host import (
7
 
    lsb_release,
 
8
    lsb_release
8
9
)
9
10
from charmhelpers.core.hookenv import (
10
11
    unit_get,
13
14
    relation_get,
14
15
    relation_set,
15
16
    local_unit,
 
17
    config,
 
18
    log,
 
19
    INFO
16
20
)
17
21
from charmhelpers.fetch import (
18
22
    apt_install,
19
 
    filter_installed_packages,
 
23
    filter_installed_packages
 
24
)
 
25
from charmhelpers.contrib.network.ip import (
 
26
    get_ipv6_addr
20
27
)
21
28
from mysql import get_mysql_root_password, MySQLHelper
22
29
 
 
30
 
23
31
try:
24
32
    import jinja2
25
33
except ImportError:
44
52
deb-src http://repo.percona.com/apt {release} main"""
45
53
MY_CNF = "/etc/mysql/my.cnf"
46
54
SEEDED_MARKER = "/var/lib/mysql/seeded"
 
55
HOSTS_FILE = '/etc/hosts'
47
56
 
48
57
 
49
58
def seeded():
64
73
    subprocess.check_call(['apt-key', 'add', KEY])
65
74
 
66
75
TEMPLATES_DIR = 'templates'
 
76
FILES_DIR = 'files'
67
77
 
68
78
 
69
79
def render_template(template_name, context, template_dir=TEMPLATES_DIR):
73
83
    return template.render(context)
74
84
 
75
85
 
76
 
# TODO: goto charm-helpers (I use this everywhere)
77
86
def get_host_ip(hostname=None):
 
87
    if config('prefer-ipv6'):
 
88
        # Ensure we have a valid ipv6 address configured
 
89
        get_ipv6_addr(exc_list=[config('vip')], fatal=True)[0]
 
90
        return socket.gethostname()
 
91
 
78
92
    hostname = hostname or unit_get('private-address')
79
93
    try:
80
94
        # Test to see if already an IPv4 address
89
103
 
90
104
 
91
105
def get_cluster_hosts():
92
 
    hosts = [get_host_ip()]
 
106
    hosts_map = {}
 
107
    hostname = get_host_ip()
 
108
    hosts = [hostname]
 
109
    # We need to add this localhost dns name to /etc/hosts along with peer
 
110
    # hosts to ensure percona gets consistently resolved addresses.
 
111
    if config('prefer-ipv6'):
 
112
        addr = get_ipv6_addr(exc_list=[config('vip')], fatal=True)[0]
 
113
        hosts_map = {addr: hostname}
 
114
 
93
115
    for relid in relation_ids('cluster'):
94
116
        for unit in related_units(relid):
95
 
            hosts.append(get_host_ip(relation_get('private-address',
96
 
                                                  unit, relid)))
 
117
            rdata = relation_get(unit=unit, rid=relid)
 
118
            private_address = rdata.get('private-address')
 
119
            if config('prefer-ipv6'):
 
120
                hostname = rdata.get('hostname')
 
121
                if not hostname or hostname in hosts:
 
122
                    log("(unit=%s) Ignoring hostname '%s' provided by cluster "
 
123
                        "relation for addr %s" %
 
124
                        (unit, hostname, private_address))
 
125
                    continue
 
126
                else:
 
127
                    log("(unit=%s) hostname '%s' provided by cluster relation "
 
128
                        "for addr %s" % (unit, hostname, private_address))
 
129
 
 
130
                hosts_map[private_address] = hostname
 
131
                hosts.append(hostname)
 
132
            else:
 
133
                hosts.append(get_host_ip(private_address))
 
134
 
 
135
    if hosts_map:
 
136
        update_hosts_file(hosts_map)
 
137
 
97
138
    return hosts
98
139
 
99
 
SQL_SST_USER_SETUP = "GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.*" \
100
 
    " TO 'sstuser'@'localhost' IDENTIFIED BY '{}'"
 
140
 
 
141
SQL_SST_USER_SETUP = ("GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* "
 
142
                      "TO 'sstuser'@'localhost' IDENTIFIED BY '{}'")
 
143
 
 
144
SQL_SST_USER_SETUP_IPV6 = ("GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT "
 
145
                           "ON *.* TO 'sstuser'@'ip6-localhost' IDENTIFIED "
 
146
                           "BY '{}'")
101
147
 
102
148
 
103
149
def configure_sstuser(sst_password):
104
150
    m_helper = MySQLHelper()
105
151
    m_helper.connect(password=get_mysql_root_password())
106
152
    m_helper.execute(SQL_SST_USER_SETUP.format(sst_password))
 
153
    m_helper.execute(SQL_SST_USER_SETUP_IPV6.format(sst_password))
107
154
 
108
155
 
109
156
# TODO: mysql charmhelper
135
182
                 **settings)
136
183
 
137
184
 
 
185
def update_hosts_file(map):
 
186
    """Percona does not currently like ipv6 addresses so we need to use dns
 
187
    names instead. In order to make them resolvable we ensure they are  in
 
188
    /etc/hosts.
 
189
 
 
190
    See https://bugs.launchpad.net/galera/+bug/1130595 for some more info.
 
191
    """
 
192
    with open(HOSTS_FILE, 'r') as hosts:
 
193
        lines = hosts.readlines()
 
194
 
 
195
    log("Updating hosts file with: %s (current: %s)" % (map, lines),
 
196
        level=INFO)
 
197
 
 
198
    newlines = []
 
199
    for ip, hostname in map.items():
 
200
        if not ip or not hostname:
 
201
            continue
 
202
 
 
203
        keepers = []
 
204
        for line in lines:
 
205
            _line = line.split()
 
206
            if len(line) < 2 or not (_line[0] == ip or hostname in _line[1:]):
 
207
                keepers.append(line)
 
208
            else:
 
209
                log("Removing line '%s' from hosts file" % (line))
 
210
 
 
211
        lines = keepers
 
212
        newlines.append("%s %s\n" % (ip, hostname))
 
213
 
 
214
    lines += newlines
 
215
 
 
216
    with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
 
217
        with open(tmpfile.name, 'w') as hosts:
 
218
            for line in lines:
 
219
                hosts.write(line)
 
220
 
 
221
    os.rename(tmpfile.name, HOSTS_FILE)
 
222
    os.chmod(HOSTS_FILE, 0o644)
 
223
 
 
224
 
 
225
def assert_charm_supports_ipv6():
 
226
    """Check whether we are able to support charms ipv6."""
 
227
    if lsb_release()['DISTRIB_CODENAME'].lower() < "trusty":
 
228
        raise Exception("IPv6 is not supported in the charms for Ubuntu "
 
229
                        "versions less than Trusty 14.04")
 
230
 
 
231
 
138
232
def unit_sorted(units):
139
233
    """Return a sorted list of unit names."""
140
234
    return sorted(