Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ dist/
.vscode
.bak
.pyo

.idea
7 changes: 4 additions & 3 deletions debinterface/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
"""Imports for easier use"""
from .adapter import NetworkAdapter
from .adapterValidation import NetworkAdapterValidation
from .dnsmasqRange import (DnsmasqRange,
DEFAULT_CONFIG as DNSMASQ_DEFAULT_CONFIG)
from .dnsmasqRange import (DEFAULT_CONFIG as DNSMASQ_DEFAULT_CONFIG, DnsmasqRange)
from .hostapd import Hostapd
from .interfaces import Interfaces
from .interfacesReader import InterfacesReader
from .interfacesValidation import InterfacesValidation
from .interfacesWriter import InterfacesWriter

__version__ = '3.5.0'
__version__ = '3.6.0'

__all__ = [
'NetworkAdapter',
Expand All @@ -18,6 +18,7 @@
'DNSMASQ_DEFAULT_CONFIG',
'Hostapd',
'Interfaces',
'InterfacesValidation',
'InterfacesReader',
'InterfacesWriter'
]
108 changes: 107 additions & 1 deletion debinterface/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
It has setter for many common options, but it is impossible to have setter for
every options on earth !
"""
from __future__ import print_function, with_statement, absolute_import
from __future__ import absolute_import, print_function, with_statement

import copy
import socket
import warnings

from .adapterValidation import NetworkAdapterValidation, VALID_OPTS

try:
import typing as tp
except ImportError:
Expand Down Expand Up @@ -483,10 +484,108 @@ def appendPostDown(self, cmd):
cmd = cmd.split()
self._ensure_list(self._ifAttributes, "post-down", cmd)

def setBondMaster(self, master_adapter_name):
# type: (str)->None
"""Set bond-master reference on slave.

Args:
master_adapter_name (str): name of master iface
"""
self._ifAttributes['bond-master'] = master_adapter_name

def setBondMode(self, mode):
# type: (tp.Union[str, int])->None
"""Set bond-mode.

Args:
mode (str, int): mode of bonding
"""
if isinstance(mode, str):
mode = mode.lower().replace('_', '-')
self._ifAttributes['bond-mode'] = mode

def setBondMiimon(self, miimon):
# type: (int)->None
"""Set bond-miimon parameter.
Specifies the MII link monitoring frequency in milliseconds.

Args:
miimon (int): miimon
"""
self._ifAttributes['bond-miimon'] = miimon

def setBondUpDelay(self, delay):
# type: (int)->None
"""Set bond-updelay parameter.
Specifies the time, in milliseconds, to wait before enabling a slave after a link recovery has been detected.
This option is only valid for the miimon link monitor. The updelay value should be a multiple of the miimon value.

Args:
delay (int): delay in milliseconds
"""
miimon = self._ifAttributes.get('bond-miimon', 0)
if miimon and delay % miimon != 0:
raise ValueError("Updelay should be multiple of miimon value")
self._ifAttributes['bond-updelay'] = delay

def setBondDownDelay(self, delay):
# type: (int)->None
"""Set bond-downdelay parameter.
Specifies the time, in milliseconds, to wait before disabling a slave after a link failure has been detected.
This option is only valid for the miimon link monitor. The updelay value should be a multiple of the miimon value.

Args:
delay (int): delay in milliseconds
"""
miimon = self._ifAttributes.get('bond-miimon', 0)
if miimon and delay % miimon != 0:
raise ValueError("Downdelay should be multiple of miimon value")
self._ifAttributes['bond-downdelay'] = delay

def setBondPrimary(self, primary_name):
# type: (str)->None
"""Set bond-primary parameter.
A string specifying which slave is the primary device.
The specified device will always be the active slave while it is available.
Only when the primary is off-line will alternate devices be used.
This is useful when one slave is preferred over another, e.g., when one slave has higher throughput than another.
The primary option is only valid for active-backup (1) mode.

Args:
primary_name (str): name of primary slave
"""
self._ifAttributes['bond-primary'] = primary_name

def setBondSlaves(self, slaves):
# type: (tp.Union[str, tp.List[str]])->None
"""Set bond-primary parameter.
Slave interfaces names

Args:
slaves (list, optional): names of slaves
"""
if not isinstance(slaves, list):
slaves = [slaves]
self._ifAttributes['bond-slaves'] = slaves

def setUnknown(self, key, val):
# type: (str, tp.Any)->None
"""Stores uncommon options as there are with no special handling
It's impossible to know about all available options
Format key with lower case. Replaces '_' with '-'

Args:
key (str): the option name
val (any): the option value
"""
key = key.lower().replace('_', '-')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about that one ? It may break a keyword ?

Copy link
Collaborator Author

@ObjatieGroba ObjatieGroba Mar 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not break keyword. As NetworkManager sources says:

Normalize keys. Convert '_' to '-', as ifupdown accepts both variants.

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/blob/master/src/core/settings/plugins/ifupdown/nms-ifupdown-interface-parser.c#L76

Copy link
Collaborator Author

@ObjatieGroba ObjatieGroba Mar 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sources of ifupdown cast all attr names into UPPER_SNAKE_CASE and accept any variants - lower or upper, '-' or '_' before writing it into OS

https://salsa.debian.org/debian/ifupdown/-/blob/master/execute.c#L41

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

@ObjatieGroba ObjatieGroba Mar 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But there are some options that should be this-case and neither another cases:

https://salsa.debian.org/debian/ifupdown/-/blob/master/config.c#L733

That's why I suggest to do such transformation

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanations !

self.setUnknownUnformatted(key, val)

def setUnknownUnformatted(self, key, val):
# type: (str, tp.Any)->None
"""Stores uncommon options as there are with no special handling
It's impossible to know about all available options
Stores key as is
WARNING: duplicated directives are overwriten. TODO better

Args:
Expand Down Expand Up @@ -607,6 +706,13 @@ def set_options(self, options):
'dns-search': self.setDnsSearch,
'nameservers': self.setNameservers,
'wpa-conf': self.setWpaConf,
'bond-master': self.setBondMaster,
'bond-slaves': self.setBondSlaves,
'bond-miimon': self.setBondMiimon,
'bond-mode': self.setBondMode,
'bond-updelay': self.setBondUpDelay,
'bond-downdelay': self.setBondDownDelay,
'bond-primary': self.setBondPrimary
} # type: tp.Dict[str, tp.Callable[[tp.Any], None]]
for key, value in options.items():
if key in roseta:
Expand Down
15 changes: 11 additions & 4 deletions debinterface/adapterValidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
but it is by no means fool proof as it is impossible to have checks
for everything as any package can add its keys.
"""
from __future__ import print_function, with_statement, absolute_import
from __future__ import absolute_import, print_function, with_statement

import socket

try:
import typing as tp
except ImportError:
pass


VALID_OPTS = {
'hotplug': {'type': bool}, # Beware, option is really called allow-hotplug
'auto': {'type': bool},
Expand Down Expand Up @@ -54,7 +55,13 @@
'post-up': {'type': list},
'down': {'type': list},
'pre-down': {'type': list},
'post-down': {'type': list}
'post-down': {'type': list},
'bond-mode': {
'in': ['balance-rr', 'active-backup', 'balance-xor', 'broadcast', '802.3ad', 'balance-tlb', 'balance-alb', 0, 1,
2, 3, 4, 5, 6]},
'bond-miimon': {'type': int},
'bond-updelay': {'type': int},
'bond-downdelay': {'type': int}
} # type: tp.Dict[str, tp.Dict[str, tp.Any]]
REQUIRED_FAMILY_OPTS = {
"inet": {
Expand All @@ -81,7 +88,7 @@
"static": (),
"manual": (),
"dhcp": (),
"v4tunnel": ("address", ),
"v4tunnel": ("address",),
"6to4": ()
},
"can": {
Expand Down
5 changes: 3 additions & 2 deletions debinterface/dnsmasqRange.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, with_statement, absolute_import
from __future__ import absolute_import, print_function, with_statement

import copy
import os
import shutil
from socket import inet_aton

from . import toolutils

try:
import typing as tp
except ImportError:
pass


DEFAULT_CONFIG = {
'dhcp-range': [
{
Expand Down
4 changes: 3 additions & 1 deletion debinterface/hostapd.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# -*- coding: utf-8 -*-
from __future__ import print_function, with_statement, absolute_import
from __future__ import absolute_import, print_function, with_statement

import os
import shutil

from . import toolutils

try:
import typing as tp
except ImportError:
Expand Down
39 changes: 35 additions & 4 deletions debinterface/interfaces.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# -*- coding: utf-8 -*-
# A class representing the contents of /etc/network/interfaces
from __future__ import print_function, with_statement, absolute_import
from .interfacesWriter import InterfacesWriter
from .interfacesReader import InterfacesReader
from .adapter import NetworkAdapter
from __future__ import absolute_import, print_function, with_statement

from . import toolutils
from .adapter import NetworkAdapter
from .interfacesReader import InterfacesReader
from .interfacesWriter import InterfacesWriter

try:
import typing as tp
except ImportError:
Expand Down Expand Up @@ -198,3 +200,32 @@ def _set_paths(self, interfaces_path, backup_path):
else:
# self._interfaces_path is never None
self._backup_path = self._interfaces_path + ".bak"

def addBond(self, name="bond0", mode=0, slaves=None):
# type: (str, tp.Union[str, int], tp.Union[None, str, tp.List[str]])->NetworkAdapter
"""Add new bond interface

Args:
name (str): name of new interfaces
mode (str/int): mode of bonding
slaves (list, optional): list of names of bond slaves

Returns:
NetworkAdapter: the new adapter
"""
if not slaves:
slaves = []

if self.getAdapter(name) is not None:
raise ValueError("Interface {} already exists".format(name))

for slave in slaves:
adapter = self.getAdapter(slave)
if adapter is None:
raise ValueError("Interface {} does not exists".format(slave))
if 'bond-master' in adapter.attributes and adapter.attributes['bond-master'] != name:
raise ValueError(
"Interface {} already has master iface {}".format(slave, adapter.attributes['bond-master']))
adapter.attributes['bond-master'] = name

return self.addAdapter({"name": name, 'bond-mode': mode, 'bond-slaves': ' '.join(slaves)})
26 changes: 25 additions & 1 deletion debinterface/interfacesReader.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
# -*- coding: utf-8 -*-
# A class representing the contents of /etc/network/interfaces
from __future__ import print_function, with_statement, absolute_import
from __future__ import absolute_import, print_function, with_statement

import os

from .adapter import NetworkAdapter

try:
import typing as tp
except ImportError:
Expand Down Expand Up @@ -118,6 +121,8 @@ def _parse_details(self, line):
if line[0].isspace() is True:
keyword, value = line.strip().split(None, 1)

keyword = keyword.lower().replace('_', '-')

if keyword == 'address':
self._adapters[self._context].setAddress(value)
elif keyword == 'netmask':
Expand All @@ -132,6 +137,25 @@ def _parse_details(self, line):
self._adapters[self._context].setHostapd(value)
elif keyword == 'wpa-conf':
self._adapters[self._context].setWpaConf(value)
elif keyword == 'bond-mode':
mode = value # type: tp.Union[str, int]
try:
mode = int(mode)
except ValueError:
pass
self._adapters[self._context].setBondMode(mode)
elif keyword == 'bond-miimon':
self._adapters[self._context].setBondMiimon(int(value))
elif keyword == 'bond-updelay':
self._adapters[self._context].setBondUpDelay(int(value))
elif keyword == 'bond-downdelay':
self._adapters[self._context].setBondDownDelay(int(value))
elif keyword == 'bond-primary':
self._adapters[self._context].setBondPrimary(value)
elif keyword == 'bond-master':
self._adapters[self._context].setBondMaster(value)
elif keyword == 'bond-slaves':
self._adapters[self._context].setBondSlaves(value.split())
elif keyword == 'dns-nameservers':
self._adapters[self._context].setDnsNameservers(value)
elif keyword == 'dns-search':
Expand Down
Loading