
This change generates /etc/sysconf/network-scripts/ifcfg-* for ivs. It also generates /etc/sysconf/ivs configuration file for ivs. It supports only RedHat at this point. Indigo Virtual Switch (IVS, https://github.com/floodlight/ivs) is a virtual switch for Linux. It is compatible with the KVM hypervisor and leveraging the Open vSwitch kernel module for packet forwarding. There are three major differences between IVS and OVS: 1. Each node can have at most one ivs, name is not required. 2. Bond is not allowed to attach to an ivs. It is the SDN controller's job to dynamically form bonds on ivs. 3. IP address can only be statically assigned. Change-Id: I276d736794d123405de793c2a4eb2c1ee55a0fad
616 lines
24 KiB
Python
616 lines
24 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
# Copyright 2014 Red Hat, Inc.
|
|
#
|
|
# 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 logging
|
|
import netaddr
|
|
from oslo_utils import strutils
|
|
|
|
from os_net_config import utils
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_NUMBERED_NICS = None
|
|
|
|
|
|
class InvalidConfigException(ValueError):
|
|
pass
|
|
|
|
|
|
def object_from_json(json):
|
|
obj_type = json.get("type")
|
|
if obj_type == "interface":
|
|
return Interface.from_json(json)
|
|
elif obj_type == "vlan":
|
|
return Vlan.from_json(json)
|
|
elif obj_type == "ovs_bridge":
|
|
return OvsBridge.from_json(json)
|
|
elif obj_type == "ovs_bond":
|
|
return OvsBond.from_json(json)
|
|
elif obj_type == "linux_bond":
|
|
return LinuxBond.from_json(json)
|
|
elif obj_type == "linux_bridge":
|
|
return LinuxBridge.from_json(json)
|
|
elif obj_type == "ivs_bridge":
|
|
return IvsBridge.from_json(json)
|
|
elif obj_type == "ivs_interface":
|
|
return IvsInterface.from_json(json)
|
|
|
|
|
|
def _get_required_field(json, name, object_name):
|
|
field = json.get(name)
|
|
if not field:
|
|
msg = '%s JSON objects require \'%s\' to be configured.' \
|
|
% (object_name, name)
|
|
raise InvalidConfigException(msg)
|
|
return field
|
|
|
|
|
|
def _numbered_nics(nic_mapping=None):
|
|
mapping = nic_mapping or {}
|
|
global _NUMBERED_NICS
|
|
if _NUMBERED_NICS:
|
|
return _NUMBERED_NICS
|
|
_NUMBERED_NICS = {}
|
|
count = 0
|
|
active_nics = utils.ordered_active_nics()
|
|
for nic in active_nics:
|
|
count += 1
|
|
nic_alias = "nic%i" % count
|
|
nic_mapped = mapping.get(nic_alias, nic)
|
|
|
|
# The mapping is either invalid, or specifies a mac
|
|
if nic_mapped not in active_nics:
|
|
for active in active_nics:
|
|
try:
|
|
active_mac = utils.interface_mac(active)
|
|
except IOError:
|
|
continue
|
|
if nic_mapped == active_mac:
|
|
logger.debug("%s matches device %s" % (nic_mapped, active))
|
|
nic_mapped = active
|
|
break
|
|
else:
|
|
# The mapping can't specify a non-active or non-existent nic
|
|
logger.warning('interface %s is not in an active nic (%s)'
|
|
% (nic_mapped, ', '.join(active_nics)))
|
|
continue
|
|
|
|
# Duplicate mappings are not allowed
|
|
if nic_mapped in _NUMBERED_NICS.values():
|
|
msg = ('interface %s already mapped, '
|
|
'check mapping file for duplicates'
|
|
% nic_mapped)
|
|
raise InvalidConfigException(msg)
|
|
|
|
_NUMBERED_NICS[nic_alias] = nic_mapped
|
|
logger.info("%s mapped to: %s" % (nic_alias, nic_mapped))
|
|
return _NUMBERED_NICS
|
|
|
|
|
|
class Route(object):
|
|
"""Base class for network routes."""
|
|
|
|
def __init__(self, next_hop, ip_netmask="", default=False):
|
|
self.next_hop = next_hop
|
|
self.ip_netmask = ip_netmask
|
|
self.default = default
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
next_hop = _get_required_field(json, 'next_hop', 'Route')
|
|
ip_netmask = json.get('ip_netmask', "")
|
|
default = strutils.bool_from_string(str(json.get('default', False)))
|
|
return Route(next_hop, ip_netmask, default)
|
|
|
|
|
|
class Address(object):
|
|
"""Base class for network addresses."""
|
|
|
|
def __init__(self, ip_netmask):
|
|
self.ip_netmask = ip_netmask
|
|
ip_nw = netaddr.IPNetwork(self.ip_netmask)
|
|
self.ip = str(ip_nw.ip)
|
|
self.netmask = str(ip_nw.netmask)
|
|
self.prefixlen = ip_nw.prefixlen
|
|
self.version = ip_nw.version
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
ip_netmask = _get_required_field(json, 'ip_netmask', 'Address')
|
|
return Address(ip_netmask)
|
|
|
|
|
|
class _BaseOpts(object):
|
|
"""Base abstraction for logical port options."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, primary=False, nic_mapping=None,
|
|
persist_mapping=False, defroute=True, dhclient_args=None,
|
|
dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
dns_servers = dns_servers or []
|
|
numbered_nic_names = _numbered_nics(nic_mapping)
|
|
self.hwaddr = None
|
|
self.hwname = None
|
|
self.renamed = False
|
|
if name in numbered_nic_names:
|
|
if persist_mapping:
|
|
self.name = name
|
|
self.hwname = numbered_nic_names[name]
|
|
self.hwaddr = utils.interface_mac(self.hwname)
|
|
self.renamed = True
|
|
else:
|
|
self.name = numbered_nic_names[name]
|
|
else:
|
|
self.name = name
|
|
|
|
self.mtu = mtu
|
|
self.use_dhcp = use_dhcp
|
|
self.use_dhcpv6 = use_dhcpv6
|
|
self.addresses = addresses
|
|
self.routes = routes
|
|
self.primary = primary
|
|
self.defroute = defroute
|
|
self.dhclient_args = dhclient_args
|
|
self.dns_servers = dns_servers
|
|
self.bridge_name = None # internal
|
|
self.linux_bridge_name = None # internal
|
|
self.ivs_bridge_name = None # internal
|
|
self.ovs_port = False # internal
|
|
self.primary_interface_name = None # internal
|
|
|
|
def v4_addresses(self):
|
|
v4_addresses = []
|
|
for addr in self.addresses:
|
|
if addr.version == 4:
|
|
v4_addresses.append(addr)
|
|
|
|
return v4_addresses
|
|
|
|
def v6_addresses(self):
|
|
v6_addresses = []
|
|
for addr in self.addresses:
|
|
if addr.version == 6:
|
|
v6_addresses.append(addr)
|
|
|
|
return v6_addresses
|
|
|
|
@staticmethod
|
|
def base_opts_from_json(json, include_primary=True):
|
|
use_dhcp = strutils.bool_from_string(str(json.get('use_dhcp', False)))
|
|
use_dhcpv6 = strutils.bool_from_string(str(json.get('use_dhcpv6',
|
|
False)))
|
|
defroute = strutils.bool_from_string(str(json.get('defroute',
|
|
True)))
|
|
mtu = json.get('mtu', None)
|
|
dhclient_args = json.get('dhclient_args')
|
|
dns_servers = json.get('dns_servers')
|
|
primary = strutils.bool_from_string(str(json.get('primary', False)))
|
|
addresses = []
|
|
routes = []
|
|
|
|
# addresses
|
|
addresses_json = json.get('addresses')
|
|
if addresses_json:
|
|
if isinstance(addresses_json, list):
|
|
for address in addresses_json:
|
|
addresses.append(Address.from_json(address))
|
|
else:
|
|
msg = 'Addresses must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
# routes
|
|
routes_json = json.get('routes')
|
|
if routes_json:
|
|
if isinstance(routes_json, list):
|
|
for route in routes_json:
|
|
routes.append(Route.from_json(route))
|
|
else:
|
|
msg = 'Routes must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
nic_mapping = json.get('nic_mapping')
|
|
persist_mapping = json.get('persist_mapping')
|
|
|
|
if include_primary:
|
|
return (use_dhcp, use_dhcpv6, addresses, routes, mtu, primary,
|
|
nic_mapping, persist_mapping, defroute, dhclient_args,
|
|
dns_servers)
|
|
else:
|
|
return (use_dhcp, use_dhcpv6, addresses, routes, mtu,
|
|
nic_mapping, persist_mapping, defroute, dhclient_args,
|
|
dns_servers)
|
|
|
|
|
|
class Interface(_BaseOpts):
|
|
"""Base class for network interfaces."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, primary=False, nic_mapping=None,
|
|
persist_mapping=False, defroute=True, dhclient_args=None,
|
|
dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
dns_servers = dns_servers or []
|
|
super(Interface, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
|
routes, mtu, primary, nic_mapping,
|
|
persist_mapping, defroute,
|
|
dhclient_args, dns_servers)
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = _get_required_field(json, 'name', 'Interface')
|
|
opts = _BaseOpts.base_opts_from_json(json)
|
|
return Interface(name, *opts)
|
|
|
|
|
|
class Vlan(_BaseOpts):
|
|
"""Base class for VLANs.
|
|
|
|
NOTE: the name parameter must be formated w/ vlan<num> where <num>
|
|
matches the vlan ID being used. Example: vlan5
|
|
"""
|
|
|
|
def __init__(self, device, vlan_id, use_dhcp=False, use_dhcpv6=False,
|
|
addresses=None, routes=None, mtu=None, primary=False,
|
|
nic_mapping=None, persist_mapping=False, defroute=True,
|
|
dhclient_args=None, dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
dns_servers = dns_servers or []
|
|
name = 'vlan%i' % vlan_id
|
|
super(Vlan, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
|
routes, mtu, primary, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers)
|
|
self.vlan_id = int(vlan_id)
|
|
|
|
numbered_nic_names = _numbered_nics(nic_mapping)
|
|
if device in numbered_nic_names:
|
|
self.device = numbered_nic_names[device]
|
|
else:
|
|
self.device = device
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
# A vlan on an OVS bridge won't require a device (OVS Int Port)
|
|
device = json.get('device')
|
|
vlan_id = _get_required_field(json, 'vlan_id', 'Vlan')
|
|
opts = _BaseOpts.base_opts_from_json(json)
|
|
return Vlan(device, vlan_id, *opts)
|
|
|
|
|
|
class IvsInterface(_BaseOpts):
|
|
"""Base class for ivs interfaces."""
|
|
|
|
def __init__(self, vlan_id, name='ivs', use_dhcp=False, use_dhcpv6=False,
|
|
addresses=None, routes=None, mtu=1500, primary=False,
|
|
nic_mapping=None, persist_mapping=False, defroute=True,
|
|
dhclient_args=None, dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
dns_servers = dns_servers or []
|
|
name_vlan = '%s%i' % (name, vlan_id)
|
|
super(IvsInterface, self).__init__(name_vlan, use_dhcp, use_dhcpv6,
|
|
addresses, routes, mtu, primary,
|
|
nic_mapping, persist_mapping,
|
|
defroute, dhclient_args,
|
|
dns_servers)
|
|
self.vlan_id = int(vlan_id)
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = json.get('name')
|
|
vlan_id = _get_required_field(json, 'vlan_id', 'IvsInterface')
|
|
opts = _BaseOpts.base_opts_from_json(json)
|
|
return IvsInterface(vlan_id, name, *opts)
|
|
|
|
|
|
class OvsBridge(_BaseOpts):
|
|
"""Base class for OVS bridges."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, members=None, ovs_options=None,
|
|
ovs_extra=None, nic_mapping=None, persist_mapping=False,
|
|
defroute=True, dhclient_args=None, dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
members = members or []
|
|
ovs_extra = ovs_extra or []
|
|
dns_servers = dns_servers or []
|
|
super(OvsBridge, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
|
routes, mtu, False, nic_mapping,
|
|
persist_mapping, defroute,
|
|
dhclient_args, dns_servers)
|
|
self.members = members
|
|
self.ovs_options = ovs_options
|
|
self.ovs_extra = ovs_extra
|
|
for member in self.members:
|
|
member.bridge_name = name
|
|
member.ovs_port = True
|
|
if member.primary:
|
|
if self.primary_interface_name:
|
|
msg = 'Only one primary interface allowed per bridge.'
|
|
raise InvalidConfigException(msg)
|
|
if member.primary_interface_name:
|
|
self.primary_interface_name = member.primary_interface_name
|
|
else:
|
|
self.primary_interface_name = member.name
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = _get_required_field(json, 'name', 'OvsBridge')
|
|
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
|
persist_mapping, defroute,
|
|
dhclient_args, dns_servers) = _BaseOpts.base_opts_from_json(
|
|
json, include_primary=False)
|
|
ovs_options = json.get('ovs_options')
|
|
ovs_extra = json.get('ovs_extra', [])
|
|
members = []
|
|
|
|
# members
|
|
members_json = json.get('members')
|
|
if members_json:
|
|
if isinstance(members_json, list):
|
|
for member in members_json:
|
|
members.append(object_from_json(member))
|
|
else:
|
|
msg = 'Members must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
return OvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
|
addresses=addresses, routes=routes, mtu=mtu,
|
|
members=members, ovs_options=ovs_options,
|
|
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
|
persist_mapping=persist_mapping, defroute=defroute,
|
|
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
|
|
|
|
|
class LinuxBridge(_BaseOpts):
|
|
"""Base class for Linux bridges."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, members=None, nic_mapping=None,
|
|
persist_mapping=False, defroute=True, dhclient_args=None,
|
|
dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
members = members or []
|
|
dns_servers = dns_servers or []
|
|
super(LinuxBridge, self).__init__(name, use_dhcp, use_dhcpv6,
|
|
addresses, routes, mtu, False,
|
|
nic_mapping, persist_mapping,
|
|
defroute, dhclient_args, dns_servers)
|
|
self.members = members
|
|
for member in self.members:
|
|
member.linux_bridge_name = name
|
|
member.ovs_port = False
|
|
if member.primary:
|
|
if self.primary_interface_name:
|
|
msg = 'Only one primary interface allowed per bridge.'
|
|
raise InvalidConfigException(msg)
|
|
if member.primary_interface_name:
|
|
self.primary_interface_name = member.primary_interface_name
|
|
else:
|
|
self.primary_interface_name = member.name
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = _get_required_field(json, 'name', 'LinuxBridge')
|
|
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers) = _BaseOpts.base_opts_from_json(
|
|
json, include_primary=False)
|
|
members = []
|
|
|
|
# members
|
|
members_json = json.get('members')
|
|
if members_json:
|
|
if isinstance(members_json, list):
|
|
for member in members_json:
|
|
members.append(object_from_json(member))
|
|
else:
|
|
msg = 'Members must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
return LinuxBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
|
addresses=addresses, routes=routes, mtu=mtu,
|
|
members=members, nic_mapping=nic_mapping,
|
|
persist_mapping=persist_mapping, defroute=defroute,
|
|
dhclient_args=dhclient_args,
|
|
dns_servers=dns_servers)
|
|
|
|
|
|
class IvsBridge(_BaseOpts):
|
|
"""Base class for IVS bridges.
|
|
|
|
Indigo Virtual Switch (IVS) is a virtual switch for Linux.
|
|
It is compatible with the KVM hypervisor and leveraging the
|
|
Open vSwitch kernel module for packet forwarding. There are
|
|
three major differences between IVS and OVS:
|
|
1. Each node can have at most one ivs, no name required.
|
|
2. Bond is not allowed to attach to an ivs. It is the SDN
|
|
controller's job to dynamically form bonds on ivs.
|
|
3. IP address can only be statically assigned.
|
|
"""
|
|
|
|
def __init__(self, name='ivs', use_dhcp=False, use_dhcpv6=False,
|
|
addresses=None, routes=None, mtu=1500, members=None,
|
|
nic_mapping=None, persist_mapping=False, defroute=True,
|
|
dhclient_args=None, dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
members = members or []
|
|
dns_servers = dns_servers or []
|
|
super(IvsBridge, self).__init__(name, use_dhcp, use_dhcpv6,
|
|
addresses, routes, mtu, False,
|
|
nic_mapping, persist_mapping,
|
|
defroute, dhclient_args, dns_servers)
|
|
self.members = members
|
|
for member in self.members:
|
|
if isinstance(member, OvsBond) or isinstance(member, LinuxBond):
|
|
msg = 'IVS does not support bond interfaces.'
|
|
raise InvalidConfigException(msg)
|
|
member.ivs_bridge_name = name
|
|
member.ovs_port = False
|
|
self.primary_interface_name = None # ivs doesn't use primary intf
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = 'ivs'
|
|
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers) = _BaseOpts.base_opts_from_json(
|
|
json, include_primary=False)
|
|
members = []
|
|
|
|
# members
|
|
members_json = json.get('members')
|
|
if members_json:
|
|
if isinstance(members_json, list):
|
|
for member in members_json:
|
|
members.append(object_from_json(member))
|
|
else:
|
|
msg = 'Members must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
return IvsBridge(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
|
addresses=addresses, routes=routes, mtu=mtu,
|
|
members=members, nic_mapping=nic_mapping,
|
|
persist_mapping=persist_mapping, defroute=defroute,
|
|
dhclient_args=dhclient_args,
|
|
dns_servers=dns_servers)
|
|
|
|
|
|
class LinuxBond(_BaseOpts):
|
|
"""Base class for Linux bonds."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, primary=False, members=None,
|
|
bonding_options=None, nic_mapping=None, persist_mapping=False,
|
|
defroute=True, dhclient_args=None, dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
members = members or []
|
|
dns_servers = dns_servers or []
|
|
super(LinuxBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
|
routes, mtu, primary, nic_mapping,
|
|
persist_mapping, defroute,
|
|
dhclient_args, dns_servers)
|
|
self.members = members
|
|
self.bonding_options = bonding_options
|
|
for member in self.members:
|
|
if member.primary:
|
|
if self.primary_interface_name:
|
|
msg = 'Only one primary interface allowed per bond.'
|
|
raise InvalidConfigException(msg)
|
|
if member.primary_interface_name:
|
|
self.primary_interface_name = member.primary_interface_name
|
|
else:
|
|
self.primary_interface_name = member.name
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = _get_required_field(json, 'name', 'LinuxBond')
|
|
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers) = _BaseOpts.base_opts_from_json(
|
|
json, include_primary=False)
|
|
bonding_options = json.get('bonding_options')
|
|
members = []
|
|
|
|
# members
|
|
members_json = json.get('members')
|
|
if members_json:
|
|
if isinstance(members_json, list):
|
|
for member in members_json:
|
|
members.append(object_from_json(member))
|
|
else:
|
|
msg = 'Members must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
return LinuxBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
|
addresses=addresses, routes=routes, mtu=mtu,
|
|
members=members, bonding_options=bonding_options,
|
|
nic_mapping=nic_mapping,
|
|
persist_mapping=persist_mapping, defroute=defroute,
|
|
dhclient_args=dhclient_args, dns_servers=dns_servers)
|
|
|
|
|
|
class OvsBond(_BaseOpts):
|
|
"""Base class for OVS bonds."""
|
|
|
|
def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
|
|
routes=None, mtu=None, primary=False, members=None,
|
|
ovs_options=None, ovs_extra=None, nic_mapping=None,
|
|
persist_mapping=False, defroute=True, dhclient_args=None,
|
|
dns_servers=None):
|
|
addresses = addresses or []
|
|
routes = routes or []
|
|
members = members or []
|
|
ovs_extra = ovs_extra or []
|
|
dns_servers = dns_servers or []
|
|
super(OvsBond, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
|
|
routes, mtu, primary, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers)
|
|
self.members = members
|
|
self.ovs_options = ovs_options
|
|
self.ovs_extra = ovs_extra
|
|
for member in self.members:
|
|
if member.primary:
|
|
if self.primary_interface_name:
|
|
msg = 'Only one primary interface allowed per bond.'
|
|
raise InvalidConfigException(msg)
|
|
if member.primary_interface_name:
|
|
self.primary_interface_name = member.primary_interface_name
|
|
else:
|
|
self.primary_interface_name = member.name
|
|
if not self.primary_interface_name:
|
|
bond_members = list(self.members)
|
|
bond_members.sort(key=lambda x: x.name)
|
|
self.primary_interface_name = bond_members[0].name
|
|
|
|
@staticmethod
|
|
def from_json(json):
|
|
name = _get_required_field(json, 'name', 'OvsBond')
|
|
(use_dhcp, use_dhcpv6, addresses, routes, mtu, nic_mapping,
|
|
persist_mapping, defroute, dhclient_args,
|
|
dns_servers) = _BaseOpts.base_opts_from_json(
|
|
json, include_primary=False)
|
|
ovs_options = json.get('ovs_options')
|
|
ovs_extra = json.get('ovs_extra', [])
|
|
members = []
|
|
|
|
# members
|
|
members_json = json.get('members')
|
|
if members_json:
|
|
if isinstance(members_json, list):
|
|
for member in members_json:
|
|
members.append(object_from_json(member))
|
|
else:
|
|
msg = 'Members must be a list.'
|
|
raise InvalidConfigException(msg)
|
|
|
|
return OvsBond(name, use_dhcp=use_dhcp, use_dhcpv6=use_dhcpv6,
|
|
addresses=addresses, routes=routes, mtu=mtu,
|
|
members=members, ovs_options=ovs_options,
|
|
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
|
|
persist_mapping=persist_mapping, defroute=defroute,
|
|
dhclient_args=dhclient_args, dns_servers=dns_servers)
|