iflow-mcp_enuno-unifi-mcp-server 0.2.1__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.
Files changed (81) hide show
  1. iflow_mcp_enuno_unifi_mcp_server-0.2.1.dist-info/METADATA +1282 -0
  2. iflow_mcp_enuno_unifi_mcp_server-0.2.1.dist-info/RECORD +81 -0
  3. iflow_mcp_enuno_unifi_mcp_server-0.2.1.dist-info/WHEEL +4 -0
  4. iflow_mcp_enuno_unifi_mcp_server-0.2.1.dist-info/entry_points.txt +2 -0
  5. iflow_mcp_enuno_unifi_mcp_server-0.2.1.dist-info/licenses/LICENSE +201 -0
  6. src/__init__.py +3 -0
  7. src/__main__.py +6 -0
  8. src/api/__init__.py +5 -0
  9. src/api/client.py +727 -0
  10. src/api/site_manager_client.py +176 -0
  11. src/cache.py +483 -0
  12. src/config/__init__.py +5 -0
  13. src/config/config.py +321 -0
  14. src/main.py +2234 -0
  15. src/models/__init__.py +126 -0
  16. src/models/acl.py +41 -0
  17. src/models/backup.py +272 -0
  18. src/models/client.py +74 -0
  19. src/models/device.py +53 -0
  20. src/models/dpi.py +50 -0
  21. src/models/firewall_policy.py +123 -0
  22. src/models/firewall_zone.py +28 -0
  23. src/models/network.py +62 -0
  24. src/models/qos_profile.py +458 -0
  25. src/models/radius.py +141 -0
  26. src/models/reference_data.py +34 -0
  27. src/models/site.py +59 -0
  28. src/models/site_manager.py +120 -0
  29. src/models/topology.py +138 -0
  30. src/models/traffic_flow.py +137 -0
  31. src/models/traffic_matching_list.py +56 -0
  32. src/models/voucher.py +42 -0
  33. src/models/vpn.py +73 -0
  34. src/models/wan.py +48 -0
  35. src/models/zbf_matrix.py +49 -0
  36. src/resources/__init__.py +8 -0
  37. src/resources/clients.py +111 -0
  38. src/resources/devices.py +102 -0
  39. src/resources/networks.py +93 -0
  40. src/resources/site_manager.py +64 -0
  41. src/resources/sites.py +86 -0
  42. src/tools/__init__.py +25 -0
  43. src/tools/acls.py +328 -0
  44. src/tools/application.py +42 -0
  45. src/tools/backups.py +1173 -0
  46. src/tools/client_management.py +505 -0
  47. src/tools/clients.py +203 -0
  48. src/tools/device_control.py +325 -0
  49. src/tools/devices.py +354 -0
  50. src/tools/dpi.py +241 -0
  51. src/tools/dpi_tools.py +89 -0
  52. src/tools/firewall.py +417 -0
  53. src/tools/firewall_policies.py +430 -0
  54. src/tools/firewall_zones.py +515 -0
  55. src/tools/network_config.py +388 -0
  56. src/tools/networks.py +190 -0
  57. src/tools/port_forwarding.py +263 -0
  58. src/tools/qos.py +1070 -0
  59. src/tools/radius.py +763 -0
  60. src/tools/reference_data.py +107 -0
  61. src/tools/site_manager.py +466 -0
  62. src/tools/site_vpn.py +95 -0
  63. src/tools/sites.py +187 -0
  64. src/tools/topology.py +406 -0
  65. src/tools/traffic_flows.py +1062 -0
  66. src/tools/traffic_matching_lists.py +371 -0
  67. src/tools/vouchers.py +249 -0
  68. src/tools/vpn.py +76 -0
  69. src/tools/wans.py +30 -0
  70. src/tools/wifi.py +498 -0
  71. src/tools/zbf_matrix.py +326 -0
  72. src/utils/__init__.py +88 -0
  73. src/utils/audit.py +213 -0
  74. src/utils/exceptions.py +114 -0
  75. src/utils/helpers.py +159 -0
  76. src/utils/logger.py +105 -0
  77. src/utils/sanitize.py +244 -0
  78. src/utils/validators.py +160 -0
  79. src/webhooks/__init__.py +6 -0
  80. src/webhooks/handlers.py +196 -0
  81. src/webhooks/receiver.py +290 -0
src/models/__init__.py ADDED
@@ -0,0 +1,126 @@
1
+ """Data models for UniFi MCP Server."""
2
+
3
+ from .acl import ACLRule
4
+ from .backup import (
5
+ BackupMetadata,
6
+ BackupOperation,
7
+ BackupSchedule,
8
+ BackupStatus,
9
+ BackupType,
10
+ BackupValidationResult,
11
+ RestoreOperation,
12
+ RestoreStatus,
13
+ )
14
+ from .client import Client
15
+ from .device import Device
16
+ from .dpi import Country, DPIApplication, DPICategory
17
+ from .firewall_policy import (
18
+ ConnectionStateType,
19
+ FirewallPolicy,
20
+ FirewallPolicyCreate,
21
+ FirewallPolicyUpdate,
22
+ IPVersion,
23
+ MatchingTarget,
24
+ MatchTarget,
25
+ PolicyAction,
26
+ Schedule,
27
+ )
28
+ from .firewall_zone import FirewallZone
29
+ from .network import Network
30
+ from .qos_profile import (
31
+ DSCPValue,
32
+ MatchCriteria,
33
+ ProAVProtocol,
34
+ ProAVTemplate,
35
+ QoSAction,
36
+ QoSPriority,
37
+ QoSProfile,
38
+ QueueAlgorithm,
39
+ RouteAction,
40
+ RouteSchedule,
41
+ SmartQueueConfig,
42
+ TrafficRoute,
43
+ )
44
+ from .radius import RADIUSProfile
45
+ from .reference_data import DeviceTag
46
+ from .site import Site
47
+ from .site_manager import (
48
+ CrossSiteStatistics,
49
+ InternetHealthMetrics,
50
+ SiteHealthSummary,
51
+ VantagePoint,
52
+ )
53
+ from .traffic_flow import FlowRisk, FlowStatistics, FlowView, TrafficFlow
54
+ from .traffic_matching_list import (
55
+ TrafficMatchingList,
56
+ TrafficMatchingListCreate,
57
+ TrafficMatchingListType,
58
+ TrafficMatchingListUpdate,
59
+ )
60
+ from .voucher import Voucher
61
+ from .vpn import VPNServer, VPNTunnel
62
+ from .wan import WANConnection
63
+ from .zbf_matrix import ApplicationBlockRule, ZoneNetworkAssignment, ZonePolicy, ZonePolicyMatrix
64
+
65
+ __all__ = [
66
+ "Site",
67
+ "Device",
68
+ "Client",
69
+ "Network",
70
+ "ACLRule",
71
+ "Voucher",
72
+ "FirewallZone",
73
+ "FirewallPolicy",
74
+ "FirewallPolicyCreate",
75
+ "FirewallPolicyUpdate",
76
+ "PolicyAction",
77
+ "MatchingTarget",
78
+ "ConnectionStateType",
79
+ "IPVersion",
80
+ "MatchTarget",
81
+ "Schedule",
82
+ "WANConnection",
83
+ "DPICategory",
84
+ "DPIApplication",
85
+ "Country",
86
+ "ZonePolicyMatrix",
87
+ "ZonePolicy",
88
+ "ApplicationBlockRule",
89
+ "ZoneNetworkAssignment",
90
+ "TrafficFlow",
91
+ "FlowStatistics",
92
+ "FlowRisk",
93
+ "FlowView",
94
+ "TrafficMatchingList",
95
+ "TrafficMatchingListCreate",
96
+ "TrafficMatchingListUpdate",
97
+ "TrafficMatchingListType",
98
+ "VPNTunnel",
99
+ "VPNServer",
100
+ "RADIUSProfile",
101
+ "DeviceTag",
102
+ "SiteHealthSummary",
103
+ "InternetHealthMetrics",
104
+ "CrossSiteStatistics",
105
+ "VantagePoint",
106
+ "BackupMetadata",
107
+ "BackupOperation",
108
+ "BackupSchedule",
109
+ "BackupStatus",
110
+ "BackupType",
111
+ "BackupValidationResult",
112
+ "RestoreOperation",
113
+ "RestoreStatus",
114
+ "QoSProfile",
115
+ "QoSPriority",
116
+ "DSCPValue",
117
+ "QoSAction",
118
+ "RouteAction",
119
+ "QueueAlgorithm",
120
+ "ProAVProtocol",
121
+ "ProAVTemplate",
122
+ "MatchCriteria",
123
+ "RouteSchedule",
124
+ "TrafficRoute",
125
+ "SmartQueueConfig",
126
+ ]
src/models/acl.py ADDED
@@ -0,0 +1,41 @@
1
+ """Access Control List (ACL) models."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+
5
+
6
+ class ACLRule(BaseModel):
7
+ """ACL rule model."""
8
+
9
+ id: str = Field(..., alias="_id", description="ACL rule identifier")
10
+ site_id: str = Field(..., description="Site identifier")
11
+ name: str = Field(..., description="Rule name")
12
+ enabled: bool = Field(True, description="Whether the rule is enabled")
13
+ action: str = Field(..., description="Action to take (allow/deny)")
14
+
15
+ # Source configuration
16
+ source_type: str | None = Field(None, description="Source type (network/device/ip/any)")
17
+ source_id: str | None = Field(None, description="Source identifier")
18
+ source_network: str | None = Field(None, description="Source network CIDR")
19
+
20
+ # Destination configuration
21
+ destination_type: str | None = Field(
22
+ None, description="Destination type (network/ip/port/dpi-category/dpi-app)"
23
+ )
24
+ destination_id: str | None = Field(None, description="Destination identifier")
25
+ destination_network: str | None = Field(None, description="Destination network CIDR")
26
+
27
+ # Protocol and ports
28
+ protocol: str | None = Field(None, description="Protocol (tcp/udp/icmp/all)")
29
+ src_port: int | None = Field(None, description="Source port")
30
+ dst_port: int | None = Field(None, description="Destination port")
31
+
32
+ # Priority and metadata
33
+ priority: int = Field(100, description="Rule priority (lower = higher priority)")
34
+ description: str | None = Field(None, description="Rule description")
35
+ rule_index: int | None = Field(None, description="Rule index in the list")
36
+
37
+ # Statistics
38
+ byte_count: int | None = Field(None, description="Bytes matched by this rule")
39
+ packet_count: int | None = Field(None, description="Packets matched by this rule")
40
+
41
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
src/models/backup.py ADDED
@@ -0,0 +1,272 @@
1
+ """Backup and restore data models."""
2
+
3
+ from datetime import datetime
4
+ from enum import Enum
5
+ from typing import Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field
8
+
9
+
10
+ class BackupType(str, Enum):
11
+ """Backup type enumeration."""
12
+
13
+ SYSTEM = "SYSTEM" # Complete OS, application, and device configurations
14
+ NETWORK = "NETWORK" # Network settings and device configurations only
15
+
16
+
17
+ class BackupStatus(str, Enum):
18
+ """Backup operation status."""
19
+
20
+ PENDING = "pending"
21
+ IN_PROGRESS = "in_progress"
22
+ COMPLETED = "completed"
23
+ FAILED = "failed"
24
+
25
+
26
+ class RestoreStatus(str, Enum):
27
+ """Restore operation status."""
28
+
29
+ PENDING = "pending"
30
+ IN_PROGRESS = "in_progress"
31
+ COMPLETED = "completed"
32
+ FAILED = "failed"
33
+ ROLLED_BACK = "rolled_back"
34
+
35
+
36
+ class BackupMetadata(BaseModel):
37
+ """Backup file metadata and information."""
38
+
39
+ backup_id: str = Field(..., description="Unique backup identifier")
40
+ filename: str = Field(..., description="Backup filename (e.g., backup_2025-01-29.unf)")
41
+ backup_type: BackupType = Field(..., description="Type of backup (SYSTEM or NETWORK)")
42
+ created_at: datetime = Field(..., description="Backup creation timestamp")
43
+ size_bytes: int | None = Field(None, description="Backup file size in bytes")
44
+ version: str | None = Field(None, description="UniFi Network version at backup time")
45
+
46
+ # Metadata about backup contents
47
+ device_count: int | None = Field(None, description="Number of devices in backup")
48
+ site_count: int | None = Field(None, description="Number of sites in backup")
49
+ network_count: int | None = Field(None, description="Number of networks in backup")
50
+
51
+ # Cloud backup status
52
+ cloud_synced: bool = Field(False, description="Whether backup is synced to cloud")
53
+ cloud_sync_time: datetime | None = Field(None, description="Last cloud sync timestamp")
54
+
55
+ # Backup location
56
+ download_url: str | None = Field(None, description="Download URL for backup file")
57
+ local_path: str | None = Field(None, description="Local filesystem path (if applicable)")
58
+
59
+ # Validation
60
+ checksum: str | None = Field(None, description="Backup file checksum (MD5 or SHA256)")
61
+ is_valid: bool = Field(True, description="Whether backup passed validation checks")
62
+ validation_message: str | None = Field(None, description="Validation error message if any")
63
+
64
+ model_config = ConfigDict(
65
+ populate_by_name=True,
66
+ json_schema_extra={
67
+ "example": {
68
+ "backup_id": "backup_20250129_123456",
69
+ "filename": "backup_2025-01-29_12-34-56.unf",
70
+ "backup_type": "NETWORK",
71
+ "created_at": "2025-01-29T12:34:56Z",
72
+ "size_bytes": 1048576,
73
+ "version": "10.0.160",
74
+ "device_count": 15,
75
+ "site_count": 1,
76
+ "network_count": 5,
77
+ "cloud_synced": True,
78
+ "is_valid": True,
79
+ }
80
+ },
81
+ )
82
+
83
+
84
+ class BackupOperation(BaseModel):
85
+ """Backup operation status and details."""
86
+
87
+ operation_id: str = Field(..., description="Unique operation identifier")
88
+ backup_type: BackupType = Field(..., description="Type of backup being created")
89
+ status: BackupStatus = Field(..., description="Current operation status")
90
+ started_at: datetime = Field(..., description="Operation start time")
91
+ completed_at: datetime | None = Field(None, description="Operation completion time")
92
+
93
+ # Progress tracking
94
+ progress_percent: int = Field(0, ge=0, le=100, description="Progress percentage (0-100)")
95
+ current_step: str | None = Field(None, description="Current operation step description")
96
+
97
+ # Result
98
+ backup_metadata: BackupMetadata | None = Field(None, description="Metadata of created backup")
99
+ error_message: str | None = Field(None, description="Error message if failed")
100
+
101
+ model_config = ConfigDict(
102
+ populate_by_name=True,
103
+ json_schema_extra={
104
+ "example": {
105
+ "operation_id": "op_backup_abc123",
106
+ "backup_type": "NETWORK",
107
+ "status": "completed",
108
+ "started_at": "2025-01-29T12:34:00Z",
109
+ "completed_at": "2025-01-29T12:35:30Z",
110
+ "progress_percent": 100,
111
+ "current_step": "Finalizing backup",
112
+ }
113
+ },
114
+ )
115
+
116
+
117
+ class RestoreOperation(BaseModel):
118
+ """Restore operation status and details."""
119
+
120
+ operation_id: str = Field(..., description="Unique operation identifier")
121
+ backup_id: str = Field(..., description="Backup being restored")
122
+ status: RestoreStatus = Field(..., description="Current operation status")
123
+ started_at: datetime = Field(..., description="Operation start time")
124
+ completed_at: datetime | None = Field(None, description="Operation completion time")
125
+
126
+ # Progress tracking
127
+ progress_percent: int = Field(0, ge=0, le=100, description="Progress percentage (0-100)")
128
+ current_step: str | None = Field(None, description="Current operation step description")
129
+
130
+ # Safety features
131
+ pre_restore_backup_id: str | None = Field(
132
+ None,
133
+ description="Backup ID of automatic pre-restore backup (for rollback)",
134
+ )
135
+ can_rollback: bool = Field(False, description="Whether rollback is available")
136
+
137
+ # Result
138
+ error_message: str | None = Field(None, description="Error message if failed")
139
+ rollback_reason: str | None = Field(None, description="Reason for rollback if applicable")
140
+
141
+ model_config = ConfigDict(
142
+ populate_by_name=True,
143
+ json_schema_extra={
144
+ "example": {
145
+ "operation_id": "op_restore_xyz789",
146
+ "backup_id": "backup_20250129_123456",
147
+ "status": "in_progress",
148
+ "started_at": "2025-01-29T14:00:00Z",
149
+ "progress_percent": 45,
150
+ "current_step": "Restoring device configurations",
151
+ "pre_restore_backup_id": "backup_20250129_140000_preRestore",
152
+ "can_rollback": True,
153
+ }
154
+ },
155
+ )
156
+
157
+
158
+ class BackupSchedule(BaseModel):
159
+ """Automated backup schedule configuration."""
160
+
161
+ schedule_id: str = Field(..., description="Unique schedule identifier")
162
+ enabled: bool = Field(True, description="Whether schedule is enabled")
163
+ backup_type: BackupType = Field(..., description="Type of backup to create")
164
+
165
+ # Schedule configuration
166
+ frequency: Literal["daily", "weekly", "monthly"] = Field(
167
+ ...,
168
+ description="Backup frequency",
169
+ )
170
+ time_of_day: str = Field(
171
+ ...,
172
+ description="Time to run backup (HH:MM format, 24-hour)",
173
+ pattern=r"^([01]\d|2[0-3]):([0-5]\d)$",
174
+ )
175
+ day_of_week: int | None = Field(
176
+ None,
177
+ ge=0,
178
+ le=6,
179
+ description="Day of week for weekly backups (0=Monday, 6=Sunday)",
180
+ )
181
+ day_of_month: int | None = Field(
182
+ None,
183
+ ge=1,
184
+ le=31,
185
+ description="Day of month for monthly backups",
186
+ )
187
+
188
+ # Retention policy
189
+ retention_days: int = Field(
190
+ 30,
191
+ ge=1,
192
+ le=365,
193
+ description="Number of days to retain backups",
194
+ )
195
+ max_backups: int = Field(
196
+ 10,
197
+ ge=1,
198
+ le=100,
199
+ description="Maximum number of backups to keep",
200
+ )
201
+
202
+ # Cloud backup
203
+ cloud_backup_enabled: bool = Field(
204
+ False,
205
+ description="Whether to sync backups to cloud",
206
+ )
207
+
208
+ # Last run info
209
+ last_run: datetime | None = Field(None, description="Last execution timestamp")
210
+ last_backup_id: str | None = Field(None, description="Last created backup ID")
211
+ next_run: datetime | None = Field(None, description="Next scheduled execution")
212
+
213
+ model_config = ConfigDict(
214
+ populate_by_name=True,
215
+ json_schema_extra={
216
+ "example": {
217
+ "schedule_id": "schedule_daily_network",
218
+ "enabled": True,
219
+ "backup_type": "NETWORK",
220
+ "frequency": "daily",
221
+ "time_of_day": "03:00",
222
+ "retention_days": 30,
223
+ "max_backups": 10,
224
+ "cloud_backup_enabled": True,
225
+ "last_run": "2025-01-29T03:00:00Z",
226
+ "next_run": "2025-01-30T03:00:00Z",
227
+ }
228
+ },
229
+ )
230
+
231
+
232
+ class BackupValidationResult(BaseModel):
233
+ """Result of backup file validation."""
234
+
235
+ backup_id: str = Field(..., description="Backup being validated")
236
+ is_valid: bool = Field(..., description="Whether backup is valid")
237
+
238
+ # Validation checks
239
+ checksum_valid: bool = Field(..., description="File integrity check passed")
240
+ format_valid: bool = Field(..., description="File format is correct")
241
+ version_compatible: bool = Field(..., description="Version is compatible with current system")
242
+
243
+ # Validation details
244
+ backup_version: str | None = Field(None, description="UniFi version of backup")
245
+ current_version: str | None = Field(None, description="Current UniFi version")
246
+ warnings: list[str] = Field(default_factory=list, description="Validation warnings")
247
+ errors: list[str] = Field(default_factory=list, description="Validation errors")
248
+
249
+ # Backup contents preview
250
+ contains_devices: int | None = Field(None, description="Number of devices in backup")
251
+ contains_networks: int | None = Field(None, description="Number of networks in backup")
252
+ contains_sites: int | None = Field(None, description="Number of sites in backup")
253
+
254
+ model_config = ConfigDict(
255
+ populate_by_name=True,
256
+ json_schema_extra={
257
+ "example": {
258
+ "backup_id": "backup_20250129_123456",
259
+ "is_valid": True,
260
+ "checksum_valid": True,
261
+ "format_valid": True,
262
+ "version_compatible": True,
263
+ "backup_version": "10.0.160",
264
+ "current_version": "10.0.160",
265
+ "warnings": [],
266
+ "errors": [],
267
+ "contains_devices": 15,
268
+ "contains_networks": 5,
269
+ "contains_sites": 1,
270
+ }
271
+ },
272
+ )
src/models/client.py ADDED
@@ -0,0 +1,74 @@
1
+ """Client data model."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
4
+
5
+
6
+ class Client(BaseModel):
7
+ """UniFi network client information."""
8
+
9
+ mac: str = Field(..., description="Client MAC address")
10
+ ip: str | None = Field(None, description="Client IP address")
11
+ hostname: str | None = Field(None, description="Client hostname")
12
+ name: str | None = Field(None, description="Client name (user-assigned)")
13
+
14
+ # Connection info
15
+ is_wired: bool | None = Field(None, description="Whether client is wired")
16
+ is_guest: bool | None = Field(None, description="Whether client is on guest network")
17
+ essid: str | None = Field(None, description="SSID name (for wireless clients)")
18
+ channel: int | None = Field(None, description="WiFi channel (for wireless clients)")
19
+ radio: str | None = Field(None, description="Radio type (ng, na, etc.)")
20
+
21
+ # Signal strength (wireless only)
22
+ signal: int | None = Field(None, description="Signal strength in dBm")
23
+ rssi: int | None = Field(None, description="RSSI value")
24
+ noise: int | None = Field(None, description="Noise level in dBm")
25
+
26
+ # Network statistics
27
+ tx_bytes: int | None = Field(None, description="Transmitted bytes")
28
+ rx_bytes: int | None = Field(None, description="Received bytes")
29
+ tx_packets: int | None = Field(None, description="Transmitted packets")
30
+ rx_packets: int | None = Field(None, description="Received packets")
31
+ tx_rate: int | None = Field(None, description="Transmission rate in Kbps")
32
+ rx_rate: int | None = Field(None, description="Receiving rate in Kbps")
33
+
34
+ # Session info
35
+ uptime: int | None = Field(None, description="Session uptime in seconds")
36
+ last_seen: int | None = Field(None, description="Last seen timestamp")
37
+ first_seen: int | None = Field(None, description="First seen timestamp")
38
+
39
+ # Device info
40
+ oui: str | None = Field(None, description="MAC OUI manufacturer")
41
+ os_class: int | None = Field(None, description="Operating system class")
42
+ os_name: str | None = Field(None, description="Operating system name")
43
+
44
+ # Associated device
45
+ ap_mac: str | None = Field(None, description="Access point MAC address")
46
+ sw_mac: str | None = Field(None, description="Switch MAC address")
47
+ gw_mac: str | None = Field(None, description="Gateway MAC address")
48
+
49
+ # VLAN
50
+ vlan: int | None = Field(None, description="VLAN ID")
51
+ network: str | None = Field(None, description="Network name")
52
+
53
+ @field_validator("os_name", mode="before")
54
+ @classmethod
55
+ def coerce_os_name_to_str(cls, v: int | str | None) -> str | None:
56
+ """Convert os_name from int to str if needed (local API returns int)."""
57
+ if v is None:
58
+ return None
59
+ return str(v)
60
+
61
+ model_config = ConfigDict(
62
+ populate_by_name=True,
63
+ json_schema_extra={
64
+ "example": {
65
+ "mac": "aa:bb:cc:dd:ee:01",
66
+ "ip": "192.168.1.100",
67
+ "hostname": "laptop-001",
68
+ "is_wired": False,
69
+ "signal": -45,
70
+ "tx_bytes": 1024000,
71
+ "rx_bytes": 2048000,
72
+ }
73
+ },
74
+ )
src/models/device.py ADDED
@@ -0,0 +1,53 @@
1
+ """Device data model."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+
5
+
6
+ class Device(BaseModel):
7
+ """UniFi network device information."""
8
+
9
+ id: str = Field(..., description="Device ID", alias="_id")
10
+ name: str | None = Field(None, description="Device name")
11
+ model: str = Field(..., description="Device model")
12
+ type: str = Field(..., description="Device type (uap, usw, ugw, etc.)")
13
+ mac: str = Field(..., description="Device MAC address")
14
+ ip: str | None = Field(None, description="Device IP address")
15
+
16
+ # Status fields
17
+ state: int = Field(..., description="Device state (0=offline, 1=online, etc.)")
18
+ adopted: bool | None = Field(None, description="Whether device is adopted")
19
+ disabled: bool | None = Field(None, description="Whether device is disabled")
20
+
21
+ # Hardware info
22
+ version: str | None = Field(None, description="Firmware version")
23
+ uptime: int | None = Field(None, description="Uptime in seconds")
24
+
25
+ # Performance metrics
26
+ cpu: float | None = Field(None, description="CPU usage percentage")
27
+ mem: float | None = Field(None, description="Memory usage percentage")
28
+ uplink_depth: int | None = Field(None, description="Uplink depth in network topology")
29
+
30
+ # Network stats
31
+ bytes: int | None = Field(None, description="Total bytes transferred")
32
+ tx_bytes: int | None = Field(None, description="Transmitted bytes")
33
+ rx_bytes: int | None = Field(None, description="Received bytes")
34
+
35
+ # Additional metadata
36
+ serial: str | None = Field(None, description="Device serial number")
37
+ license_state: str | None = Field(None, description="License state")
38
+
39
+ model_config = ConfigDict(
40
+ populate_by_name=True,
41
+ json_schema_extra={
42
+ "example": {
43
+ "_id": "507f1f77bcf86cd799439011",
44
+ "name": "AP-Office",
45
+ "model": "U6-LR",
46
+ "type": "uap",
47
+ "mac": "aa:bb:cc:dd:ee:ff",
48
+ "ip": "192.168.1.10",
49
+ "state": 1,
50
+ "uptime": 86400,
51
+ }
52
+ },
53
+ )
src/models/dpi.py ADDED
@@ -0,0 +1,50 @@
1
+ """Deep Packet Inspection (DPI) models."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+
5
+
6
+ class DPICategory(BaseModel):
7
+ """DPI category model."""
8
+
9
+ id: str = Field(..., alias="_id", description="Category identifier")
10
+ name: str = Field(..., description="Category name")
11
+ description: str | None = Field(None, description="Category description")
12
+
13
+ # Application count
14
+ app_count: int | None = Field(None, description="Number of applications in this category")
15
+
16
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
17
+
18
+
19
+ class DPIApplication(BaseModel):
20
+ """DPI application model."""
21
+
22
+ id: str = Field(..., alias="_id", description="Application identifier")
23
+ name: str = Field(..., description="Application name")
24
+ category_id: str = Field(..., description="Category identifier")
25
+ category_name: str | None = Field(None, description="Category name")
26
+
27
+ # Application metadata
28
+ enabled: bool = Field(True, description="Whether application detection is enabled")
29
+
30
+ # Traffic classification
31
+ protocols: list[str] = Field(
32
+ default_factory=list, description="Protocols used by this application"
33
+ )
34
+ ports: list[int] = Field(default_factory=list, description="Common ports used")
35
+
36
+ model_config = ConfigDict(populate_by_name=True, extra="allow")
37
+
38
+
39
+ class Country(BaseModel):
40
+ """Country information model."""
41
+
42
+ code: str = Field(..., description="ISO country code")
43
+ name: str = Field(..., description="Country name")
44
+ iso_code: str | None = Field(None, description="ISO 3166-1 alpha-2 code")
45
+ iso3_code: str | None = Field(None, description="ISO 3166-1 alpha-3 code")
46
+
47
+ # Regulatory information
48
+ regulatory_domain: str | None = Field(None, description="Regulatory domain for wireless")
49
+
50
+ model_config = ConfigDict(populate_by_name=True, extra="allow")