Vlan ui
This commit is contained in:
parent
173eac79a5
commit
92c53b29ae
|
@ -237,6 +237,21 @@ class NetworkController(BaseController, TaskWatcher):
|
||||||
netplan_config_file_name = '00-snapd-config.yaml'
|
netplan_config_file_name = '00-snapd-config.yaml'
|
||||||
return os.path.join(self.root, 'etc/netplan', netplan_config_file_name)
|
return os.path.join(self.root, 'etc/netplan', netplan_config_file_name)
|
||||||
|
|
||||||
|
def add_vlan(self, device, vlan):
|
||||||
|
cmd = ['ip', 'link', 'add', 'name', '%s.%s' % (device.name, vlan),
|
||||||
|
'link', device.name, 'type', 'vlan', 'id', str(vlan)]
|
||||||
|
try:
|
||||||
|
run_command(cmd, check=True)
|
||||||
|
except:
|
||||||
|
self.ui.frame.body.show_network_error('add-vlan')
|
||||||
|
|
||||||
|
def rm_virtual_interface(self, device):
|
||||||
|
cmd = ['ip', 'link', 'delete', 'dev', device.name]
|
||||||
|
try:
|
||||||
|
run_command(cmd, check=True)
|
||||||
|
except:
|
||||||
|
self.ui.frame.body.show_network_error('rm-dev')
|
||||||
|
|
||||||
def network_finish(self, config):
|
def network_finish(self, config):
|
||||||
log.debug("network config: \n%s",
|
log.debug("network config: \n%s",
|
||||||
yaml.dump(sanitize_config(config), default_flow_style=False))
|
yaml.dump(sanitize_config(config), default_flow_style=False))
|
||||||
|
|
|
@ -23,6 +23,7 @@ from subiquitycore import netplan
|
||||||
|
|
||||||
NETDEV_IGNORED_IFACE_NAMES = ['lo']
|
NETDEV_IGNORED_IFACE_NAMES = ['lo']
|
||||||
NETDEV_IGNORED_IFACE_TYPES = ['bridge', 'tun', 'tap', 'dummy', 'sit']
|
NETDEV_IGNORED_IFACE_TYPES = ['bridge', 'tun', 'tap', 'dummy', 'sit']
|
||||||
|
NETDEV_WHITELIST_IFACE_TYPES = ['vlan']
|
||||||
log = logging.getLogger('subiquitycore.models.network')
|
log = logging.getLogger('subiquitycore.models.network')
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,6 +46,11 @@ class Networkdev:
|
||||||
def __init__(self, net_info, configuration):
|
def __init__(self, net_info, configuration):
|
||||||
self._net_info = net_info
|
self._net_info = net_info
|
||||||
self._configuration = configuration
|
self._configuration = configuration
|
||||||
|
if self.type == 'vlan':
|
||||||
|
# probably should parse /proc/self/net/vlan/config instead
|
||||||
|
link, vid = self.name.split('.')
|
||||||
|
self._configuration['id'] = int(vid)
|
||||||
|
self._configuration['link'] = link
|
||||||
|
|
||||||
def render(self):
|
def render(self):
|
||||||
if self.configured_ip_addresses or self.dhcp4 or self.dhcp6:
|
if self.configured_ip_addresses or self.dhcp4 or self.dhcp6:
|
||||||
|
@ -98,6 +104,10 @@ class Networkdev:
|
||||||
def is_bonded(self):
|
def is_bonded(self):
|
||||||
return self.is_bond_master or self.is_bond_slave
|
return self.is_bond_master or self.is_bond_slave
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_virtual(self):
|
||||||
|
return self._net_info.is_virtual
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speed(self):
|
def speed(self):
|
||||||
'''string'ify and bucketize iface speed:
|
'''string'ify and bucketize iface speed:
|
||||||
|
@ -337,7 +347,7 @@ class NetworkModel(object):
|
||||||
return
|
return
|
||||||
if link.name in NETDEV_IGNORED_IFACE_NAMES:
|
if link.name in NETDEV_IGNORED_IFACE_NAMES:
|
||||||
return
|
return
|
||||||
if link.is_virtual:
|
if link.is_virtual and link.type not in NETDEV_WHITELIST_IFACE_TYPES:
|
||||||
return
|
return
|
||||||
config = self.config.config_for_device(link)
|
config = self.config.config_for_device(link)
|
||||||
log.debug("new_link %s %s with config %s",
|
log.debug("new_link %s %s with config %s",
|
||||||
|
@ -465,6 +475,7 @@ class NetworkModel(object):
|
||||||
ethernets = {}
|
ethernets = {}
|
||||||
bonds = {}
|
bonds = {}
|
||||||
wifis = {}
|
wifis = {}
|
||||||
|
vlans = {}
|
||||||
for dev in self.devices.values():
|
for dev in self.devices.values():
|
||||||
if dev.type == 'eth':
|
if dev.type == 'eth':
|
||||||
ethernets.update(dev.render())
|
ethernets.update(dev.render())
|
||||||
|
@ -472,12 +483,16 @@ class NetworkModel(object):
|
||||||
bonds.update(dev.render())
|
bonds.update(dev.render())
|
||||||
if dev.type == 'wlan':
|
if dev.type == 'wlan':
|
||||||
wifis.update(dev.render())
|
wifis.update(dev.render())
|
||||||
|
if dev.type == 'vlan':
|
||||||
|
vlans.update(dev.render())
|
||||||
if any(ethernets):
|
if any(ethernets):
|
||||||
config['network']['ethernets'] = ethernets
|
config['network']['ethernets'] = ethernets
|
||||||
if any(bonds):
|
if any(bonds):
|
||||||
config['network']['bonds'] = bonds
|
config['network']['bonds'] = bonds
|
||||||
if any(wifis):
|
if any(wifis):
|
||||||
config['network']['wifis'] = wifis
|
config['network']['wifis'] = wifis
|
||||||
|
if any(vlans):
|
||||||
|
config['network']['vlans'] = vlans
|
||||||
|
|
||||||
nw_routes = []
|
nw_routes = []
|
||||||
if self.default_v4_gateway:
|
if self.default_v4_gateway:
|
||||||
|
|
|
@ -44,7 +44,7 @@ from subiquitycore.ui.utils import (
|
||||||
make_action_menu_row,
|
make_action_menu_row,
|
||||||
Padding,
|
Padding,
|
||||||
)
|
)
|
||||||
from .network_configure_manual_interface import EditNetworkStretchy
|
from .network_configure_manual_interface import EditNetworkStretchy, AddVlanStretchy
|
||||||
from .network_configure_wlan_interface import NetworkConfigureWLANStretchy
|
from .network_configure_wlan_interface import NetworkConfigureWLANStretchy
|
||||||
|
|
||||||
from subiquitycore.view import BaseView
|
from subiquitycore.view import BaseView
|
||||||
|
@ -149,6 +149,12 @@ class NetworkView(BaseView):
|
||||||
def _action_edit_ipv6(self, device):
|
def _action_edit_ipv6(self, device):
|
||||||
self.show_stretchy_overlay(EditNetworkStretchy(self, device, 6))
|
self.show_stretchy_overlay(EditNetworkStretchy(self, device, 6))
|
||||||
|
|
||||||
|
def _action_add_vlan(self, device):
|
||||||
|
self.show_stretchy_overlay(AddVlanStretchy(self, device))
|
||||||
|
|
||||||
|
def _action_rm_dev(self, device):
|
||||||
|
self.controller.rm_virtual_interface(device)
|
||||||
|
|
||||||
def _action(self, sender, action, device):
|
def _action(self, sender, action, device):
|
||||||
m = getattr(self, '_action_{}'.format(action))
|
m = getattr(self, '_action_{}'.format(action))
|
||||||
m(device)
|
m(device)
|
||||||
|
@ -199,6 +205,10 @@ class NetworkView(BaseView):
|
||||||
("Edit IPv4", True, 'edit_ipv4', True),
|
("Edit IPv4", True, 'edit_ipv4', True),
|
||||||
("Edit IPv6", True, 'edit_ipv6', True),
|
("Edit IPv6", True, 'edit_ipv6', True),
|
||||||
]
|
]
|
||||||
|
if dev.type != 'vlan':
|
||||||
|
actions.append((_("Add a VLAN tag"), True, 'add_vlan', True))
|
||||||
|
if dev.is_virtual:
|
||||||
|
actions.append((_("Delete"), True, 'rm_dev', True))
|
||||||
menu = ActionMenu(actions)
|
menu = ActionMenu(actions)
|
||||||
connect_signal(menu, 'action', self._action, dev)
|
connect_signal(menu, 'action', self._action, dev)
|
||||||
rows.append(make_action_menu_row([
|
rows.append(make_action_menu_row([
|
||||||
|
@ -244,6 +254,10 @@ class NetworkView(BaseView):
|
||||||
self.error.set_text("Downing network interfaces failed.")
|
self.error.set_text("Downing network interfaces failed.")
|
||||||
elif action == 'canceled':
|
elif action == 'canceled':
|
||||||
self.error.set_text("Network configuration canceled.")
|
self.error.set_text("Network configuration canceled.")
|
||||||
|
elif action == 'add-vlan':
|
||||||
|
self.error.set_text("Failed to add a VLAN tag.")
|
||||||
|
elif action == 'rm-dev':
|
||||||
|
self.error.set_text("Failed to delete a virtual interface.")
|
||||||
else:
|
else:
|
||||||
self.error.set_text("An unexpected error has occurred; "
|
self.error.set_text("An unexpected error has occurred; "
|
||||||
"please verify your settings.")
|
"please verify your settings.")
|
||||||
|
|
|
@ -235,3 +235,48 @@ class EditNetworkStretchy(Stretchy):
|
||||||
|
|
||||||
def cancel(self, sender=None):
|
def cancel(self, sender=None):
|
||||||
self.parent.remove_overlay()
|
self.parent.remove_overlay()
|
||||||
|
|
||||||
|
class VlanForm(Form):
|
||||||
|
|
||||||
|
def __init__(self, parent, device):
|
||||||
|
self.parent = parent
|
||||||
|
self.device = device
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
vlan = StringField(_("VLAN ID:"))
|
||||||
|
|
||||||
|
def clean_vlan(self, value):
|
||||||
|
try:
|
||||||
|
vlanid = int(value)
|
||||||
|
except ValueError:
|
||||||
|
vlanid = None
|
||||||
|
if vlanid is None or vlanid < 1 or vlanid > 4095:
|
||||||
|
raise ValueError(
|
||||||
|
_("VLAN ID must be between 1 and 4095"))
|
||||||
|
return vlanid
|
||||||
|
|
||||||
|
def validate_vlan(self):
|
||||||
|
new_name = '%s.%s' % (self.device.name, self.vlan.value)
|
||||||
|
if new_name in self.parent.model.devices_by_name:
|
||||||
|
return _("%s already exists") % new_name
|
||||||
|
|
||||||
|
|
||||||
|
class AddVlanStretchy(Stretchy):
|
||||||
|
|
||||||
|
def __init__(self, parent, device):
|
||||||
|
self.parent = parent
|
||||||
|
self.device = device
|
||||||
|
self.form = VlanForm(parent, device)
|
||||||
|
connect_signal(self.form, 'submit', self.done)
|
||||||
|
connect_signal(self.form, 'cancel', self.cancel)
|
||||||
|
super().__init__(
|
||||||
|
_('Add a VLAN tag'),
|
||||||
|
[Pile(self.form.as_rows()), Text(""), self.form.buttons],
|
||||||
|
0, 0)
|
||||||
|
|
||||||
|
def done(self, sender):
|
||||||
|
self.parent.remove_overlay()
|
||||||
|
self.parent.controller.add_vlan(self.device, self.form.vlan.value)
|
||||||
|
|
||||||
|
def cancel(self, sender=None):
|
||||||
|
self.parent.remove_overlay()
|
||||||
|
|
Loading…
Reference in New Issue