fix for hosts update issue + unit tests
This commit is contained in:
parent
7ede70871c
commit
8eaea905f7
4
Makefile
4
Makefile
|
@ -1,10 +1,14 @@
|
|||
#!/usr/bin/make
|
||||
PYTHON := /usr/bin/env python
|
||||
export PYTHONPATH := hooks
|
||||
|
||||
lint:
|
||||
@flake8 --exclude hooks/charmhelpers hooks
|
||||
@charm proof
|
||||
|
||||
unit_test:
|
||||
@$(PYTHON) /usr/bin/nosetests --nologcapture unit_tests
|
||||
|
||||
bin/charm_helpers_sync.py:
|
||||
@mkdir -p bin
|
||||
@bzr cat lp:charm-helpers/tools/charm_helpers_sync/charm_helpers_sync.py \
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
''' General utilities for percona '''
|
||||
import re
|
||||
import subprocess
|
||||
from subprocess import Popen, PIPE
|
||||
import socket
|
||||
import tempfile
|
||||
import os
|
||||
from charmhelpers.core.host import (
|
||||
lsb_release
|
||||
|
@ -13,7 +15,8 @@ from charmhelpers.core.hookenv import (
|
|||
relation_get,
|
||||
relation_set,
|
||||
local_unit,
|
||||
config
|
||||
config,
|
||||
log
|
||||
)
|
||||
from charmhelpers.fetch import (
|
||||
apt_install,
|
||||
|
@ -49,6 +52,7 @@ REPO = """deb http://repo.percona.com/apt {release} main
|
|||
deb-src http://repo.percona.com/apt {release} main"""
|
||||
MY_CNF = "/etc/mysql/my.cnf"
|
||||
SEEDED_MARKER = "/var/lib/mysql/seeded"
|
||||
HOSTS_FILE = '/etc/hosts'
|
||||
|
||||
|
||||
def seeded():
|
||||
|
@ -78,15 +82,10 @@ def render_template(template_name, context, template_dir=TEMPLATES_DIR):
|
|||
return template.render(context)
|
||||
|
||||
|
||||
# TODO: goto charm-helpers (I use this everywhere)
|
||||
def get_host_ip(hostname=None):
|
||||
if config('prefer-ipv6'):
|
||||
private_address = get_ipv6_addr(exc_list=[config('vip')])[0]
|
||||
hostname = socket.gethostname()
|
||||
host_map = {}
|
||||
host_map[private_address] = hostname
|
||||
render_hosts(host_map)
|
||||
return hostname
|
||||
get_ipv6_addr(exc_list=[config('vip')])[0]
|
||||
return socket.gethostname()
|
||||
|
||||
hostname = hostname or unit_get('private-address')
|
||||
try:
|
||||
|
@ -102,22 +101,25 @@ def get_host_ip(hostname=None):
|
|||
|
||||
|
||||
def get_cluster_hosts():
|
||||
hosts = [get_host_ip()]
|
||||
hosts = []
|
||||
hosts_map = {}
|
||||
for relid in relation_ids('cluster'):
|
||||
for unit in related_units(relid):
|
||||
private_address = relation_get('private-address', unit, relid)
|
||||
|
||||
if config('prefer-ipv6'):
|
||||
hosts.append(get_host_ip())
|
||||
hostname = relation_get('hostname', unit, relid)
|
||||
if not hostname or hostname in hosts:
|
||||
log("hostname '%s' provided by cluster relation" % (hostname))
|
||||
if not hostname:
|
||||
continue
|
||||
|
||||
hosts_map[private_address] = hostname
|
||||
hosts.append(hostname)
|
||||
else:
|
||||
hosts.append(get_host_ip(private_address))
|
||||
|
||||
render_hosts(hosts_map)
|
||||
update_hosts_file(hosts_map)
|
||||
return hosts
|
||||
|
||||
SQL_SST_USER_SETUP = "GRANT RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.*" \
|
||||
|
@ -159,23 +161,39 @@ def relation_clear(r_id=None):
|
|||
**settings)
|
||||
|
||||
|
||||
def render_hosts(map):
|
||||
FILE = '/etc/hosts'
|
||||
print "render_hosts"
|
||||
with open(FILE, 'r') as hosts:
|
||||
def update_hosts_file(map):
|
||||
"""Percona does not currently like ipv6 addresses so we need to use dns
|
||||
names instead. In order to make them resolvable we ensure they are in
|
||||
/etc/hosts.
|
||||
|
||||
See https://bugs.launchpad.net/galera/+bug/1130595 for some more info.
|
||||
"""
|
||||
with open(HOSTS_FILE, 'r') as hosts:
|
||||
lines = hosts.readlines()
|
||||
|
||||
key = re.compile("^(.+?)\s(.+)")
|
||||
newlines = []
|
||||
for ip, hostname in map.items():
|
||||
if not ip or not hostname:
|
||||
continue
|
||||
for line in lines:
|
||||
if line.startswith(ip) or hostname in line:
|
||||
lines.remove(line)
|
||||
lines.append(ip + ' ' + hostname + '\n')
|
||||
|
||||
with open(FILE, 'w') as hosts:
|
||||
for line in lines:
|
||||
hosts.write(line)
|
||||
match = re.match(key, line)
|
||||
if match:
|
||||
if ((match.group(1) != ip and
|
||||
hostname not in match.group(2).split()) and
|
||||
line not in newlines):
|
||||
# keep the line
|
||||
newlines.append(line)
|
||||
|
||||
newlines.append("%s %s\n" % (ip, hostname))
|
||||
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
|
||||
with open(tmpfile.name, 'w') as hosts:
|
||||
for line in newlines:
|
||||
hosts.write(line)
|
||||
|
||||
os.rename(tmpfile.name, HOSTS_FILE)
|
||||
|
||||
|
||||
def assert_charm_supports_ipv6():
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
import mock
|
||||
import os
|
||||
import unittest
|
||||
import tempfile
|
||||
import sys
|
||||
|
||||
sys.modules['MySQLdb'] = mock.Mock()
|
||||
import percona_utils
|
||||
|
||||
|
||||
class UtilsTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
super(UtilsTests, self).setUp()
|
||||
|
||||
def test_update_empty_hosts_file(self):
|
||||
map = {'1.2.3.4': 'my-host'}
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
|
||||
percona_utils.HOSTS_FILE = tmpfile.name
|
||||
percona_utils.HOSTS_FILE = tmpfile.name
|
||||
percona_utils.update_hosts_file(map)
|
||||
|
||||
with open(tmpfile.name, 'r') as fd:
|
||||
lines = fd.readlines()
|
||||
|
||||
os.remove(tmpfile.name)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], "%s %s\n" % (map.items()[0]))
|
||||
|
||||
def test_update_hosts_file_w_dup(self):
|
||||
map = {'1.2.3.4': 'my-host'}
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
|
||||
percona_utils.HOSTS_FILE = tmpfile.name
|
||||
|
||||
with open(tmpfile.name, 'w') as fd:
|
||||
fd.write("%s %s\n" % (map.items()[0]))
|
||||
|
||||
percona_utils.update_hosts_file(map)
|
||||
|
||||
with open(tmpfile.name, 'r') as fd:
|
||||
lines = fd.readlines()
|
||||
|
||||
os.remove(tmpfile.name)
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertEqual(lines[0], "%s %s\n" % (map.items()[0]))
|
||||
|
||||
def test_update_hosts_file_entry(self):
|
||||
altmap = {'2.4.6.8': 'alt-host'}
|
||||
map = {'1.2.3.4': 'my-host'}
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmpfile:
|
||||
percona_utils.HOSTS_FILE = tmpfile.name
|
||||
|
||||
with open(tmpfile.name, 'w') as fd:
|
||||
fd.write("%s %s\n" % (altmap.items()[0]))
|
||||
|
||||
percona_utils.update_hosts_file(map)
|
||||
|
||||
with open(tmpfile.name, 'r') as fd:
|
||||
lines = fd.readlines()
|
||||
|
||||
os.remove(tmpfile.name)
|
||||
self.assertEqual(len(lines), 2)
|
||||
self.assertEqual(lines[0], "%s %s\n" % (altmap.items()[0]))
|
||||
self.assertEqual(lines[1], "%s %s\n" % (map.items()[0]))
|
||||
|
||||
@mock.patch("percona_utils.log")
|
||||
@mock.patch("percona_utils.config")
|
||||
@mock.patch("percona_utils.update_hosts_file")
|
||||
@mock.patch("percona_utils.get_host_ip")
|
||||
@mock.patch("percona_utils.relation_get")
|
||||
@mock.patch("percona_utils.related_units")
|
||||
@mock.patch("percona_utils.relation_ids")
|
||||
def test_get_cluster_hosts(self, mock_rel_ids, mock_rel_units,
|
||||
mock_rel_get, mock_get_host_ip,
|
||||
mock_update_hosts_file, mock_config,
|
||||
mock_log):
|
||||
mock_rel_ids.return_value = [1,2]
|
||||
mock_rel_units.return_value = [3,4]
|
||||
mock_rel_get.return_value = '0.0.0.0'
|
||||
mock_config.side_effect = lambda k: False
|
||||
|
||||
percona_utils.get_cluster_hosts()
|
||||
|
||||
mock_rel_get.assert_called_with('private-address', 4, 2)
|
||||
|
||||
@mock.patch("percona_utils.log")
|
||||
@mock.patch("percona_utils.config")
|
||||
@mock.patch("percona_utils.update_hosts_file")
|
||||
@mock.patch("percona_utils.get_host_ip")
|
||||
@mock.patch("percona_utils.relation_get")
|
||||
@mock.patch("percona_utils.related_units")
|
||||
@mock.patch("percona_utils.relation_ids")
|
||||
def test_get_cluster_hosts_ipv6(self, mock_rel_ids, mock_rel_units,
|
||||
mock_rel_get, mock_get_host_ip,
|
||||
mock_update_hosts_file, mock_config,
|
||||
mock_log):
|
||||
mock_rel_ids.return_value = [1,2]
|
||||
mock_rel_units.return_value = [3,4]
|
||||
mock_rel_get.return_value = '0.0.0.0'
|
||||
mock_config.side_effect = lambda k: True
|
||||
|
||||
percona_utils.get_cluster_hosts()
|
||||
|
||||
mock_rel_get.assert_called_with('hostname', 4, 2)
|
Loading…
Reference in New Issue