Merge "Calculate undercloud ctlplane DHCP allocation pools"
This commit is contained in:
commit
7fe40c3265
@ -0,0 +1,33 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
The ``dhcp_start`` and ``dhcp_end`` options are now optional for subnet
|
||||
definitions in the Undercloud configuration (``undercloud.conf``).
|
||||
The the allocation_pools are calculated by removing the ``local_ip``,
|
||||
``gateway``, ``undercloud_admin_host``, ``undercloud_public_host`` and
|
||||
``inspection_iprange`` from the subnets full IP range. Allocation pools for
|
||||
all remaining ranges will be configured. Additionally the new option
|
||||
``dhcp_exlcude`` can be used to exclude additional IP addresses and/or
|
||||
IP address ranges, for example to exclude ``172.20.0.105`` and the range
|
||||
``172.20.0.210-172.20.0.219``::
|
||||
|
||||
dhcp_exclude = 172.20.0.105,172.20.0.210-172.20.0.219
|
||||
|
||||
* When ``dhcp_start`` is defined any addresses prior to this address is
|
||||
also removed from the allocation pools.
|
||||
* When ``dhcp_end`` is defined any addresses after this address is also
|
||||
removed from the allocation pools.
|
||||
|
||||
.. Note:: If the default cidr (``192.168.24.0/24``) is used for the local
|
||||
subnet the ``dhcp_start`` and ``dhcp_end`` cannot simply be
|
||||
removed to utilize the full address space of the subnet. This due
|
||||
to the default values of ``dhcp_start`` and ``dhcp_end``.
|
||||
- |
|
||||
It is now possible to configure non-contiguous allocation pools for the
|
||||
Undercloud ctlplane subnets. The ``dhcp_start`` and ``dhcp_end`` options
|
||||
have been extended to allow a list of start and end address pairs. For
|
||||
example to create allocation pools ``172.20.0.100-172.20.0.150`` and
|
||||
``172.20.0.200-172.20.0.250``::
|
||||
|
||||
dhcp_start = 172.20.0.100,172.20.0.200
|
||||
dhcp_end = 172.20.0.150,172.20.0.250
|
@ -27,6 +27,27 @@ CONF = cfg.CONF
|
||||
# Control plane network name
|
||||
SUBNETS_DEFAULT = ['ctlplane-subnet']
|
||||
|
||||
CIDR_HELP_STR = _(
|
||||
'Network CIDR for the Neutron-managed subnet for Overcloud instances.')
|
||||
DHCP_START_HELP_STR = _(
|
||||
'Start of DHCP allocation range for PXE and DHCP of Overcloud instances '
|
||||
'on this network.')
|
||||
DHCP_END_HELP_STR = _(
|
||||
'End of DHCP allocation range for PXE and DHCP of Overcloud instances on '
|
||||
'this network.')
|
||||
DHCP_EXCLUDE_HELP_STR = _(
|
||||
'List of IP addresses or IP ranges to exclude from the subnets allocation '
|
||||
'pool. Example: 192.168.24.50,192.168.24.80-192.168.24.90')
|
||||
INSPECTION_IPRANGE_HELP_STR = _(
|
||||
'Temporary IP range that will be given to nodes on this network during '
|
||||
'the inspection process. Should not overlap with the range defined by '
|
||||
'dhcp_start and dhcp_end, but should be in the same ip subnet.')
|
||||
GATEWAY_HELP_STR = _(
|
||||
'Network gateway for the Neutron-managed network for Overcloud instances '
|
||||
'on this network.')
|
||||
MASQUERADE_HELP_STR = _(
|
||||
'The network will be masqueraded for external access.')
|
||||
|
||||
# Deprecated options
|
||||
_deprecated_opt_network_gateway = [cfg.DeprecatedOpt(
|
||||
'network_gateway', group='DEFAULT')]
|
||||
@ -315,46 +336,57 @@ class UndercloudConfig(StandaloneConfig):
|
||||
_service_opts = self.get_undercloud_service_opts()
|
||||
return self.sort_opts(_base_opts + _service_opts)
|
||||
|
||||
def get_subnet_opts(self):
|
||||
def get_local_subnet_opts(self):
|
||||
_subnets_opts = [
|
||||
cfg.StrOpt('cidr',
|
||||
default='192.168.24.0/24',
|
||||
default=constants.CTLPLANE_CIDR_DEFAULT,
|
||||
deprecated_opts=_deprecated_opt_network_cidr,
|
||||
help=_(
|
||||
'Network CIDR for the Neutron-managed subnet for '
|
||||
'Overcloud instances.')),
|
||||
cfg.StrOpt('dhcp_start',
|
||||
default='192.168.24.5',
|
||||
help=CIDR_HELP_STR),
|
||||
cfg.ListOpt('dhcp_start',
|
||||
default=constants.CTLPLANE_DHCP_START_DEFAULT,
|
||||
deprecated_opts=_deprecated_opt_dhcp_start,
|
||||
help=_(
|
||||
'Start of DHCP allocation range for PXE and DHCP '
|
||||
'of Overcloud instances on this network.')),
|
||||
cfg.StrOpt('dhcp_end',
|
||||
default='192.168.24.24',
|
||||
help=DHCP_START_HELP_STR),
|
||||
cfg.ListOpt('dhcp_end',
|
||||
default=constants.CTLPLANE_DHCP_END_DEFAULT,
|
||||
deprecated_opts=_deprecated_opt_dhcp_end,
|
||||
help=_('End of DHCP allocation range for PXE and DHCP '
|
||||
'of Overcloud instances on this network.')),
|
||||
help=DHCP_END_HELP_STR),
|
||||
cfg.ListOpt('dhcp_exclude',
|
||||
default=[],
|
||||
help=DHCP_EXCLUDE_HELP_STR),
|
||||
cfg.StrOpt('inspection_iprange',
|
||||
default='192.168.24.100,192.168.24.120',
|
||||
default=constants.CTLPLANE_INSPECTION_IPRANGE_DEFAULT,
|
||||
deprecated_opts=_deprecated_opt_inspection_iprange,
|
||||
help=_(
|
||||
'Temporary IP range that will be given to nodes on '
|
||||
'this network during the inspection process. '
|
||||
'Should not overlap with the range defined by '
|
||||
'dhcp_start and dhcp_end, but should be in the '
|
||||
'same ip subnet.'
|
||||
)),
|
||||
help=INSPECTION_IPRANGE_HELP_STR),
|
||||
cfg.StrOpt('gateway',
|
||||
default='192.168.24.1',
|
||||
default=constants.CTLPLANE_GATEWAY_DEFAULT,
|
||||
deprecated_opts=_deprecated_opt_network_gateway,
|
||||
help=_(
|
||||
'Network gateway for the Neutron-managed network '
|
||||
'for Overcloud instances on this network.')),
|
||||
help=GATEWAY_HELP_STR),
|
||||
cfg.BoolOpt('masquerade',
|
||||
default=False,
|
||||
help=_(
|
||||
'The network will be masqueraded for external '
|
||||
'access.')),
|
||||
help=MASQUERADE_HELP_STR),
|
||||
]
|
||||
return self.sort_opts(_subnets_opts)
|
||||
|
||||
def get_remote_subnet_opts(self):
|
||||
_subnets_opts = [
|
||||
cfg.StrOpt('cidr',
|
||||
help=CIDR_HELP_STR),
|
||||
cfg.ListOpt('dhcp_start',
|
||||
default=[],
|
||||
help=DHCP_START_HELP_STR),
|
||||
cfg.ListOpt('dhcp_end',
|
||||
default=[],
|
||||
help=DHCP_END_HELP_STR),
|
||||
cfg.ListOpt('dhcp_exclude',
|
||||
default=[],
|
||||
help=DHCP_EXCLUDE_HELP_STR),
|
||||
cfg.StrOpt('inspection_iprange',
|
||||
help=INSPECTION_IPRANGE_HELP_STR),
|
||||
cfg.StrOpt('gateway',
|
||||
help=GATEWAY_HELP_STR),
|
||||
cfg.BoolOpt('masquerade',
|
||||
default=False,
|
||||
help=MASQUERADE_HELP_STR),
|
||||
]
|
||||
return self.sort_opts(_subnets_opts)
|
||||
|
||||
@ -364,7 +396,8 @@ def list_opts():
|
||||
config = UndercloudConfig()
|
||||
_opts = config.get_opts()
|
||||
return [(None, copy.deepcopy(_opts)),
|
||||
(SUBNETS_DEFAULT[0], copy.deepcopy(config.get_subnet_opts()))]
|
||||
(SUBNETS_DEFAULT[0],
|
||||
copy.deepcopy(config.get_local_subnet_opts()))]
|
||||
|
||||
|
||||
def load_global_config():
|
||||
|
@ -82,3 +82,10 @@ ANSIBLE_VALIDATION_DIR = '/usr/share/openstack-tripleo-validations/validations'
|
||||
|
||||
# The path to the local CA certificate installed on the undercloud
|
||||
LOCAL_CACERT_PATH = '/etc/pki/ca-trust/source/anchors/cm-local-ca.pem'
|
||||
|
||||
# ctlplane network defaults
|
||||
CTLPLANE_CIDR_DEFAULT = '192.168.24.0/24'
|
||||
CTLPLANE_DHCP_START_DEFAULT = ['192.168.24.5']
|
||||
CTLPLANE_DHCP_END_DEFAULT = ['192.168.24.24']
|
||||
CTLPLANE_INSPECTION_IPRANGE_DEFAULT = '192.168.24.100,192.168.24.120'
|
||||
CTLPLANE_GATEWAY_DEFAULT = '192.168.24.1'
|
||||
|
@ -138,13 +138,18 @@ class TestUndercloudConfig(base.TestCase):
|
||||
self.assertEqual(expected, [x.name for x in ret])
|
||||
|
||||
def test_get_subnet_opts(self):
|
||||
ret = self.config.get_subnet_opts()
|
||||
expected = ['cidr',
|
||||
'dhcp_end',
|
||||
'dhcp_exclude',
|
||||
'dhcp_start',
|
||||
'gateway',
|
||||
'inspection_iprange',
|
||||
'masquerade']
|
||||
|
||||
ret = self.config.get_local_subnet_opts()
|
||||
self.assertEqual(expected, [x.name for x in ret])
|
||||
|
||||
ret = self.config.get_remote_subnet_opts()
|
||||
self.assertEqual(expected, [x.name for x in ret])
|
||||
|
||||
def test_get_undercloud_service_opts(self):
|
||||
|
@ -123,8 +123,9 @@ class TestNetworkSettings(base.TestCase):
|
||||
self.grp0 = cfg.OptGroup(name='ctlplane-subnet',
|
||||
title='ctlplane-subnet')
|
||||
self.opts = [cfg.StrOpt('cidr'),
|
||||
cfg.StrOpt('dhcp_start'),
|
||||
cfg.StrOpt('dhcp_end'),
|
||||
cfg.ListOpt('dhcp_start'),
|
||||
cfg.ListOpt('dhcp_end'),
|
||||
cfg.ListOpt('dhcp_exclude'),
|
||||
cfg.StrOpt('inspection_iprange'),
|
||||
cfg.StrOpt('gateway'),
|
||||
cfg.BoolOpt('masquerade')]
|
||||
@ -134,6 +135,7 @@ class TestNetworkSettings(base.TestCase):
|
||||
self.conf.config(cidr='192.168.24.0/24',
|
||||
dhcp_start='192.168.24.5',
|
||||
dhcp_end='192.168.24.24',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.24.100,192.168.24.120',
|
||||
gateway='192.168.24.1',
|
||||
masquerade=False,
|
||||
@ -153,12 +155,180 @@ class TestNetworkSettings(base.TestCase):
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.5', 'end': '192.168.24.24'}],
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'}}}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_start_end_all_addresses(self):
|
||||
self.conf.config(dhcp_start='192.168.24.0',
|
||||
dhcp_end='192.168.24.255',
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.4', 'end': '192.168.24.99'},
|
||||
{'start': '192.168.24.121', 'end': '192.168.24.254'}],
|
||||
'DhcpRangeEnd': '192.168.24.255',
|
||||
'DhcpRangeStart': '192.168.24.0',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'}}}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_ignore_dhcp_start_end_if_default_but_cidr_not_default(self):
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
inspection_iprange='192.168.10.100,192.168.10.120',
|
||||
gateway='192.168.10.1',
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.10.1',
|
||||
'ip_range': '192.168.10.100,192.168.10.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.2', 'end': '192.168.10.99'},
|
||||
{'start': '192.168.10.121', 'end': '192.168.10.254'}],
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.1'}}}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_dhcp_exclude(self):
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
inspection_iprange='192.168.10.100,192.168.10.120',
|
||||
gateway='192.168.10.1',
|
||||
dhcp_exclude=['192.168.10.50',
|
||||
'192.168.10.80-192.168.10.89'],
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.10.1',
|
||||
'ip_range': '192.168.10.100,192.168.10.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.2', 'end': '192.168.10.49'},
|
||||
{'start': '192.168.10.51', 'end': '192.168.10.79'},
|
||||
{'start': '192.168.10.90', 'end': '192.168.10.99'},
|
||||
{'start': '192.168.10.121', 'end': '192.168.10.254'}],
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.1'}}}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_no_dhcp_start_no_dhcp_end(self):
|
||||
self.conf.config(dhcp_start=[],
|
||||
dhcp_end=[],
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.4', 'end': '192.168.24.99'},
|
||||
{'start': '192.168.24.121', 'end': '192.168.24.254'}],
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'}}}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_dhcp_start_no_dhcp_end(self):
|
||||
self.conf.config(dhcp_start='192.168.24.10',
|
||||
dhcp_end=[],
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.10', 'end': '192.168.24.99'},
|
||||
{'start': '192.168.24.121', 'end': '192.168.24.254'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeStart': '192.168.24.10',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'}}
|
||||
}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_dhcp_end_no_dhcp_start(self):
|
||||
self.conf.config(dhcp_start=[],
|
||||
dhcp_end='192.168.24.220',
|
||||
group='ctlplane-subnet')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'}],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.4', 'end': '192.168.24.99'},
|
||||
{'start': '192.168.24.121', 'end': '192.168.24.220'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeEnd': '192.168.24.220',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'}}
|
||||
}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_routed_network(self):
|
||||
self.conf.config(subnets=['ctlplane-subnet', 'subnet1', 'subnet2'])
|
||||
self.conf.register_opts(self.opts, group=self.grp1)
|
||||
@ -168,6 +338,7 @@ class TestNetworkSettings(base.TestCase):
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
dhcp_start='192.168.10.10',
|
||||
dhcp_end='192.168.10.99',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.10.100,192.168.10.189',
|
||||
gateway='192.168.10.254',
|
||||
masquerade=True,
|
||||
@ -175,6 +346,7 @@ class TestNetworkSettings(base.TestCase):
|
||||
self.conf.config(cidr='192.168.20.0/24',
|
||||
dhcp_start='192.168.20.10',
|
||||
dhcp_end='192.168.20.99',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.20.100,192.168.20.189',
|
||||
gateway='192.168.20.254',
|
||||
masquerade=True,
|
||||
@ -213,16 +385,25 @@ class TestNetworkSettings(base.TestCase):
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
# The ctlplane-subnet subnet have defaults
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.5', 'end': '192.168.24.24'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'},
|
||||
'subnet1': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.10', 'end': '192.168.10.99'}],
|
||||
'DhcpRangeEnd': '192.168.10.99',
|
||||
'DhcpRangeStart': '192.168.10.10',
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.254'},
|
||||
'subnet2': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.20.10', 'end': '192.168.20.99'}],
|
||||
'DhcpRangeEnd': '192.168.20.99',
|
||||
'DhcpRangeStart': '192.168.20.10',
|
||||
'NetworkCidr': '192.168.20.0/24',
|
||||
@ -238,12 +419,14 @@ class TestNetworkSettings(base.TestCase):
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
dhcp_start='192.168.10.10',
|
||||
dhcp_end='192.168.10.99',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.10.100,192.168.10.189',
|
||||
gateway='192.168.10.254',
|
||||
group='subnet1')
|
||||
self.conf.config(cidr='192.168.20.0/24',
|
||||
dhcp_start='192.168.20.10',
|
||||
dhcp_end='192.168.20.99',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.20.100,192.168.20.189',
|
||||
gateway='192.168.20.254',
|
||||
group='subnet2')
|
||||
@ -272,16 +455,25 @@ class TestNetworkSettings(base.TestCase):
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
# The ctlplane-subnet subnet have defaults
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.5', 'end': '192.168.24.24'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'},
|
||||
'subnet1': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.10', 'end': '192.168.10.99'}],
|
||||
'DhcpRangeEnd': '192.168.10.99',
|
||||
'DhcpRangeStart': '192.168.10.10',
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.254'},
|
||||
'subnet2': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.20.10', 'end': '192.168.20.99'}],
|
||||
'DhcpRangeEnd': '192.168.20.99',
|
||||
'DhcpRangeStart': '192.168.20.10',
|
||||
'NetworkCidr': '192.168.20.0/24',
|
||||
@ -290,6 +482,102 @@ class TestNetworkSettings(base.TestCase):
|
||||
}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_no_allocation_pool_on_remote_network(self):
|
||||
self.conf.config(subnets=['ctlplane-subnet', 'subnet1'])
|
||||
self.conf.register_opts(self.opts, group=self.grp1)
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.10.200,192.168.10.254',
|
||||
gateway='192.168.10.254',
|
||||
masquerade=False,
|
||||
group='subnet1')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [
|
||||
{'ip_netmask': '192.168.10.0/24', 'next_hop': '192.168.24.1'}],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'},
|
||||
{'gateway': '192.168.10.254',
|
||||
'ip_range': '192.168.10.200,192.168.10.254',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'subnet1'},
|
||||
],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
# The ctlplane-subnet subnet have defaults
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.5', 'end': '192.168.24.24'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'},
|
||||
'subnet1': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.1', 'end': '192.168.10.199'}],
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.254'}
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
def test_no_allocation_pool_on_remote_network_three_pools(self):
|
||||
self.conf.config(subnets=['ctlplane-subnet', 'subnet1'])
|
||||
self.conf.register_opts(self.opts, group=self.grp1)
|
||||
self.conf.config(cidr='192.168.10.0/24',
|
||||
dhcp_exclude=[],
|
||||
inspection_iprange='192.168.10.100,192.168.10.199',
|
||||
gateway='192.168.10.222',
|
||||
masquerade=False,
|
||||
group='subnet1')
|
||||
env = {}
|
||||
undercloud_config._process_network_args(env)
|
||||
expected = {
|
||||
'ControlPlaneStaticRoutes': [
|
||||
{'ip_netmask': '192.168.10.0/24', 'next_hop': '192.168.24.1'}],
|
||||
'DnsServers': '',
|
||||
'IronicInspectorSubnets': [
|
||||
{'gateway': '192.168.24.1',
|
||||
'ip_range': '192.168.24.100,192.168.24.120',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'ctlplane-subnet'},
|
||||
{'gateway': '192.168.10.222',
|
||||
'ip_range': '192.168.10.100,192.168.10.199',
|
||||
'netmask': '255.255.255.0',
|
||||
'tag': 'subnet1'},
|
||||
],
|
||||
'MasqueradeNetworks': {},
|
||||
'UndercloudCtlplaneSubnets': {
|
||||
# The ctlplane-subnet subnet have defaults
|
||||
'ctlplane-subnet': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.24.5', 'end': '192.168.24.24'}],
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd
|
||||
# once change: Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is
|
||||
# merged and THT uses AllocationPools.
|
||||
'DhcpRangeEnd': '192.168.24.24',
|
||||
'DhcpRangeStart': '192.168.24.5',
|
||||
'NetworkCidr': '192.168.24.0/24',
|
||||
'NetworkGateway': '192.168.24.1'},
|
||||
'subnet1': {
|
||||
'AllocationPools': [
|
||||
{'start': '192.168.10.1', 'end': '192.168.10.99'},
|
||||
{'start': '192.168.10.200', 'end': '192.168.10.221'},
|
||||
{'start': '192.168.10.223', 'end': '192.168.10.254'}],
|
||||
'NetworkCidr': '192.168.10.0/24',
|
||||
'NetworkGateway': '192.168.10.222'}
|
||||
}
|
||||
}
|
||||
self.assertEqual(expected, env)
|
||||
|
||||
|
||||
class TestTLSSettings(base.TestCase):
|
||||
def test_public_host_with_ip_should_give_ip_endpoint_environment(self):
|
||||
|
@ -199,6 +199,7 @@ class TestUndercloudInstall(TestPluginV1):
|
||||
self.conf.config(local_mtu='1234')
|
||||
self.conf.config(undercloud_nameservers=['8.8.8.8', '8.8.4.4'])
|
||||
self.conf.config(subnets='foo')
|
||||
self.conf.config(local_subnet='foo')
|
||||
mock_masq.return_value = {'1.1.1.1/11': ['2.2.2.2/22']}
|
||||
mock_sroutes.return_value = {'ip_netmask': '1.1.1.1/11',
|
||||
'next_hop': '1.1.1.1'}
|
||||
|
@ -77,8 +77,6 @@ PARAMETER_MAPPING = {
|
||||
SUBNET_PARAMETER_MAPPING = {
|
||||
'cidr': 'NetworkCidr',
|
||||
'gateway': 'NetworkGateway',
|
||||
'dhcp_start': 'DhcpRangeStart',
|
||||
'dhcp_end': 'DhcpRangeEnd',
|
||||
}
|
||||
|
||||
THT_HOME = os.environ.get('THT_HOME',
|
||||
@ -108,7 +106,10 @@ load_global_config()
|
||||
def _load_subnets_config_groups():
|
||||
for group in CONF.subnets:
|
||||
g = cfg.OptGroup(name=group, title=group)
|
||||
CONF.register_opts(config.get_subnet_opts(), group=g)
|
||||
if group == CONF.local_subnet:
|
||||
CONF.register_opts(config.get_local_subnet_opts(), group=g)
|
||||
else:
|
||||
CONF.register_opts(config.get_remote_subnet_opts(), group=g)
|
||||
|
||||
LOG = logging.getLogger(__name__ + ".undercloud_config")
|
||||
|
||||
@ -248,6 +249,62 @@ def _generate_masquerade_networks():
|
||||
return masqurade_networks
|
||||
|
||||
|
||||
def _calculate_allocation_pools(subnet):
|
||||
"""Calculate subnet allocation pools
|
||||
|
||||
Remove the gateway address, the inspection IP range and the undercloud IP's
|
||||
from the subnets full IP range and return all remaining address ranges as
|
||||
allocation pools. If dhcp_start and/or dhcp_end is defined, also remove
|
||||
addresses before dhcp_start and addresses after dhcp_end.
|
||||
"""
|
||||
ip_network = netaddr.IPNetwork(subnet.cidr)
|
||||
# NOTE(hjensas): Ignore the default dhcp_start and dhcp_end if cidr is not
|
||||
# the default as well. I.e allow not specifying dhcp_start and dhcp_end.
|
||||
if (subnet.cidr != constants.CTLPLANE_CIDR_DEFAULT
|
||||
and subnet.dhcp_start == constants.CTLPLANE_DHCP_START_DEFAULT
|
||||
and subnet.dhcp_end == constants.CTLPLANE_DHCP_END_DEFAULT):
|
||||
subnet.dhcp_start, subnet.dhcp_end = None, None
|
||||
if subnet.dhcp_start and subnet.dhcp_end:
|
||||
ip_set = netaddr.IPSet()
|
||||
for a, b in zip(subnet.dhcp_start, subnet.dhcp_end):
|
||||
ip_set.add(netaddr.IPRange(netaddr.IPAddress(a),
|
||||
netaddr.IPAddress(b)))
|
||||
else:
|
||||
ip_set = netaddr.IPSet(ip_network)
|
||||
# Remove addresses before dhcp_start if defined
|
||||
if subnet.dhcp_start:
|
||||
a = netaddr.IPAddress(ip_network.first)
|
||||
b = netaddr.IPAddress(subnet.dhcp_start[0]) - 1
|
||||
ip_set.remove(netaddr.IPRange(a, b))
|
||||
# Remove addresses after dhcp_end if defined
|
||||
if subnet.dhcp_end:
|
||||
a = netaddr.IPAddress(subnet.dhcp_end[0]) + 1
|
||||
b = netaddr.IPAddress(ip_network.last)
|
||||
ip_set.remove(netaddr.IPRange(a, b))
|
||||
# Remove network address and broadcast address
|
||||
ip_set.remove(ip_network.first)
|
||||
ip_set.remove(ip_network.last)
|
||||
# Remove gateway, local_ip, admin_host and public_host addresses
|
||||
ip_set.remove(netaddr.IPAddress(subnet.get('gateway')))
|
||||
ip_set.remove(netaddr.IPNetwork(CONF.local_ip).ip)
|
||||
ip_set.remove(netaddr.IPNetwork(CONF.undercloud_admin_host))
|
||||
ip_set.remove(netaddr.IPNetwork(CONF.undercloud_public_host))
|
||||
# Remove addresses in the inspection_iprange
|
||||
inspect_start, inspect_end = subnet.get('inspection_iprange').split(',')
|
||||
ip_set.remove(netaddr.IPRange(inspect_start, inspect_end))
|
||||
# Remove dhcp_exclude addresses and ip ranges
|
||||
for exclude in subnet.dhcp_exclude:
|
||||
if '-' in exclude:
|
||||
exclude_start, exclude_end = exclude.split('-')
|
||||
ip_set.remove(netaddr.IPRange(exclude_start, exclude_end))
|
||||
else:
|
||||
ip_set.remove(netaddr.IPAddress(exclude))
|
||||
|
||||
return [{'start': netaddr.IPAddress(ip_range.first).format(),
|
||||
'end': netaddr.IPAddress(ip_range.last).format()}
|
||||
for ip_range in list(ip_set.iter_ipranges())]
|
||||
|
||||
|
||||
def _process_network_args(env):
|
||||
"""Populate the environment with network configuration."""
|
||||
|
||||
@ -256,8 +313,20 @@ def _process_network_args(env):
|
||||
env['UndercloudCtlplaneSubnets'] = {}
|
||||
for subnet in CONF.subnets:
|
||||
s = CONF.get(subnet)
|
||||
env['UndercloudCtlplaneSubnets'][subnet] = {}
|
||||
env['UndercloudCtlplaneSubnets'][subnet] = {
|
||||
'AllocationPools': _calculate_allocation_pools(s)
|
||||
}
|
||||
# TODO(hjensas): Remove DhcpRangeStart and DhcpRangeEnd once change:
|
||||
# Ifdf3e9d22766c1b5ede151979b93754a3d244cc3 is merged and THT uses
|
||||
# AllocationPools.
|
||||
if s.get('dhcp_start'):
|
||||
env['UndercloudCtlplaneSubnets'][subnet].update(
|
||||
{'DhcpRangeStart': s.get('dhcp_start')[0]})
|
||||
if s.get('dhcp_end'):
|
||||
env['UndercloudCtlplaneSubnets'][subnet].update(
|
||||
{'DhcpRangeEnd': s.get('dhcp_end')[0]})
|
||||
for param_key, param_value in SUBNET_PARAMETER_MAPPING.items():
|
||||
if param_value:
|
||||
env['UndercloudCtlplaneSubnets'][subnet].update(
|
||||
{param_value: s[param_key]})
|
||||
env['MasqueradeNetworks'] = _generate_masquerade_networks()
|
||||
|
@ -288,8 +288,15 @@ def _validate_in_cidr(subnet_props, subnet_name):
|
||||
raise FailedValidation(message)
|
||||
|
||||
validate_addr_in_cidr(subnet_props.gateway, 'gateway')
|
||||
validate_addr_in_cidr(subnet_props.dhcp_start, 'dhcp_start')
|
||||
validate_addr_in_cidr(subnet_props.dhcp_end, 'dhcp_end')
|
||||
# NOTE(hjensas): Ignore the default dhcp_start and dhcp_end if cidr is not
|
||||
# the default as well. I.e allow not specifying dhcp_start and dhcp_end.
|
||||
if not (subnet_props.cidr != constants.CTLPLANE_CIDR_DEFAULT and
|
||||
subnet_props.dhcp_start == constants.CTLPLANE_DHCP_START_DEFAULT
|
||||
and subnet_props.dhcp_end == constants.CTLPLANE_DHCP_END_DEFAULT):
|
||||
for start in subnet_props.dhcp_start:
|
||||
validate_addr_in_cidr(start, 'dhcp_start')
|
||||
for end in subnet_props.dhcp_end:
|
||||
validate_addr_in_cidr(end, 'dhcp_end')
|
||||
if subnet_name == CONF.local_subnet:
|
||||
validate_addr_in_cidr(str(netaddr.IPNetwork(CONF.local_ip).ip),
|
||||
'local_ip')
|
||||
@ -308,9 +315,21 @@ def _validate_in_cidr(subnet_props, subnet_name):
|
||||
require_ip=False)
|
||||
|
||||
|
||||
def _validate_dhcp_range(subnet_props):
|
||||
start = netaddr.IPAddress(subnet_props.dhcp_start)
|
||||
end = netaddr.IPAddress(subnet_props.dhcp_end)
|
||||
def _validate_dhcp_range(subnet_props, subnet_name):
|
||||
len_dhcp_start = len(subnet_props.dhcp_start)
|
||||
len_dhcp_end = len(subnet_props.dhcp_end)
|
||||
if (len_dhcp_start > 1 or len_dhcp_end > 1 and
|
||||
len_dhcp_start != len_dhcp_end):
|
||||
message = (_('Number of elements in dhcp_start and dhcp_end must be '
|
||||
'identical. Subnet "{0}" have "{1}" dhcp_start elements '
|
||||
'and "{2}" dhcp_end elements.').format(subnet_name,
|
||||
len_dhcp_start,
|
||||
len_dhcp_end))
|
||||
LOG.error(message)
|
||||
raise FailedValidation(message)
|
||||
for a, b in zip(subnet_props.dhcp_start, subnet_props.dhcp_end):
|
||||
start = netaddr.IPAddress(a)
|
||||
end = netaddr.IPAddress(b)
|
||||
if start >= end:
|
||||
message = (_('Invalid dhcp range specified, dhcp_start "{0}" does '
|
||||
'not come before dhcp_end "{1}"').format(start, end))
|
||||
@ -328,23 +347,6 @@ def _validate_inspection_range(subnet_props):
|
||||
raise FailedValidation(message)
|
||||
|
||||
|
||||
def _validate_no_overlap(subnet_props):
|
||||
"""Validate the provisioning and inspection ip ranges do not overlap"""
|
||||
dhcp_set = netaddr.IPSet(netaddr.IPRange(subnet_props.dhcp_start,
|
||||
subnet_props.dhcp_end))
|
||||
inspection_set = netaddr.IPSet(netaddr.IPRange(
|
||||
subnet_props.inspection_iprange.split(',')[0],
|
||||
subnet_props.inspection_iprange.split(',')[1]))
|
||||
if dhcp_set.intersection(inspection_set):
|
||||
message = (_('Inspection DHCP range "{0}-{1} overlaps provisioning '
|
||||
'DHCP range "{2}-{3}".') %
|
||||
(subnet_props.inspection_iprange.split(',')[0],
|
||||
subnet_props.inspection_iprange.split(',')[1],
|
||||
subnet_props.dhcp_start, subnet_props.dhcp_end))
|
||||
LOG.error(message)
|
||||
raise FailedValidation(message)
|
||||
|
||||
|
||||
def _validate_interface_exists():
|
||||
"""Validate the provided local interface exists"""
|
||||
if (not CONF.net_config_override
|
||||
@ -549,11 +551,9 @@ def check(verbose_level, upgrade=False):
|
||||
_checking_status('Subnet "%s" is in CIDR' % subnet)
|
||||
_validate_in_cidr(s, subnet)
|
||||
_checking_status('DHCP range is in subnet "%s"' % subnet)
|
||||
_validate_dhcp_range(s)
|
||||
_validate_dhcp_range(s, subnet)
|
||||
_checking_status('Inspection range for subnet "%s"' % subnet)
|
||||
_validate_inspection_range(s)
|
||||
_checking_status('Subnet "%s" has no overlap' % subnet)
|
||||
_validate_no_overlap(s)
|
||||
_checking_status('IP addresses')
|
||||
_validate_ips()
|
||||
_checking_status('Network interfaces')
|
||||
|
Loading…
Reference in New Issue
Block a user