[hopem,r=gnuoy]

Fixes unicast ipv6

Closes-Bug: 1461145
This commit is contained in:
Edward Hope-Morley 2015-06-04 14:04:35 +01:00
commit 974177bb78
3 changed files with 145 additions and 16 deletions

View File

@ -16,10 +16,12 @@ from charmhelpers.core.hookenv import (
INFO,
related_units,
relation_ids,
relation_get,
relation_set,
config,
Hooks,
UnregisteredHookError,
local_unit,
)
from charmhelpers.core.host import (
@ -51,9 +53,13 @@ from utils import (
enable_lsb_services,
disable_lsb_services,
disable_upstart_services,
get_ipv6_addr,
)
from charmhelpers.contrib.charmsupport import nrpe
from charmhelpers.contrib.network.ip import (
is_ipv6,
)
hooks = Hooks()
@ -97,6 +103,18 @@ def get_transport():
return val
def ensure_ipv6_requirements(hanode_rid):
# hanode relation needs ipv6 private-address
addr = relation_get(rid=hanode_rid, unit=local_unit(),
attribute='private-address')
log("Current private-address is %s" % (addr))
if not is_ipv6(addr):
addr = get_ipv6_addr()
log("New private-address is %s" % (addr))
relation_set(relation_id=hanode_rid,
**{'private-address': addr})
@hooks.hook()
def config_changed():
if config('prefer-ipv6'):
@ -108,6 +126,10 @@ def config_changed():
enable_lsb_services('pacemaker')
if config('prefer-ipv6'):
for rid in relation_ids('hanode'):
ensure_ipv6_requirements(rid)
if configure_corosync():
pcmk.wait_for_pcmk()
configure_cluster_global()
@ -124,10 +146,17 @@ def upgrade_charm():
update_nrpe_config()
@hooks.hook('ha-relation-joined',
'ha-relation-changed',
'hanode-relation-joined',
@hooks.hook('hanode-relation-joined',
'hanode-relation-changed')
def hanode_relation_changed():
if config('prefer-ipv6'):
ensure_ipv6_requirements(None)
ha_relation_changed()
@hooks.hook('ha-relation-joined',
'ha-relation-changed')
def ha_relation_changed():
# Check that we are related to a principle and that
# it has already provided the required corosync configuration

View File

@ -15,11 +15,11 @@ from charmhelpers.core.hookenv import (
log,
DEBUG,
INFO,
WARNING,
relation_get,
related_units,
relation_ids,
config,
unit_private_ip,
unit_get,
)
from charmhelpers.contrib.openstack.utils import get_host_ip
@ -158,16 +158,6 @@ def get_corosync_id(unit_name):
return off_set + int(unit_name.split('/')[1])
def get_ha_nodes():
ha_units = peer_ips(peer_relation='hanode')
ha_units[local_unit()] = unit_private_ip()
ha_nodes = {}
for unit in ha_units:
corosync_id = get_corosync_id(unit)
ha_nodes[corosync_id] = get_host_ip(ha_units[unit])
return ha_nodes
def nulls(data):
"""Returns keys of values that are null (but not bool)"""
return [k for k in data.iterkeys()
@ -297,9 +287,60 @@ def get_transport():
return val
def get_ipv6_addr():
"""Exclude any ip addresses configured or managed by corosync."""
excludes = []
for rid in relation_ids('ha'):
for unit in related_units(rid):
resources = parse_data(rid, unit, 'resources')
for res in resources.itervalues():
if 'ocf:heartbeat:IPv6addr' in res:
res_params = parse_data(rid, unit, 'resource_params')
res_p = res_params.get(res)
if res_p:
for k, v in res_p.itervalues():
if utils.is_ipv6(v):
log("Excluding '%s' from address list" % v,
level=DEBUG)
excludes.append(v)
return utils.get_ipv6_addr(exc_list=excludes)[0]
def get_ha_nodes():
ha_units = peer_ips(peer_relation='hanode')
ha_nodes = {}
for unit in ha_units:
corosync_id = get_corosync_id(unit)
addr = ha_units[unit]
if config('prefer-ipv6'):
if not utils.is_ipv6(addr):
# Not an error since cluster may still be forming/updating
log("Expected an ipv6 address but got %s" % (addr),
level=WARNING)
ha_nodes[corosync_id] = addr
else:
ha_nodes[corosync_id] = get_host_ip(addr)
corosync_id = get_corosync_id(local_unit())
if config('prefer-ipv6'):
addr = get_ipv6_addr()
else:
addr = get_host_ip(unit_get('private-address'))
ha_nodes[corosync_id] = addr
return ha_nodes
def get_cluster_nodes():
hosts = []
hosts.append(unit_get('private-address'))
if config('prefer-ipv6'):
hosts.append(get_ipv6_addr())
else:
hosts.append(unit_get('private-address'))
for relid in relation_ids('hanode'):
for unit in related_units(relid):
if relation_get('ready', rid=relid, unit=unit):

View File

@ -25,6 +25,7 @@ class UtilsTestCase(unittest.TestCase):
def tearDown(self):
shutil.rmtree(self.tmpdir)
@mock.patch.object(utils, 'get_ha_nodes', lambda *args: {'1': '10.0.0.1'})
@mock.patch.object(utils, 'relation_get')
@mock.patch.object(utils, 'related_units')
@mock.patch.object(utils, 'relation_ids')
@ -47,7 +48,6 @@ class UtilsTestCase(unittest.TestCase):
related_units.return_value = ['unit-machine-0']
relation_get.return_value = 'iface'
utils.get_ha_nodes = mock.MagicMock()
conf = utils.get_corosync_conf()
if enabled:
@ -87,3 +87,62 @@ class UtilsTestCase(unittest.TestCase):
def test_nulls(self):
self.assertEquals(utils.nulls({'a': '', 'b': None, 'c': False}),
['a', 'b'])
@mock.patch.object(utils, 'local_unit', lambda *args: 'hanode/0')
@mock.patch.object(utils, 'get_ipv6_addr')
@mock.patch.object(utils, 'get_host_ip')
@mock.patch.object(utils.utils, 'is_ipv6', lambda *args: None)
@mock.patch.object(utils, 'get_corosync_id', lambda u: "%s-cid" % (u))
@mock.patch.object(utils, 'peer_ips', lambda *args, **kwargs:
{'hanode/1': '10.0.0.2'})
@mock.patch.object(utils, 'unit_get')
@mock.patch.object(utils, 'config')
def test_get_ha_nodes(self, mock_config, mock_unit_get, mock_get_host_ip,
mock_get_ipv6_addr):
mock_get_host_ip.side_effect = lambda host: host
def unit_get(key):
return {'private-address': '10.0.0.1'}.get(key)
mock_unit_get.side_effect = unit_get
def config(key):
return {'prefer-ipv6': False}.get(key)
mock_config.side_effect = config
nodes = utils.get_ha_nodes()
self.assertEqual(nodes, {'hanode/0-cid': '10.0.0.1',
'hanode/1-cid': '10.0.0.2'})
self.assertTrue(mock_get_host_ip.called)
self.assertFalse(mock_get_ipv6_addr.called)
@mock.patch.object(utils, 'local_unit', lambda *args: 'hanode/0')
@mock.patch.object(utils, 'get_ipv6_addr')
@mock.patch.object(utils, 'get_host_ip')
@mock.patch.object(utils.utils, 'is_ipv6')
@mock.patch.object(utils, 'get_corosync_id', lambda u: "%s-cid" % (u))
@mock.patch.object(utils, 'peer_ips', lambda *args, **kwargs:
{'hanode/1': '2001:db8:1::2'})
@mock.patch.object(utils, 'unit_get')
@mock.patch.object(utils, 'config')
def test_get_ha_nodes_ipv6(self, mock_config, mock_unit_get, mock_is_ipv6,
mock_get_host_ip, mock_get_ipv6_addr):
mock_get_ipv6_addr.return_value = '2001:db8:1::1'
mock_get_host_ip.side_effect = lambda host: host
def unit_get(key):
return {'private-address': '10.0.0.1'}.get(key)
mock_unit_get.side_effect = unit_get
def config(key):
return {'prefer-ipv6': True}.get(key)
mock_config.side_effect = config
nodes = utils.get_ha_nodes()
self.assertEqual(nodes, {'hanode/0-cid': '2001:db8:1::1',
'hanode/1-cid': '2001:db8:1::2'})
self.assertFalse(mock_get_host_ip.called)
self.assertTrue(mock_get_ipv6_addr.called)