Skip to content
Merged
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
28 changes: 28 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]


## [2.35.1] - 2026-03-06
### Added
- [API_PARSER] Add api_collector parameters in the returned representation of Frontends through APIs
### Changed
- [APPLICATIONS] [LOGOMHIREDIS] Use new raw_message_nolf template to send logs without newline added
- [DEPENDENCIES]
- aiohappyeyeballs 2.4.4 -> 2.6.1
- aiohttp 3.10.5 -> 3.13.3
- aiosignal 1.3.1 -> 1.4.0
- botocore 1.34.55 -> 1.34.162
- cryptography 44.0.2 -> 44.0.3
- django 4.2.26 -> 4.2.28
- pillow 10.3.0 -> 12.1.1
- propcache (added) 0.4.1
- pyasn1 0.5.1 -> 0.6.2
- pyasn1-modules 0.3.0 -> 0.4.2
- sqlparse 0.5.3 -> 0.5.5
- urllib3 2.0.7 -> 2.6.3
- yarl 1.9.4 -> 1.22.0
- python-ldap 3.4.4 -> 3.4.5
- werkzeug 3.1.3 -> 3.1.5
### Fixed
- [NETWORK] Improve rc.conf networking lines' parsing patterns
- [GUI] [JS] Avoid DOM-based XSS (and silence JS scanner's false positives...)
- [API_PARSER] Fix a bug preventing to create/update frontend through APIs
- [API_PARSER] Fix possibility of multiple running instances of a collector


## [2.35.0] - 2026-02-06
### Added
- [SETTINGS] Allow importing custom and optional modules to the Django project
Expand Down
169 changes: 15 additions & 154 deletions home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,61 +22,44 @@
It is call whenever a sysadmin calls bsdinstall netconfig from the vlt-adm menu
"""

import sys

Check failure on line 25 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:25:1: E402 Module level import not at top of file
import os

Check failure on line 26 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:26:1: E402 Module level import not at top of file

# Django setup part
sys.path.append('/home/vlt-os/vulture_os')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", 'vulture_os.settings')

import django

Check failure on line 32 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:32:1: E402 Module level import not at top of file
from django.conf import settings

Check failure on line 33 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:33:1: E402 Module level import not at top of file
django.setup()

from system.cluster.models import (Cluster, NetworkInterfaceCard,
NetworkAddress, NetworkAddressNIC)

Check failure on line 37 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:36:1: E402 Module level import not at top of file


from toolkit.network.network import (
PATTERN_IFACE_NAME,
PATTERN_IFCONFIG,
parse_ifconfig_key,
parse_ifconfig_values,
parse_gateway_config
)

Check failure on line 45 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:39:1: E402 Module level import not at top of file

import logging

Check failure on line 47 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:47:1: E402 Module level import not at top of file
logging.config.dictConfig(settings.LOG_SETTINGS)
logger = logging.getLogger('daemon')

import re

Check failure on line 51 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:51:1: E402 Module level import not at top of file
import subprocess

Check failure on line 52 in home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py

View workflow job for this annotation

GitHub Actions / check

Ruff (E402)

home/jails.apache/.zfs-source/home/vlt-os/scripts/net2mongo.py:52:1: E402 Module level import not at top of file

PATTERN_IFCONFIG = re.compile('^ifconfig_(.*)="?\'?([^"\']*)"?\'?')
PATTERN_GATEWAY = re.compile("^defaultrouter=(.*)")
PATTERN_GATEWAY6 = re.compile("^ipv6_defaultrouter=(.*)")
# Handles almost all types of IPv6 formats
PATTERN_INET6 = re.compile(r"(inet6 )?(.* )?(((([0-9A-Fa-f]{1,4}:){1,6}:)|(([0-9A-Fa-f]{1,4}:){7}))([0-9A-Fa-f]{1,4}))(( prefixlen )|(/))([0-9\.]{1,3})")
PATTERN_INET = re.compile(r"(inet )?(.* )?(([0-9]{1,3}\.){3}[0-9]{1,3})(( netmask )|(\/))([0-9\.]{1,2})( .*)?")
# Correct group number for the pattern matches above, to get IP/prefix from it
# WARNING change those groups if you change the patterns above!
PATTERN_INET_IP_GROUP = 3
PATTERN_INET_PREFIX_OR_NETMASK_GROUP = 8
PATTERN_INET6_IP_GROUP = 3
PATTERN_INET6_PREFIX_OR_NETMASK_GROUP = 13
PATTERN_ALIAS = re.compile(r"( |^)alias( |$)")
PATTERN_IFACE_NAME = re.compile("([a-z]+)([0-9]+)")
PATTERN_VLAN = re.compile("vlan ([0-9]+)")
PATTERN_VLANDEV = re.compile("vlandev ([a-z0-9\.]+)")
PATTERN_LAGGPROTO = re.compile("laggproto ([a-z]+)")
PATTERN_LAGGPORT = re.compile("laggport ([a-z0-9]+)")
PATTERN_CARP_VHID = re.compile(r"( |^)vhid ([0-9]+)( |$)")
PATTERN_CARP_ADVSKEW = re.compile(r"( |^)advskew ([0-9]+)( |$)")
PATTERN_CARP_PASS = re.compile(r"( |^)pass ([0-9a-zA-Z]+)( |$)")
PATTERN_FIB = re.compile("fib ([0-9])")

def refresh_physical_NICs(node):
""" Get physical NICs """
# Remove all 'unused' interfaces (may be reimported with the next for loop)
deletion_list = NetworkInterfaceCard.objects.filter(networkaddressnic=None, networkaddress=None, node=node)
for to_delete in deletion_list:
iface_name_match = re.search(PATTERN_IFACE_NAME, to_delete.dev)
if iface_name_match:
name = iface_name_match.group(1)
iface_id = iface_name_match.group(2)
name = iface_name_match.group("name")
iface_id = iface_name_match.group("id")
# Only remove interfaces that cannot represent a NetworkAddress
if not NetworkAddress.objects.filter(type=name, iface_id=iface_id).exists():
logger.info(f"Node::refresh_physical_NICs: Deleting obsolete interface {to_delete.dev}")
Expand All @@ -89,7 +72,7 @@
d, created = NetworkInterfaceCard.objects.get_or_create(
dev=nic,
node=node)
if created:
if not created:
logger.debug("Node::refresh_physical_NICs: NIC {} exists in database".format(d.dev))
else:
logger.info("Node::refresh_physical_NICs: Creating NIC {}".format(nic))
Expand All @@ -98,128 +81,6 @@
logger.exception(e)


def parse_ifconfig_key(line, config):
split = line.split("_")

if len(split) > 3:
logger.error(f"Node::parse_ifconfig_key: could not parse line '{line}',"
" problem is on '{tmp}' (too many '_', don't know how to read)")
return False

if "ipv6" in split:
split.remove('ipv6')
config['ipv6'] = True
config['family'] = 'inet6'
else:
config['family'] = 'inet'

if "alias" in split[-1]:
logger.debug("Node::parse_ifconfig_key: line is an alias")
config['nic'] = [split[0]]
config['type'] = 'alias'

iface_name_match = re.search(PATTERN_IFACE_NAME, split[-1])
if not iface_name_match:
return False

config['name'] = iface_name_match.group(1)
config['iface_id'] = iface_name_match.group(2)
if config['name'] == 'vlan':
logger.debug("Node::parse_ifconfig_key: line is a vlan configuration")
config['type'] = 'vlan'
if config['name'] == 'lagg':
logger.debug("Node::parse_ifconfig_key: line is a lagg configuration")
config['type'] = 'lagg'

return True


def parse_ifconfig_values(line, config):
parse_success = False

if line.upper() in ['DHCP', 'SYNCDHCP']:
logger.debug("Node::parse_ifconfig_values: interface is configured for DHCP")
config['dhcp'] = True
config['type'] = "system"
return True

if config.get('ipv6'):
pattern = PATTERN_INET6
ip_group = PATTERN_INET_IP_GROUP
prefix_or_netmask_group = PATTERN_INET6_PREFIX_OR_NETMASK_GROUP
else:
pattern = PATTERN_INET
ip_group = PATTERN_INET6_IP_GROUP
prefix_or_netmask_group = PATTERN_INET_PREFIX_OR_NETMASK_GROUP

inet_match = re.search(pattern, line)
if inet_match:
logger.debug("Node::parse_ifconfig_values: interface has an IP")
parse_success = True
config['ip'] = inet_match.group(ip_group)
logger.debug(f"Node::parse_ifconfig_values: IP {inet_match.group(ip_group)}")
config['prefix_or_netmask'] = inet_match.group(prefix_or_netmask_group)
if 'type' not in config:
if re.search(PATTERN_ALIAS, line):
config['type'] = 'alias'
else:
config['type'] = 'system'

if carp_vhid_match := re.search(PATTERN_CARP_VHID, line):
logger.debug(f"Node::parse_ifconfig_values: Found CARP VHID {carp_vhid_match.group(2)}")
config['carp_vhid'] = carp_vhid_match.group(2)

if carp_prio_match := re.search(PATTERN_CARP_ADVSKEW, line):
logger.debug(f"Node::parse_ifconfig_values: Found CARP skew {carp_prio_match.group(2)}")
config['carp_priority'] = carp_prio_match.group(2)

if carp_pass_match := re.search(PATTERN_CARP_PASS, line):
logger.debug("Node::parse_ifconfig_values: Found CARP password")
config['carp_password'] = carp_pass_match.group(2)

fib_match = re.search(PATTERN_FIB, line)
if fib_match:
logger.debug("Node::parse_ifconfig_values: interface has specific fib")
config['fib'] = fib_match.group(1)

vlan_match = re.search(PATTERN_VLAN, line)
vlandev_match = re.search(PATTERN_VLANDEV, line)
if vlan_match and vlandev_match:
logger.debug("Node::parse_ifconfig_values: interface has vlan parameters")
parse_success = True
config['vlan'] = vlan_match.group(1)
config['nic'] = [vlandev_match.group(1)]

laggproto_match = re.search(PATTERN_LAGGPROTO, line)
laggport_matches = re.findall(PATTERN_LAGGPORT, line)
if laggproto_match and laggport_matches:
logger.debug("Node::parse_ifconfig_values: interface is a Link Aggregation")
parse_success = True
config['lagg_proto'] = laggproto_match.group(1)
config['nic'] = laggport_matches
logger.debug("line does not define network configuration: configurations are "
f"laggproto = {config['lagg_proto']}, laggports = {config['nic']}")

return parse_success


def parse_gateway_config(line, config):
gateway_match = re.search(PATTERN_GATEWAY, line)
have_gateway = False
if gateway_match:
logger.debug("Node::parse_gateway_config: this is a gateway (ipv4) configuration line")
config['defaultgateway'] = gateway_match.group(1)
have_gateway = True

gateway6_match = re.search(PATTERN_GATEWAY6, line)
if gateway6_match:
logger.debug("Node::parse_gateway_config: this is a gateway (ipv6) configuration line")
config['defaultgateway_ipv6'] = gateway6_match.group(1)
have_gateway = True

return have_gateway


if __name__ == "__main__":

this_node = Cluster.get_current_node()
Expand All @@ -239,8 +100,8 @@
ifconfig_parsed = False

if ifconfig_match:
key = ifconfig_match.group(1)
value = ifconfig_match.group(2)
key = ifconfig_match.group("key")
value = ifconfig_match.group("value")

key_parsed = parse_ifconfig_key(key, config)

Expand Down Expand Up @@ -354,12 +215,12 @@
'name': config['name'] + config['iface_id'],
'ip': config.get('ip'),
'prefix_or_netmask': config.get('prefix_or_netmask'),
'fib': config.get('fib', 0),
'fib': config.get('fib', 0),
'carp_vhid': config.get('carp_vhid', 0),
'vlan': config.get('vlan', 0),
'lagg_proto': config.get('lagg_proto', ''),
})

logger.info("Node::network_sync: {} Network Address configuration {}".format("created" if created else "updated", address))


Expand All @@ -374,7 +235,7 @@
"carp_priority": config.get('carp_priority', 0),
"carp_passwd": config.get('carp_password', ''),
}
)
)
logger.info("Node::network_sync: {} link {}".format("created" if created else "updated", address_nic))
except Exception as e:
logger.error(f"Node::network_sync: Could not create link {address} -> {iface}")
Expand Down
Loading