Merge "Enable PXEBoot address range options in config_controller"

This commit is contained in:
Zuul 2018-12-14 18:34:38 +00:00 committed by Gerrit Code Review
commit d009a5335a
4 changed files with 269 additions and 17 deletions

View File

@ -10,7 +10,7 @@ from configobjects import DEFAULT_NAMES, NETWORK_PREFIX_NAMES, OAM_TYPE, \
from netaddr import IPRange
from utils import lag_mode_to_str, validate_network_str, \
check_network_overlap, is_mtu_valid, is_speed_valid, get_service, \
get_optional
get_optional, validate_address_str
from exceptions import ConfigFail, ValidateFail
@ -359,6 +359,8 @@ class ConfigValidator(object):
def validate_pxeboot(self):
# PXEBoot network configuration
start_end_in_config = False
if self.config_type in [REGION_CONFIG, SUBCLOUD_CONFIG]:
self.pxeboot_section_name = 'REGION2_PXEBOOT_NETWORK'
else:
@ -373,6 +375,51 @@ class ConfigValidator(object):
raise ValidateFail("Invalid PXEBOOT_NETWORK IP version - "
"only IPv4 supported")
self.configured_networks.append(pxeboot_subnet)
pxeboot_start_address = None
pxeboot_end_address = None
if self.conf.has_option(self.pxeboot_section_name,
"IP_START_ADDRESS"):
start_addr_str = self.conf.get(self.pxeboot_section_name,
"IP_START_ADDRESS")
pxeboot_start_address = validate_address_str(
start_addr_str, pxeboot_subnet
)
if self.conf.has_option(self.pxeboot_section_name,
"IP_END_ADDRESS"):
end_addr_str = self.conf.get(self.pxeboot_section_name,
"IP_END_ADDRESS")
pxeboot_end_address = validate_address_str(
end_addr_str, pxeboot_subnet
)
if pxeboot_start_address or pxeboot_end_address:
if not pxeboot_end_address:
raise ConfigFail("Missing attribute %s for %s" %
('IP_END_ADDRESS',
self.pxeboot_section_name))
if not pxeboot_start_address:
raise ConfigFail("Missing attribute %s for %s" %
('IP_START_ADDRESS',
self.pxeboot_section_name))
if not pxeboot_start_address < pxeboot_end_address:
raise ConfigFail("Start address %s not "
"less than end address %s for %s."
% (start_addr_str,
end_addr_str,
self.pxeboot_section_name))
min_addresses = 8
if not IPRange(start_addr_str, end_addr_str).size >= \
min_addresses:
raise ConfigFail("Address range for %s must contain "
"at least %d addresses." %
(self.pxeboot_section_name,
min_addresses))
start_end_in_config = True
self.pxeboot_network_configured = True
except ValidateFail as e:
raise ConfigFail("Invalid PXEBOOT_CIDR value of %s for %s."
@ -385,13 +432,28 @@ class ConfigValidator(object):
if self.pxeboot_network_configured:
self.cgcs_conf.set('cPXEBOOT', 'PXEBOOT_SUBNET',
str(pxeboot_subnet))
if start_end_in_config:
self.cgcs_conf.set("cPXEBOOT",
"PXEBOOT_START_ADDRESS",
start_addr_str)
self.cgcs_conf.set("cPXEBOOT",
"PXEBOOT_END_ADDRESS",
end_addr_str)
pxeboot_floating_addr = pxeboot_start_address
pxeboot_controller_addr_0 = pxeboot_start_address + 1
pxeboot_controller_addr_1 = pxeboot_controller_addr_0 + 1
else:
pxeboot_floating_addr = pxeboot_subnet[2]
pxeboot_controller_addr_0 = pxeboot_subnet[3]
pxeboot_controller_addr_1 = pxeboot_subnet[4]
self.cgcs_conf.set('cPXEBOOT',
'CONTROLLER_PXEBOOT_FLOATING_ADDRESS',
str(pxeboot_subnet[2]))
str(pxeboot_floating_addr))
self.cgcs_conf.set('cPXEBOOT', 'CONTROLLER_PXEBOOT_ADDRESS_0',
str(pxeboot_subnet[3]))
str(pxeboot_controller_addr_0))
self.cgcs_conf.set('cPXEBOOT', 'CONTROLLER_PXEBOOT_ADDRESS_1',
str(pxeboot_subnet[4]))
str(pxeboot_controller_addr_1))
self.cgcs_conf.set('cPXEBOOT', 'PXECONTROLLER_FLOATING_HOSTNAME',
'pxecontroller')

View File

@ -58,8 +58,16 @@ def timestamped(dname, fmt='{dname}_%Y-%m-%d-%H-%M-%S'):
def prompt_for(prompt_text, default_input, validator):
valid = False
while not valid:
"""
:param prompt_text: text for the prompt
:param default_input: default input if user hit enter directly
:param validator: validator function to validate user input,
validator should return error message in case
of invalid input, or None if input is valid.
:return: return a valid user input
"""
error_msg = None
while True:
user_input = input(prompt_text)
if user_input.lower() == 'q':
raise UserQuit
@ -67,12 +75,12 @@ def prompt_for(prompt_text, default_input, validator):
user_input = default_input
if validator:
valid = validator(user_input)
else:
valid = True
error_msg = validator(user_input)
if not valid:
print("Invalid choice")
if error_msg is not None:
print(error_msg)
else:
break
return user_input
@ -345,6 +353,9 @@ class ConfigAssistant():
self.controller_pxeboot_hostname_suffix = "-pxeboot"
self.private_pxeboot_subnet = IPNetwork("169.254.202.0/24")
self.pxecontroller_floating_hostname = "pxecontroller"
self.pxeboot_start_address = None
self.pxeboot_end_address = None
self.use_entire_pxeboot_subnet = True
# Management network config
self.management_interface_configured = False
@ -668,7 +679,8 @@ class ConfigAssistant():
}
user_input = prompt_for(
"System mode [duplex-direct]: ", '1',
lambda text: text in value_mapping
lambda text: "Invalid choice" if text not in value_mapping
else None
)
self.system_mode = value_mapping[user_input.lower()]
@ -683,7 +695,8 @@ class ConfigAssistant():
}
user_input = prompt_for(
"Configure Distributed Cloud System Controller [y/N]: ", 'n',
lambda text: text in value_mapping
lambda text: "Invalid choice" if text not in value_mapping
else None
)
self.system_dc_role = value_mapping[user_input.lower()]
@ -781,6 +794,9 @@ class ConfigAssistant():
self.controller_pxeboot_address_1 = \
IPAddress(self.pxeboot_subnet[4])
self.pxeboot_start_address = self.pxeboot_subnet[2]
self.pxeboot_end_address = self.pxeboot_subnet[-2]
def input_pxeboot_config(self):
"""Allow user to input pxeboot config and perform validation."""
@ -846,12 +862,77 @@ class ConfigAssistant():
break
except AddrFormatError:
print("Invalid subnet - please enter a valid IPv4 subnet")
value_mapping = {
"y": True,
"n": False,
}
user_input = prompt_for(
"Use entire PXEBoot subnet [Y/n]: ", 'Y',
lambda text: "Invalid choice"
if text.lower() not in value_mapping
else None
)
self.use_entire_pxeboot_subnet = value_mapping[user_input.lower()]
if not self.use_entire_pxeboot_subnet:
def validate_input_address(text, error_header):
try:
validate_address_str(text, self.pxeboot_subnet)
return None
except ValidateFail as e:
return "%s\n Reason: %s" % (error_header, e)
while True:
self.pxeboot_start_address = self.pxeboot_subnet[2]
self.pxeboot_end_address = self.pxeboot_subnet[-2]
input_str = prompt_for(
"PXEBoot network start address [" +
str(self.pxeboot_start_address) +
"]: ", str(self.pxeboot_start_address),
lambda text: validate_input_address(
text, "Invalid start address.")
)
self.pxeboot_start_address = IPAddress(input_str)
input_str = prompt_for(
"PXEBoot network end address [" +
str(self.pxeboot_end_address) +
"]: ", str(self.pxeboot_end_address),
lambda text: validate_input_address(
text, "Invalid end address.")
)
self.pxeboot_end_address = IPAddress(input_str)
if not self.pxeboot_start_address < \
self.pxeboot_end_address:
print("Start address not less than end address. ")
continue
address_range = IPRange(
str(self.pxeboot_start_address),
str(self.pxeboot_end_address))
min_addresses = 8
if not address_range.size >= min_addresses:
print(
"Address range must contain at least "
"%d addresses." % min_addresses)
continue
print('')
break
else:
self.pxeboot_start_address = self.pxeboot_subnet[2]
self.pxeboot_end_address = self.pxeboot_subnet[-2]
else:
# Use private subnet for pxe booting
self.pxeboot_subnet = self.private_pxeboot_subnet
self.pxeboot_start_address = self.pxeboot_subnet[2]
self.pxeboot_end_address = self.pxeboot_subnet[-2]
default_controller_pxeboot_float_ip = self.pxeboot_subnet[2]
ip_input = IPAddress(default_controller_pxeboot_float_ip)
ip_input = self.pxeboot_start_address
if not self.is_valid_pxeboot_address(ip_input):
raise ConfigFail("Unable to create controller PXEBoot "
"floating address")
@ -2443,6 +2524,19 @@ class ConfigAssistant():
self.separate_pxeboot_network = True
self.pxeboot_subnet = IPNetwork(config.get(
'cPXEBOOT', 'PXEBOOT_SUBNET'))
if config.has_option('cPXEBOOT', 'PXEBOOT_START_ADDRESS'):
self.pxeboot_start_address = IPAddress(config.get(
'cPXEBOOT', 'PXEBOOT_START_ADDRESS'))
if config.has_option('cPXEBOOT', 'PXEBOOT_END_ADDRESS'):
self.pxeboot_end_address = IPAddress(config.get(
'cPXEBOOT', 'PXEBOOT_END_ADDRESS'))
if not self.pxeboot_start_address and \
not self.pxeboot_end_address:
self.pxeboot_start_address = self.pxeboot_subnet[2]
self.pxeboot_end_address = self.pxeboot_subnet[-2]
self.use_entire_pxeboot_subnet = True
else:
self.use_entire_pxeboot_subnet = False
self.controller_pxeboot_address_0 = IPAddress(config.get(
'cPXEBOOT', 'CONTROLLER_PXEBOOT_ADDRESS_0'))
self.controller_pxeboot_address_1 = IPAddress(config.get(
@ -2955,6 +3049,10 @@ class ConfigAssistant():
str(self.controller_pxeboot_address_0))
print("Controller 1 PXEBoot address: " +
str(self.controller_pxeboot_address_1))
if not self.use_entire_pxeboot_subnet:
print("PXEBoot start address: " +
str(self.pxeboot_start_address))
print("PXEBoot end address: " + str(self.pxeboot_end_address))
print("PXEBoot Controller floating hostname: " +
str(self.pxecontroller_floating_hostname))
@ -4103,8 +4201,8 @@ class ConfigAssistant():
'name': 'pxeboot',
'network': str(self.pxeboot_subnet.network),
'prefix': self.pxeboot_subnet.prefixlen,
'ranges': [(str(self.pxeboot_subnet[2]),
str(self.pxeboot_subnet[-2]))],
'ranges': [(str(self.pxeboot_start_address),
str(self.pxeboot_end_address))],
}
pool = client.sysinv.address_pool.create(**values)

View File

@ -0,0 +1,57 @@
[LOGICAL_INTERFACE_1]
LAG_INTERFACE=N
INTERFACE_MTU=1500
INTERFACE_LINK_CAPACITY=1000
INTERFACE_PORTS=eth1
[LOGICAL_INTERFACE_2]
LAG_INTERFACE=N
;LAG_MODE=
INTERFACE_MTU=1500
;INTERFACE_LINK_CAPACITY=
INTERFACE_PORTS=eth0
[PXEBOOT_NETWORK]
PXEBOOT_CIDR=192.168.102.0/24
IP_START_ADDRESS=192.168.102.32
IP_END_ADDRESS=192.168.102.54
[MGMT_NETWORK]
VLAN=123
CIDR=192.168.204.0/24
MULTICAST_CIDR=239.1.1.0/28
DYNAMIC_ALLOCATION=Y
LOGICAL_INTERFACE=LOGICAL_INTERFACE_1
;[INFRA_NETWORK]
;VLAN=124
;IP_START_ADDRESS=192.168.205.102
;IP_END_ADDRESS=192.168.205.199
;DYNAMIC_ALLOCATION=Y
;CIDR=192.168.205.0/24
;LOGICAL_INTERFACE=LOGICAL_INTERFACE_1
[OAM_NETWORK]
;VLAN=
;IP_START_ADDRESS=10.10.10.2
;IP_END_ADDRESS=10.10.10.4
IP_FLOATING_ADDRESS=10.10.10.20
IP_UNIT_0_ADDRESS=10.10.10.30
IP_UNIT_1_ADDRESS=10.10.10.40
CIDR=10.10.10.0/24
GATEWAY=10.10.10.1
LOGICAL_INTERFACE=LOGICAL_INTERFACE_2
;[PXEBOOT_NETWORK]
;PXEBOOT_CIDR=192.168.203.0/24
;[BOARD_MANAGEMENT_NETWORK]
;VLAN=1
;MTU=1496
;SUBNET=192.168.203.0/24
[AUTHENTICATION]
ADMIN_PASSWORD=Li69nux*
[VERSION]
RELEASE = TEST.SW.VERSION

View File

@ -528,3 +528,38 @@ def test_system_config_validation():
validate_only=True)
with pytest.raises(exceptions.ConfigFail):
validate(system_config, DEFAULT_CONFIG, None, False)
def test_pxeboot_range():
""" Test import of system_config file for PXEBoot network address """
# Create the path to the system_config file
systemfile = os.path.join(
os.getcwd(), "controllerconfig/tests/files/", "system_config.pxeboot")
# Test import and generation of answer file
_test_system_config(systemfile)
# Test detection of invalid PXEBoot network start address
system_config = cr.parse_system_config(systemfile)
system_config.set('PXEBOOT_NETWORK', 'IP_START_ADDRESS', '8.123.122.345')
with pytest.raises(exceptions.ConfigFail):
validate(system_config, DEFAULT_CONFIG, None, False)
# Test detection of invalid PXEBoot network end address
system_config = cr.parse_system_config(systemfile)
system_config.set('PXEBOOT_NETWORK', 'IP_END_ADDRESS', '128.123.122.345')
with pytest.raises(exceptions.ConfigFail):
validate(system_config, DEFAULT_CONFIG, None, False)
# Test detection of smaller PXEBoot network end address
system_config = cr.parse_system_config(systemfile)
system_config.set('PXEBOOT_NETWORK', 'IP_END_ADDRESS', '192.168.102.30')
with pytest.raises(exceptions.ConfigFail):
validate(system_config, DEFAULT_CONFIG, None, False)
# Test detection of PXEBoot network range less than min required (8)
system_config = cr.parse_system_config(systemfile)
system_config.set('PXEBOOT_NETWORK', 'IP_END_ADDRESS', '128.123.122.34')
with pytest.raises(exceptions.ConfigFail):
validate(system_config, DEFAULT_CONFIG, None, False)