Handle multiple network interfaces
Support public and private network in kolla-mesos configuration and Vagrant. Change-Id: Ic8df2b608a018dfd59640002c897fd21341bef27 Closes-Bug: #1523448
This commit is contained in:
parent
df9f8a304b
commit
83d8341993
@ -10,20 +10,41 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import fcntl
|
||||
import socket
|
||||
import struct
|
||||
import netifaces
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
# TODO(nihilifer): Autodetect networks and find a way to share commons between
|
||||
# kolla_mesos and kolla_mesos_start.py.
|
||||
def get_ip_address(ifname='eth0'):
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
try:
|
||||
return socket.inet_ntoa(fcntl.ioctl(
|
||||
s.fileno(),
|
||||
0x8915, # SIOCGIFADDR
|
||||
struct.pack('256s', ifname[:15])
|
||||
)[20:24])
|
||||
except IOError:
|
||||
return '127.0.0.1'
|
||||
CONF = cfg.CONF
|
||||
CONF.import_group('network', 'kolla_mesos.config.network')
|
||||
|
||||
|
||||
def _get_localhost():
|
||||
"""Get localhost IP address regarding the IP protocol version"""
|
||||
if CONF.network.ipv6:
|
||||
return '::1'
|
||||
return '127.0.0.1'
|
||||
|
||||
|
||||
def get_ip_address(public=True):
|
||||
"""Get IP address of the interface connected to the public network.
|
||||
|
||||
If there is no such an interface, then localhost is returned.
|
||||
"""
|
||||
if public:
|
||||
iface = CONF.network.public_interface
|
||||
else:
|
||||
iface = CONF.network.private_interface
|
||||
|
||||
if iface not in netifaces.interfaces():
|
||||
return _get_localhost()
|
||||
|
||||
if CONF.network.ipv6:
|
||||
address_family = netifaces.AF_INET6
|
||||
else:
|
||||
address_family = netifaces.AF_INET
|
||||
|
||||
for ifaddress in netifaces.ifaddresses(iface)[address_family]:
|
||||
if 'addr' in ifaddress:
|
||||
return ifaddress['addr']
|
||||
|
||||
return _get_localhost()
|
||||
|
32
kolla_mesos/config/network.py
Normal file
32
kolla_mesos/config/network.py
Normal file
@ -0,0 +1,32 @@
|
||||
# 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.
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
network_opts = [
|
||||
cfg.StrOpt('private-interface',
|
||||
default='eth1',
|
||||
help='NIC connected to the private network'),
|
||||
cfg.StrOpt('public-interface',
|
||||
default='eth2',
|
||||
help='NIC connected to the public network'),
|
||||
cfg.BoolOpt('ipv6',
|
||||
default=False,
|
||||
help='Use IPv6 protocol')
|
||||
]
|
||||
network_opt_group = cfg.OptGroup(name='network',
|
||||
title='Options for network interfaces')
|
||||
CONF.register_group(network_opt_group)
|
||||
CONF.register_cli_opts(network_opts, network_opt_group)
|
||||
CONF.register_opts(network_opts, network_opt_group)
|
@ -13,6 +13,7 @@
|
||||
from kolla_mesos.config import chronos
|
||||
from kolla_mesos.config import kolla
|
||||
from kolla_mesos.config import marathon
|
||||
from kolla_mesos.config import network
|
||||
from kolla_mesos.config import profiles
|
||||
from kolla_mesos.config import zookeeper
|
||||
|
||||
@ -22,6 +23,7 @@ def list_opts():
|
||||
('chronos', chronos.chronos_opts),
|
||||
('kolla', kolla.kolla_opts),
|
||||
('marathon', marathon.marathon_opts),
|
||||
('network', network.network_opts),
|
||||
('profiles', profiles.profiles_opts),
|
||||
('zookeeper', zookeeper.zookeeper_opts)
|
||||
]
|
||||
|
82
kolla_mesos/tests/common/test_network_utils.py
Normal file
82
kolla_mesos/tests/common/test_network_utils.py
Normal file
@ -0,0 +1,82 @@
|
||||
# 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.
|
||||
|
||||
import mock
|
||||
import netifaces
|
||||
from oslo_config import cfg
|
||||
|
||||
from kolla_mesos.common import network_utils
|
||||
from kolla_mesos.tests import base
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
class TestNetworkUtils(base.BaseTestCase):
|
||||
|
||||
def test_get_localhost_ipv4(self):
|
||||
CONF.set_override('ipv6', False, group='network')
|
||||
localhost = network_utils._get_localhost()
|
||||
self.assertEqual(localhost, '127.0.0.1')
|
||||
|
||||
def test_get_localhost_ipv6(self):
|
||||
CONF.set_override('ipv6', True, group='network')
|
||||
localhost = network_utils._get_localhost()
|
||||
self.assertEqual(localhost, '::1')
|
||||
|
||||
@mock.patch('netifaces.interfaces')
|
||||
@mock.patch('netifaces.ifaddresses')
|
||||
def test_get_ip_address_public_ipv4(self, ifaddresses_mock,
|
||||
interfaces_mock):
|
||||
CONF.set_override('ipv6', False, group='network')
|
||||
interfaces_mock.return_value = ['eth2']
|
||||
ifaddresses_mock.return_value = {
|
||||
netifaces.AF_INET: [{'addr': '10.0.0.1'}]
|
||||
}
|
||||
ip_address = network_utils.get_ip_address()
|
||||
self.assertEqual(ip_address, '10.0.0.1')
|
||||
|
||||
@mock.patch('netifaces.interfaces')
|
||||
@mock.patch('netifaces.ifaddresses')
|
||||
def test_get_ip_address_private_ipv4(self, ifaddresses_mock,
|
||||
interfaces_mock):
|
||||
CONF.set_override('ipv6', False, group='network')
|
||||
interfaces_mock.return_value = ['eth1']
|
||||
ifaddresses_mock.return_value = {
|
||||
netifaces.AF_INET: [{'addr': '10.0.0.1'}]
|
||||
}
|
||||
ip_address = network_utils.get_ip_address(public=False)
|
||||
self.assertEqual(ip_address, '10.0.0.1')
|
||||
|
||||
@mock.patch('netifaces.interfaces')
|
||||
@mock.patch('netifaces.ifaddresses')
|
||||
def test_get_ip_address_public_ipv6(self, ifaddresses_mock,
|
||||
interfaces_mock):
|
||||
CONF.set_override('ipv6', True, group='network')
|
||||
interfaces_mock.return_value = ['eth2']
|
||||
ifaddresses_mock.return_value = {
|
||||
netifaces.AF_INET6: [{'addr': 'fe80::5054:ff:fe80:e42b%eth2'}]
|
||||
}
|
||||
ip_address = network_utils.get_ip_address()
|
||||
self.assertEqual(ip_address, 'fe80::5054:ff:fe80:e42b%eth2')
|
||||
|
||||
@mock.patch('netifaces.interfaces')
|
||||
@mock.patch('netifaces.ifaddresses')
|
||||
def test_get_ip_address_private_ipv6(self, ifaddresses_mock,
|
||||
interfaces_mock):
|
||||
CONF.set_override('ipv6', True, group='network')
|
||||
interfaces_mock.return_value = ['eth1']
|
||||
ifaddresses_mock.return_value = {
|
||||
netifaces.AF_INET6: [{'addr': 'fe80::5054:ff:fefc:273e%eth1'}]
|
||||
}
|
||||
ip_address = network_utils.get_ip_address(public=False)
|
||||
self.assertEqual(ip_address, 'fe80::5054:ff:fefc:273e%eth1')
|
45
kolla_mesos/tests/config/test_network_config.py
Normal file
45
kolla_mesos/tests/config/test_network_config.py
Normal file
@ -0,0 +1,45 @@
|
||||
# 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.
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
from kolla_mesos.tests import base
|
||||
from kolla_mesos.tests.fakes import config_file as fake_config_file
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
CONF.import_group('network', 'kolla_mesos.config.network')
|
||||
|
||||
|
||||
NETWORK_TEXT_CONFIG = """
|
||||
[network]
|
||||
private_interface = test_priv_iface
|
||||
public_interface = test_pub_iface
|
||||
"""
|
||||
|
||||
|
||||
class TestNetworkConfig(base.BaseTestCase):
|
||||
|
||||
def _asserts(self):
|
||||
self.assertEqual(CONF.network.private_interface, 'test_priv_iface')
|
||||
self.assertEqual(CONF.network.public_interface, 'test_pub_iface')
|
||||
|
||||
def test_cli_config(self):
|
||||
argv = ['--network-private-interface', 'test_priv_iface',
|
||||
'--network-public-interface', 'test_pub_iface']
|
||||
CONF(argv, project='kolla-mesos')
|
||||
self._asserts()
|
||||
|
||||
@fake_config_file.FakeConfigFile(NETWORK_TEXT_CONFIG)
|
||||
def test_file_config(self):
|
||||
CONF([], project='kolla-mesos', default_config_files=['/dev/null'])
|
||||
self._asserts()
|
@ -7,5 +7,6 @@ Babel>=1.3
|
||||
dcos>=0.1.3 # Apache-2.0
|
||||
Jinja2>=2.8 # BSD License (3 clause)
|
||||
kazoo>=2.2
|
||||
netifaces>=0.10.4
|
||||
oslo.config>=2.7.0 # Apache-2.0
|
||||
PyYAML>=3.1.0
|
||||
|
@ -1,6 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
HOST_IP=$(ip addr show eth0 | grep -Po 'inet \K[\d.]+')
|
||||
NET_IFACE=eth2
|
||||
|
||||
function get_host_ip {
|
||||
echo $(ip addr show $NET_IFACE | grep -Po 'inet \K[\d.]+')
|
||||
}
|
||||
|
||||
HOST_IP=$(get_host_ip)
|
||||
|
||||
function infra_start {
|
||||
docker run -d \
|
||||
@ -73,6 +79,7 @@ Usage: $0 COMMAND [options]
|
||||
|
||||
Options:
|
||||
--host, -i <host_ip> Specify path to host ip
|
||||
--net-iface, -n <nic> Specify NIC to use for host ip lookup
|
||||
--help, -h Show this usage information
|
||||
|
||||
Commands:
|
||||
@ -81,7 +88,7 @@ Commands:
|
||||
EOF
|
||||
}
|
||||
|
||||
ARGS=$(getopt -o hi: -l help,host: --name "$0" -- "$@") || { usage >&2; exit 2; }
|
||||
ARGS=$(getopt -o hin: -l help,host,net-iface: --name "$0" -- "$@") || { usage >&2; exit 2; }
|
||||
eval set -- "$ARGS"
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
@ -91,6 +98,12 @@ while [ "$#" -gt 0 ]; do
|
||||
shift 2
|
||||
;;
|
||||
|
||||
(--net-iface|-n)
|
||||
NET_IFACE="$2"
|
||||
HOST_IP=$(get_host_ip)
|
||||
shift 2
|
||||
;;
|
||||
|
||||
(--help|-h)
|
||||
usage
|
||||
shift
|
||||
|
6
vagrant/Vagrantfile
vendored
6
vagrant/Vagrantfile
vendored
@ -25,10 +25,8 @@ end
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = get_default(:base_image)
|
||||
|
||||
config.vm.network "forwarded_port", guest: 4400, host: 4400
|
||||
config.vm.network "forwarded_port", guest: 5050, host: 5050
|
||||
config.vm.network "forwarded_port", guest: 5051, host: 5051
|
||||
config.vm.network "forwarded_port", guest: 8080, host: 8080
|
||||
config.vm.network "private_network", type: "dhcp"
|
||||
config.vm.network "public_network", dev: get_default(:bridge_interface), mode: 'bridge', type: 'bridge'
|
||||
|
||||
config.vm.synced_folder "..", "/home/vagrant/kolla-mesos", type: get_default(:sync_method)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user