Format the IP addresses in payload before adding a subcloud

The IPv6 addresses can be represented in multiple formats. As IP
addresses are stored as text in database, ansible inventory and
overrides, this commit converts the IP addresses in payload to
standard text format of IPv6 address during adding a new subcloud.

Tested with installing and bootstrapping  a new subcloud(RVMC
configured) with the correct IPv6 address values, but with
unrecommended upper case letters and '0'. The addresses are
converted to standard format in database, ansible inventory and
overrides files.

Partial-Bug: 1931459
Signed-off-by: Yuxing Jiang <yuxing.jiang@windriver.com>
Change-Id: I6c26e749941f1ea2597f91886ad8f7da64521f0d
This commit is contained in:
Yuxing Jiang 2021-06-09 11:11:27 -04:00
parent 0e93c09b52
commit cb97981101
2 changed files with 94 additions and 0 deletions

View File

@ -82,6 +82,17 @@ SUBCLOUD_ADD_GET_FILE_CONTENTS = [
INSTALL_VALUES,
]
BOOTSTRAP_VALUES_ADDRESSES = [
'bootstrap-address', 'management_start_address', 'management_end_address',
'management_gateway_address', 'systemcontroller_gateway_address',
'external_oam_gateway_address', 'external_oam_floating_address'
]
INSTALL_VALUES_ADDRESSES = [
'bootstrap_address', 'bmc_address', 'nexthop_gateway',
'network_address'
]
# The following parameters can be provided by the user for
# remote subcloud restore
# - initial_backup_dir (default to /opt/platform-backup)
@ -445,6 +456,31 @@ class SubcloudsController(object):
pecan.abort(400, _("oam_floating_address invalid: %s") % e)
self._validate_group_id(context, group_id)
def _format_ip_address(self, payload):
"""Format IP addresses in 'bootstrap_values' and 'install_values'.
The IPv6 addresses can be represented in multiple ways. Format and
update the IP addresses in payload before saving it to database.
"""
if INSTALL_VALUES in payload:
for k in INSTALL_VALUES_ADDRESSES:
if k in payload[INSTALL_VALUES]:
try:
address = IPAddress(payload[INSTALL_VALUES].get(k)).format()
except AddrFormatError as e:
LOG.exception(e)
pecan.abort(400, _("%s invalid: %s") % (k, e))
payload[INSTALL_VALUES].update({k: address})
for k in BOOTSTRAP_VALUES_ADDRESSES:
if k in payload:
try:
address = IPAddress(payload.get(k)).format()
except AddrFormatError as e:
LOG.exception(e)
pecan.abort(400, _("%s invalid: %s") % (k, e))
payload.update({k: address})
@staticmethod
def _validate_install_values(payload):
"""Validate install values if 'install_values' is present in payload.
@ -896,6 +932,8 @@ class SubcloudsController(object):
self._validate_install_values(payload)
self._format_ip_address(payload)
# Upload the deploy config files if it is included in the request
# It has a dependency on the subcloud name, and it is called after
# the name has been validated

View File

@ -334,6 +334,33 @@ class TestSubcloudPost(testroot.DCManagerApiTest,
headers=self.get_api_headers())
self._verify_post_success(response)
def test_post_subcloud_bad_bootstrap_address(self):
"""Test POST operation with a bad bootstrap-address"""
param_key = "bootstrap-address"
# bootstrap-address must be valid IP address
bad_values = ["10.10.10.wut", # including letters in the IP
"10.10.10.276" # 276 is invalid
]
good_values = "10.10.10.3"
self._test_post_param_inputs(param_key,
bad_values,
good_values)
def test_post_subcloud_bad_IPv6_bootstrap_address(self):
"""Test POST operation with a bad bootstrap-address"""
param_key = "bootstrap-address"
# bootstrap-address must be valid IP address
bad_values = ["2620::10a:a103::1135", # more than one double colons
"2620:10a:a001:a103::wut", # invalid letter
"2620:10a:a001:a103:1135" # Incomplete IP
]
good_values = "2620:10a:a001:a103::1135"
self._test_post_param_inputs(param_key,
bad_values,
good_values)
def test_post_subcloud_bad_gateway(self):
"""Test POST with an invalid gateway."""
@ -1167,6 +1194,35 @@ class TestSubcloudAPIOther(testroot.DCManagerApiTest):
self.assertEqual(install_values, "/opt/dc/ansible/subcloud1/install_values.yml")
self.assertEqual(deploy_config, "/opt/dc/ansible/subcloud1_deploy_config.yml")
@mock.patch.object(rpc_client, 'ManagerClient')
def test_format_ip_address(self, mock_rpc_client):
sc = subclouds.SubcloudsController()
fake_payload = dict()
good_values = {
'10.10.10.3': '10.10.10.3',
'2620:10a:a001:a103::1135': '2620:10a:a001:a103::1135',
'2620:10A:A001:A103::1135': '2620:10a:a001:a103::1135', # with upper case letters
'2620:010a:a001:a103::1135': '2620:10a:a001:a103::1135', # with leading zeros
'2620:10a:a001:a103:0000::1135': '2620:10a:a001:a103::1135' # with a string of zeros
}
for k, v in good_values.items():
fake_payload.update({'bootstrap-address': k})
sc._format_ip_address(fake_payload)
self.assertEqual(fake_payload['bootstrap-address'], v)
fake_payload[subclouds.INSTALL_VALUES] = dict()
for k, v in good_values.items():
fake_payload[subclouds.INSTALL_VALUES].update({'bmc_address': k})
sc._format_ip_address(fake_payload)
self.assertEqual(fake_payload[subclouds.INSTALL_VALUES]['bmc_address'], v)
fake_payload.update({'othervalues1': 'othervalues1'})
fake_payload[subclouds.INSTALL_VALUES].update({'othervalues2': 'othervalues2'})
sc._format_ip_address(fake_payload)
self.assertEqual(fake_payload['othervalues1'], 'othervalues1')
self.assertEqual(fake_payload[subclouds.INSTALL_VALUES]['othervalues2'], 'othervalues2')
@mock.patch.object(rpc_client, 'ManagerClient')
@mock.patch.object(keyring, 'get_password')
def test_get_subcloud_db_install_values(