Merge "Fix kolla_address in IPv6 fully-routed topo case"
This commit is contained in:
commit
00ed275c44
@ -15,16 +15,7 @@
|
|||||||
import jinja2
|
import jinja2
|
||||||
|
|
||||||
from kolla_ansible import exception
|
from kolla_ansible import exception
|
||||||
|
from kolla_ansible.helpers import _call_bool_filter
|
||||||
|
|
||||||
def _call_bool_filter(context, value):
|
|
||||||
"""Pass a value through the 'bool' filter.
|
|
||||||
|
|
||||||
:param context: Jinja2 Context object.
|
|
||||||
:param value: Value to pass through bool filter.
|
|
||||||
:returns: A boolean.
|
|
||||||
"""
|
|
||||||
return context.environment.call_filter("bool", value, context=context)
|
|
||||||
|
|
||||||
|
|
||||||
@jinja2.contextfilter
|
@jinja2.contextfilter
|
||||||
|
21
kolla_ansible/helpers.py
Normal file
21
kolla_ansible/helpers.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
def _call_bool_filter(context, value):
|
||||||
|
"""Pass a value through the 'bool' filter.
|
||||||
|
|
||||||
|
:param context: Jinja2 Context object.
|
||||||
|
:param value: Value to pass through bool filter.
|
||||||
|
:returns: A boolean.
|
||||||
|
"""
|
||||||
|
return context.environment.call_filter("bool", value, context=context)
|
@ -18,6 +18,7 @@ from jinja2.filters import contextfilter
|
|||||||
from jinja2.runtime import Undefined
|
from jinja2.runtime import Undefined
|
||||||
|
|
||||||
from kolla_ansible.exception import FilterError
|
from kolla_ansible.exception import FilterError
|
||||||
|
from kolla_ansible.helpers import _call_bool_filter
|
||||||
|
|
||||||
|
|
||||||
@contextfilter
|
@contextfilter
|
||||||
@ -50,14 +51,15 @@ def kolla_address(context, network_name, hostname=None):
|
|||||||
if isinstance(hostvars, Undefined):
|
if isinstance(hostvars, Undefined):
|
||||||
raise FilterError("'hostvars' variable is unavailable")
|
raise FilterError("'hostvars' variable is unavailable")
|
||||||
|
|
||||||
del context # remove for sanity
|
|
||||||
|
|
||||||
host = hostvars.get(hostname)
|
host = hostvars.get(hostname)
|
||||||
if isinstance(host, Undefined):
|
if isinstance(host, Undefined):
|
||||||
raise FilterError("'{hostname}' not in 'hostvars'"
|
raise FilterError("'{hostname}' not in 'hostvars'"
|
||||||
.format(hostname=hostname))
|
.format(hostname=hostname))
|
||||||
|
|
||||||
del hostvars # remove for sanity (no 'Undefined' beyond this point)
|
del hostvars # remove for clarity (no need for other hosts)
|
||||||
|
|
||||||
|
# NOTE(yoctozepto): variable "host" will *not* return Undefined
|
||||||
|
# same applies to all its children (act like plain dictionary)
|
||||||
|
|
||||||
interface_name = host.get(network_name + '_interface')
|
interface_name = host.get(network_name + '_interface')
|
||||||
if interface_name is None:
|
if interface_name is None:
|
||||||
@ -101,11 +103,27 @@ def kolla_address(context, network_name, hostname=None):
|
|||||||
address = af_interface.get('address')
|
address = af_interface.get('address')
|
||||||
elif address_family == 'ipv6':
|
elif address_family == 'ipv6':
|
||||||
# ipv6 has no concept of a secondary address
|
# ipv6 has no concept of a secondary address
|
||||||
# prefix 128 is the default from keepalived
|
# explicitly exclude the vip addresses
|
||||||
# it needs to be excluded here
|
# to avoid excluding all /128
|
||||||
|
|
||||||
|
haproxy_enabled = host.get('enable_haproxy')
|
||||||
|
if haproxy_enabled is None:
|
||||||
|
raise FilterError("'enable_haproxy' variable is unavailable")
|
||||||
|
haproxy_enabled = _call_bool_filter(context, haproxy_enabled)
|
||||||
|
|
||||||
|
if haproxy_enabled:
|
||||||
|
vip_addresses = [
|
||||||
|
host.get('kolla_internal_vip_address'),
|
||||||
|
host.get('kolla_external_vip_address'),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# no addresses are virtual (kolla-wise)
|
||||||
|
vip_addresses = []
|
||||||
|
|
||||||
global_ipv6_addresses = [x for x in af_interface if
|
global_ipv6_addresses = [x for x in af_interface if
|
||||||
x['scope'] == 'global' and
|
x['scope'] == 'global' and
|
||||||
x['prefix'] != '128']
|
x['address'] not in vip_addresses]
|
||||||
|
|
||||||
if global_ipv6_addresses:
|
if global_ipv6_addresses:
|
||||||
address = global_ipv6_addresses[0]['address']
|
address = global_ipv6_addresses[0]['address']
|
||||||
else:
|
else:
|
||||||
|
23
kolla_ansible/tests/unit/helpers.py
Normal file
23
kolla_ansible/tests/unit/helpers.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
def _to_bool(value):
|
||||||
|
"""Simplified version of the bool filter.
|
||||||
|
|
||||||
|
Avoids having a dependency on Ansible in unit tests.
|
||||||
|
"""
|
||||||
|
if value == 'yes':
|
||||||
|
return True
|
||||||
|
if value == 'no':
|
||||||
|
return False
|
||||||
|
return bool(value)
|
@ -22,6 +22,8 @@ from kolla_ansible.exception import FilterError
|
|||||||
from kolla_ansible.kolla_address import kolla_address
|
from kolla_ansible.kolla_address import kolla_address
|
||||||
from kolla_ansible.put_address_in_context import put_address_in_context
|
from kolla_ansible.put_address_in_context import put_address_in_context
|
||||||
|
|
||||||
|
from kolla_ansible.tests.unit.helpers import _to_bool
|
||||||
|
|
||||||
|
|
||||||
class TestAddressContextFilter(unittest.TestCase):
|
class TestAddressContextFilter(unittest.TestCase):
|
||||||
|
|
||||||
@ -58,6 +60,7 @@ class TestKollaAddressFilter(unittest.TestCase):
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
# Bandit complains about Jinja2 autoescaping without nosec.
|
# Bandit complains about Jinja2 autoescaping without nosec.
|
||||||
self.env = jinja2.Environment() # nosec
|
self.env = jinja2.Environment() # nosec
|
||||||
|
self.env.filters['bool'] = _to_bool
|
||||||
|
|
||||||
def _make_context(self, parent):
|
def _make_context(self, parent):
|
||||||
return self.env.context_class(
|
return self.env.context_class(
|
||||||
@ -97,6 +100,7 @@ class TestKollaAddressFilter(unittest.TestCase):
|
|||||||
'inventory_hostname': 'primary',
|
'inventory_hostname': 'primary',
|
||||||
'hostvars': {
|
'hostvars': {
|
||||||
'primary': {
|
'primary': {
|
||||||
|
'enable_haproxy': 'yes',
|
||||||
'api_address_family': 'ipv6',
|
'api_address_family': 'ipv6',
|
||||||
'api_interface': 'fake-interface',
|
'api_interface': 'fake-interface',
|
||||||
'ansible_fake_interface': {
|
'ansible_fake_interface': {
|
||||||
@ -133,6 +137,7 @@ class TestKollaAddressFilter(unittest.TestCase):
|
|||||||
'inventory_hostname': 'primary',
|
'inventory_hostname': 'primary',
|
||||||
'hostvars': {
|
'hostvars': {
|
||||||
'primary': {
|
'primary': {
|
||||||
|
'enable_haproxy': 'yes',
|
||||||
'api_address_family': 'ipv6',
|
'api_address_family': 'ipv6',
|
||||||
'api_interface': 'fake-interface',
|
'api_interface': 'fake-interface',
|
||||||
'ansible_fake_interface': {
|
'ansible_fake_interface': {
|
||||||
@ -185,3 +190,109 @@ class TestKollaAddressFilter(unittest.TestCase):
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
self.assertRaises(FilterError, kolla_address, context, 'api')
|
self.assertRaises(FilterError, kolla_address, context, 'api')
|
||||||
|
|
||||||
|
def test_valid_ipv6_config_prefix_128(self):
|
||||||
|
addr = 'fd::'
|
||||||
|
context = self._make_context({
|
||||||
|
'inventory_hostname': 'primary',
|
||||||
|
'hostvars': {
|
||||||
|
'primary': {
|
||||||
|
'enable_haproxy': 'yes',
|
||||||
|
'api_address_family': 'ipv6',
|
||||||
|
'api_interface': 'fake-interface',
|
||||||
|
'ansible_fake_interface': {
|
||||||
|
'ipv6': [
|
||||||
|
{
|
||||||
|
'address': addr,
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.assertEqual(addr, kolla_address(context, 'api'))
|
||||||
|
|
||||||
|
def test_valid_ipv6_config_ignore_internal_vip_address(self):
|
||||||
|
addr = 'fd::'
|
||||||
|
context = self._make_context({
|
||||||
|
'inventory_hostname': 'primary',
|
||||||
|
'hostvars': {
|
||||||
|
'primary': {
|
||||||
|
'enable_haproxy': 'yes',
|
||||||
|
'kolla_internal_vip_address': addr + '1',
|
||||||
|
'api_address_family': 'ipv6',
|
||||||
|
'api_interface': 'fake-interface',
|
||||||
|
'ansible_fake_interface': {
|
||||||
|
'ipv6': [
|
||||||
|
{
|
||||||
|
'address': addr + '1',
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'address': addr,
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.assertEqual(addr, kolla_address(context, 'api'))
|
||||||
|
|
||||||
|
def test_valid_ipv6_config_ignore_external_vip_address(self):
|
||||||
|
addr = 'fd::'
|
||||||
|
context = self._make_context({
|
||||||
|
'inventory_hostname': 'primary',
|
||||||
|
'hostvars': {
|
||||||
|
'primary': {
|
||||||
|
'enable_haproxy': 'yes',
|
||||||
|
'kolla_external_vip_address': addr + '1',
|
||||||
|
'api_address_family': 'ipv6',
|
||||||
|
'api_interface': 'fake-interface',
|
||||||
|
'ansible_fake_interface': {
|
||||||
|
'ipv6': [
|
||||||
|
{
|
||||||
|
'address': addr + '1',
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'address': addr,
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.assertEqual(addr, kolla_address(context, 'api'))
|
||||||
|
|
||||||
|
def test_valid_ipv6_config_do_not_ignore_any_vip_address(self):
|
||||||
|
addr = 'fd::'
|
||||||
|
context = self._make_context({
|
||||||
|
'inventory_hostname': 'primary',
|
||||||
|
'hostvars': {
|
||||||
|
'primary': {
|
||||||
|
'enable_haproxy': 'no',
|
||||||
|
'kolla_external_vip_address': addr,
|
||||||
|
'kolla_internal_vip_address': addr,
|
||||||
|
'api_address_family': 'ipv6',
|
||||||
|
'api_interface': 'fake-interface',
|
||||||
|
'ansible_fake_interface': {
|
||||||
|
'ipv6': [
|
||||||
|
{
|
||||||
|
'address': addr,
|
||||||
|
'scope': 'global',
|
||||||
|
'prefix': 128,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
self.assertEqual(addr, kolla_address(context, 'api'))
|
||||||
|
@ -20,17 +20,7 @@ import jinja2
|
|||||||
from kolla_ansible import exception
|
from kolla_ansible import exception
|
||||||
from kolla_ansible import filters
|
from kolla_ansible import filters
|
||||||
|
|
||||||
|
from kolla_ansible.tests.unit.helpers import _to_bool
|
||||||
def _to_bool(value):
|
|
||||||
"""Simplified version of the bool filter.
|
|
||||||
|
|
||||||
Avoids having a dependency on Ansible in unit tests.
|
|
||||||
"""
|
|
||||||
if value == 'yes':
|
|
||||||
return True
|
|
||||||
if value == 'no':
|
|
||||||
return False
|
|
||||||
return bool(value)
|
|
||||||
|
|
||||||
|
|
||||||
class TestFilters(unittest.TestCase):
|
class TestFilters(unittest.TestCase):
|
||||||
|
6
releasenotes/notes/bug-1848941-7e192be1885af513.yaml
Normal file
6
releasenotes/notes/bug-1848941-7e192be1885af513.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
IPv6 fully-routed topology (/128 addressing) is now allowed
|
||||||
|
(where applicable).
|
||||||
|
`LP#1848941 <https://launchpad.net/bugs/1848941>`__
|
Loading…
Reference in New Issue
Block a user