wnm 0.0.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wnm might be problematic. Click here for more details.

@@ -0,0 +1,13 @@
1
+ """
2
+ Firewall management abstraction for WNM.
3
+
4
+ Provides a pluggable interface for firewall operations across different
5
+ firewall implementations (ufw, firewalld, iptables, or no-op).
6
+ """
7
+
8
+ from wnm.firewall.base import FirewallManager
9
+ from wnm.firewall.factory import get_firewall_manager
10
+ from wnm.firewall.null_firewall import NullFirewall
11
+ from wnm.firewall.ufw_manager import UFWManager
12
+
13
+ __all__ = ["FirewallManager", "get_firewall_manager", "NullFirewall", "UFWManager"]
wnm/firewall/base.py ADDED
@@ -0,0 +1,71 @@
1
+ """
2
+ Abstract base class for firewall managers.
3
+
4
+ Firewall managers handle opening/closing ports for node communication
5
+ across different firewall implementations.
6
+ """
7
+
8
+ from abc import ABC, abstractmethod
9
+
10
+
11
+ class FirewallManager(ABC):
12
+ """
13
+ Abstract interface for firewall management.
14
+
15
+ Each implementation handles a specific firewall backend:
16
+ - UFWManager: Ubuntu's Uncomplicated Firewall (ufw)
17
+ - FirewalldManager: Firewalld (RHEL/Fedora/CentOS)
18
+ - IptablesManager: Direct iptables manipulation
19
+ - NullFirewall: No-op implementation (firewall disabled)
20
+ """
21
+
22
+ @abstractmethod
23
+ def enable_port(
24
+ self, port: int, protocol: str = "udp", comment: str = None
25
+ ) -> bool:
26
+ """
27
+ Open a firewall port for incoming traffic.
28
+
29
+ Args:
30
+ port: Port number to open
31
+ protocol: Protocol type (udp/tcp)
32
+ comment: Optional comment/description for the rule
33
+
34
+ Returns:
35
+ True if port was opened successfully, False otherwise
36
+ """
37
+ pass
38
+
39
+ @abstractmethod
40
+ def disable_port(self, port: int, protocol: str = "udp") -> bool:
41
+ """
42
+ Close a firewall port, blocking incoming traffic.
43
+
44
+ Args:
45
+ port: Port number to close
46
+ protocol: Protocol type (udp/tcp)
47
+
48
+ Returns:
49
+ True if port was closed successfully, False otherwise
50
+ """
51
+ pass
52
+
53
+ @abstractmethod
54
+ def is_enabled(self) -> bool:
55
+ """
56
+ Check if the firewall is enabled and active.
57
+
58
+ Returns:
59
+ True if firewall is active, False otherwise
60
+ """
61
+ pass
62
+
63
+ @abstractmethod
64
+ def is_available(self) -> bool:
65
+ """
66
+ Check if this firewall implementation is available on the system.
67
+
68
+ Returns:
69
+ True if firewall tools are installed, False otherwise
70
+ """
71
+ pass
@@ -0,0 +1,95 @@
1
+ """
2
+ Factory for creating firewall manager instances.
3
+
4
+ Provides auto-detection of available firewall implementations
5
+ and a factory function for creating the appropriate manager.
6
+ """
7
+
8
+ import logging
9
+ import os
10
+
11
+ from wnm.firewall.base import FirewallManager
12
+ from wnm.firewall.null_firewall import NullFirewall
13
+ from wnm.firewall.ufw_manager import UFWManager
14
+
15
+
16
+ def get_default_firewall_type() -> str:
17
+ """
18
+ Auto-detect the best firewall manager for this system.
19
+
20
+ Checks for available firewall tools in priority order:
21
+ 1. UFW (Ubuntu/Debian)
22
+ 2. Firewalld (RHEL/Fedora) - not yet implemented
23
+ 3. Iptables (Linux fallback) - not yet implemented
24
+ 4. NullFirewall (disabled/unavailable)
25
+
26
+ Returns:
27
+ Firewall type name: "ufw", "firewalld", "iptables", or "null"
28
+ """
29
+ # Check if firewall is disabled via environment variable
30
+ if os.environ.get("WNM_FIREWALL_DISABLED", "").lower() in ("1", "true", "yes"):
31
+ logging.info("Firewall disabled via WNM_FIREWALL_DISABLED environment variable")
32
+ return "null"
33
+
34
+ # Try UFW first (most common on Ubuntu/Debian)
35
+ ufw = UFWManager()
36
+ if ufw.is_available():
37
+ logging.debug("Auto-detected UFW firewall")
38
+ return "ufw"
39
+
40
+ # TODO: Add firewalld detection
41
+ # firewalld = FirewalldManager()
42
+ # if firewalld.is_available():
43
+ # logging.debug("Auto-detected firewalld")
44
+ # return "firewalld"
45
+
46
+ # TODO: Add iptables detection
47
+ # iptables = IptablesManager()
48
+ # if iptables.is_available():
49
+ # logging.debug("Auto-detected iptables")
50
+ # return "iptables"
51
+
52
+ # Default to null firewall if nothing available
53
+ logging.warning("No firewall implementation available, using NullFirewall")
54
+ return "null"
55
+
56
+
57
+ def get_firewall_manager(firewall_type: str = None) -> FirewallManager:
58
+ """
59
+ Create a firewall manager instance.
60
+
61
+ Args:
62
+ firewall_type: Type of firewall ("ufw", "firewalld", "iptables", "null")
63
+ If None, auto-detects best available option
64
+
65
+ Returns:
66
+ FirewallManager instance
67
+
68
+ Raises:
69
+ ValueError: If firewall_type is not recognized
70
+ """
71
+ if firewall_type is None:
72
+ firewall_type = get_default_firewall_type()
73
+
74
+ firewall_type = firewall_type.lower()
75
+
76
+ managers = {
77
+ "ufw": UFWManager,
78
+ "null": NullFirewall,
79
+ "disabled": NullFirewall, # Alias for null
80
+ # TODO: Add when implemented
81
+ # "firewalld": FirewalldManager,
82
+ # "iptables": IptablesManager,
83
+ }
84
+
85
+ if firewall_type not in managers:
86
+ raise ValueError(
87
+ f"Unknown firewall type: {firewall_type}. "
88
+ f"Available: {', '.join(managers.keys())}"
89
+ )
90
+
91
+ manager_class = managers[firewall_type]
92
+ manager = manager_class()
93
+
94
+ logging.debug(f"Created firewall manager: {firewall_type}")
95
+ return manager
@@ -0,0 +1,71 @@
1
+ """
2
+ Null firewall manager implementation.
3
+
4
+ A no-op firewall manager for systems where firewall management is
5
+ disabled, not needed, or handled externally (e.g., Docker networking).
6
+ """
7
+
8
+ import logging
9
+
10
+ from wnm.firewall.base import FirewallManager
11
+
12
+
13
+ class NullFirewall(FirewallManager):
14
+ """
15
+ No-op firewall manager that performs no actual firewall operations.
16
+
17
+ This is used when:
18
+ - Firewall management is disabled in configuration
19
+ - Running in Docker where port mapping handles exposure
20
+ - Firewall is managed externally
21
+ - Development/testing environments without firewall
22
+ """
23
+
24
+ def enable_port(
25
+ self, port: int, protocol: str = "udp", comment: str = None
26
+ ) -> bool:
27
+ """
28
+ No-op port enable operation.
29
+
30
+ Args:
31
+ port: Port number (ignored)
32
+ protocol: Protocol type (ignored)
33
+ comment: Comment (ignored)
34
+
35
+ Returns:
36
+ Always True
37
+ """
38
+ logging.debug(f"NullFirewall: Skipping enable for port {port}/{protocol}")
39
+ return True
40
+
41
+ def disable_port(self, port: int, protocol: str = "udp") -> bool:
42
+ """
43
+ No-op port disable operation.
44
+
45
+ Args:
46
+ port: Port number (ignored)
47
+ protocol: Protocol type (ignored)
48
+
49
+ Returns:
50
+ Always True
51
+ """
52
+ logging.debug(f"NullFirewall: Skipping disable for port {port}/{protocol}")
53
+ return True
54
+
55
+ def is_enabled(self) -> bool:
56
+ """
57
+ Check if firewall is enabled.
58
+
59
+ Returns:
60
+ Always False (null firewall is never "enabled")
61
+ """
62
+ return False
63
+
64
+ def is_available(self) -> bool:
65
+ """
66
+ Check if firewall is available.
67
+
68
+ Returns:
69
+ Always True (null firewall is always "available")
70
+ """
71
+ return True
@@ -0,0 +1,118 @@
1
+ """
2
+ UFW (Uncomplicated Firewall) manager implementation.
3
+
4
+ Manages firewall ports using Ubuntu's ufw command-line tool.
5
+ Requires sudo privileges for port operations.
6
+ """
7
+
8
+ import logging
9
+ import shutil
10
+ import subprocess
11
+
12
+ from wnm.firewall.base import FirewallManager
13
+
14
+
15
+ class UFWManager(FirewallManager):
16
+ """
17
+ Firewall manager for Ubuntu's Uncomplicated Firewall (ufw).
18
+
19
+ Uses 'sudo ufw' commands to manage port rules.
20
+ """
21
+
22
+ def enable_port(
23
+ self, port: int, protocol: str = "udp", comment: str = None
24
+ ) -> bool:
25
+ """
26
+ Open a firewall port using ufw.
27
+
28
+ Args:
29
+ port: Port number to open
30
+ protocol: Protocol type (udp/tcp)
31
+ comment: Optional comment for the rule
32
+
33
+ Returns:
34
+ True if port was opened successfully
35
+ """
36
+ if not self.is_available():
37
+ logging.warning("UFW is not available on this system")
38
+ return False
39
+
40
+ logging.info(f"Opening firewall port {port}/{protocol}")
41
+
42
+ try:
43
+ cmd = ["sudo", "ufw", "allow", f"{port}/{protocol}"]
44
+ if comment:
45
+ cmd.extend(["comment", comment])
46
+
47
+ subprocess.run(
48
+ cmd,
49
+ check=True,
50
+ capture_output=True,
51
+ text=True,
52
+ )
53
+ return True
54
+
55
+ except (subprocess.CalledProcessError, Exception) as err:
56
+ logging.error(f"Failed to open firewall port: {err}")
57
+ return False
58
+
59
+ def disable_port(self, port: int, protocol: str = "udp") -> bool:
60
+ """
61
+ Close a firewall port using ufw.
62
+
63
+ Args:
64
+ port: Port number to close
65
+ protocol: Protocol type (udp/tcp)
66
+
67
+ Returns:
68
+ True if port was closed successfully
69
+ """
70
+ if not self.is_available():
71
+ logging.warning("UFW is not available on this system")
72
+ return False
73
+
74
+ logging.info(f"Closing firewall port {port}/{protocol}")
75
+
76
+ try:
77
+ subprocess.run(
78
+ ["sudo", "ufw", "delete", "allow", f"{port}/{protocol}"],
79
+ check=True,
80
+ capture_output=True,
81
+ text=True,
82
+ )
83
+ return True
84
+
85
+ except (subprocess.CalledProcessError, Exception) as err:
86
+ logging.error(f"Failed to close firewall port: {err}")
87
+ return False
88
+
89
+ def is_enabled(self) -> bool:
90
+ """
91
+ Check if UFW is active.
92
+
93
+ Returns:
94
+ True if ufw is active, False otherwise
95
+ """
96
+ if not self.is_available():
97
+ return False
98
+
99
+ try:
100
+ result = subprocess.run(
101
+ ["sudo", "ufw", "status"],
102
+ check=True,
103
+ capture_output=True,
104
+ text=True,
105
+ )
106
+ return "Status: active" in result.stdout
107
+
108
+ except subprocess.CalledProcessError:
109
+ return False
110
+
111
+ def is_available(self) -> bool:
112
+ """
113
+ Check if ufw is installed on the system.
114
+
115
+ Returns:
116
+ True if ufw command is available
117
+ """
118
+ return shutil.which("ufw") is not None
wnm/migration.py ADDED
@@ -0,0 +1,42 @@
1
+ """
2
+ Migration and node discovery utilities.
3
+
4
+ This module handles surveying existing nodes from process managers for
5
+ database initialization and migration from anm (Autonomi Node Manager).
6
+
7
+ These functions are only used during initialization, not regular operation.
8
+ The database is the source of truth for node management.
9
+ """
10
+
11
+ import logging
12
+
13
+ from wnm.process_managers.factory import get_default_manager_type, get_process_manager
14
+
15
+
16
+ def survey_machine(machine_config, manager_type: str = None) -> list:
17
+ """
18
+ Survey all nodes managed by the process manager.
19
+
20
+ This is used during database initialization/rebuild to discover
21
+ existing nodes. The specific process manager handles its own path
22
+ logic internally.
23
+
24
+ Args:
25
+ machine_config: Machine configuration object
26
+ manager_type: Type of process manager ("systemd", "launchctl", etc.)
27
+ If None, auto-detects from platform
28
+
29
+ Returns:
30
+ List of node dictionaries ready for database insertion
31
+ """
32
+ if manager_type is None:
33
+ # Auto-detect manager type from platform
34
+ manager_type = get_default_manager_type()
35
+
36
+ logging.info(f"Surveying machine with {manager_type} manager")
37
+
38
+ # Get the appropriate process manager
39
+ manager = get_process_manager(manager_type)
40
+
41
+ # Use the manager's survey_nodes() method
42
+ return manager.survey_nodes(machine_config)