Validate local_interface exists

In order to improve the user experiance, we should validate that the
provided local_interface actually exists prior to trying to configure
the undercloud with it. If net_config_override is not used and the
local_interface does not exist, an error will be returned to the
user early on in the installation process. Additionally if the user
does not have an undercloud.conf, a warning is printed to show that
the defaults will be used.

Change-Id: Ia2a7e7fc916f6d2b62e212cb42641494b88d6d17
Closes-Bug: #1709177
This commit is contained in:
Alex Schultz 2017-08-07 14:39:03 -06:00
parent 88c3b8529b
commit 062346e319
5 changed files with 60 additions and 5 deletions

View File

@ -12,6 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
import mock
from oslo_config import fixture as config_fixture
from oslotest import base
@ -25,7 +27,9 @@ class TestValidator(base.BaseTestCase):
self.conf = config_fixture.Config()
self.useFixture(self.conf)
def test_validation_passes(self):
@mock.patch('netifaces.interfaces')
def test_validation_passes(self, ifaces_mock):
ifaces_mock.return_value = ['eth1']
undercloud._validate_network()
def test_fail_on_local_ip(self):
@ -122,7 +126,9 @@ class TestValidator(base.BaseTestCase):
validator.validate_config(params, lambda x: None)
self.assertEqual(save_params, params)
def test_valid_undercloud_nameserver_passes(self):
@mock.patch('netifaces.interfaces')
def test_valid_undercloud_nameserver_passes(self, ifaces_mock):
ifaces_mock.return_value = ['eth1']
self.conf.config(undercloud_nameservers=['192.168.24.4',
'192.168.24.5'])
undercloud._validate_network()
@ -144,19 +150,44 @@ class TestValidator(base.BaseTestCase):
self.assertRaises(validator.FailedValidation,
undercloud._validate_network)
def test_ssl_hosts_allowed(self):
@mock.patch('netifaces.interfaces')
def test_ssl_hosts_allowed(self, ifaces_mock):
ifaces_mock.return_value = ['eth1']
self.conf.config(undercloud_public_host='public.domain',
undercloud_admin_host='admin.domain',
undercloud_service_certificate='foo.pem',
enable_ui=False)
undercloud._validate_network()
def test_allow_all_with_ui(self):
@mock.patch('netifaces.interfaces')
def test_allow_all_with_ui(self, ifaces_mock):
ifaces_mock.return_value = ['eth1']
self.conf.config(undercloud_admin_host='10.0.0.10',
generate_service_certificate=True,
enable_ui=True)
def test_fail_on_invalid_ip(self):
@mock.patch('netifaces.interfaces')
def test_fail_on_invalid_ip(self, ifaces_mock):
ifaces_mock.return_value = ['eth1']
self.conf.config(dhcp_start='foo.bar')
self.assertRaises(validator.FailedValidation,
undercloud._validate_network)
@mock.patch('netifaces.interfaces')
def test_validate_interface_exists(self, ifaces_mock):
ifaces_mock.return_value = ['eth0', 'eth1']
self.conf.config(local_interface='eth0')
undercloud._validate_network()
@mock.patch('netifaces.interfaces')
def test_fail_validate_interface_missing(self, ifaces_mock):
ifaces_mock.return_value = ['eth0', 'eth1']
self.conf.config(local_interface='em1')
self.assertRaises(validator.FailedValidation,
undercloud._validate_network)
@mock.patch('netifaces.interfaces')
def test_validate_interface_with_net_config_override(self, ifaces_mock):
ifaces_mock.return_value = ['eth0', 'eth1']
self.conf.config(local_interface='em2', net_config_override='foo')
undercloud._validate_network()

View File

@ -550,6 +550,8 @@ def _load_config():
conf_params += ['--config-file', PATHS.PASSWORD_PATH]
if os.path.isfile(PATHS.CONF_PATH):
conf_params += ['--config-file', PATHS.CONF_PATH]
else:
LOG.warning('%s does not exist. Using defaults.' % PATHS.CONF_PATH)
CONF(conf_params)

View File

@ -13,6 +13,7 @@
# under the License.
import netaddr
import netifaces
class FailedValidation(Exception):
@ -35,6 +36,7 @@ def validate_config(params, error_callback):
_validate_inspection_range(local_params, error_callback)
_validate_no_overlap(local_params, error_callback)
_validate_ips(local_params, error_callback)
_validate_interface_exists(local_params, error_callback)
def _validate_ips(params, error_callback):
@ -143,3 +145,13 @@ def _validate_no_overlap(params, error_callback):
(params['inspection_start'], params['inspection_end'],
params['dhcp_start'], params['dhcp_end']))
error_callback(message)
def _validate_interface_exists(params, error_callback):
"""Validate the provided local interface exists"""
local_interface = params['local_interface']
net_override = params['net_config_override']
if not net_override and local_interface not in netifaces.interfaces():
message = ('Invalid local_interface specified. %s is not available.' %
local_interface)
error_callback(message)

View File

@ -0,0 +1,9 @@
---
fixes:
- |
Validate the local_interface for the undercloud install to fail fast if
the interface does not actually exist on the system. If net_config_override
is configured, the local_interface will not be validated.
- |
Log a warning if undercloud.conf is missing to indicate that the defaults
will be used.

View File

@ -9,6 +9,7 @@ python-swiftclient>=3.2.0 # Apache-2.0
oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
psutil>=3.2.2 # BSD
netaddr!=0.7.16,>=0.7.13 # BSD
netifaces>=0.10.4 # MIT
pystache # MIT
os-refresh-config # Apache-2.0
os-apply-config # Apache-2.0