monsterops 1.12.0__tar.gz

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 (258) hide show
  1. monsterops-1.12.0/.env.example +38 -0
  2. monsterops-1.12.0/.gitignore +21 -0
  3. monsterops-1.12.0/CHANGELOG.md +110 -0
  4. monsterops-1.12.0/Dockerfile +18 -0
  5. monsterops-1.12.0/LICENSE +21 -0
  6. monsterops-1.12.0/PKG-INFO +138 -0
  7. monsterops-1.12.0/README.md +73 -0
  8. monsterops-1.12.0/SECURITY.md +25 -0
  9. monsterops-1.12.0/alembic/README +1 -0
  10. monsterops-1.12.0/alembic/env.py +85 -0
  11. monsterops-1.12.0/alembic/script.py.mako +28 -0
  12. monsterops-1.12.0/alembic/versions/a2f9c4b1e837_phase13_notifications.py +122 -0
  13. monsterops-1.12.0/alembic/versions/a4d1c7e6b520_firewall_autoblock.py +37 -0
  14. monsterops-1.12.0/alembic/versions/a9d4e7f2c1b5_realms_proxy.py +115 -0
  15. monsterops-1.12.0/alembic/versions/a9f3e2b1c0d8_retrograde_stop_trigger.py +39 -0
  16. monsterops-1.12.0/alembic/versions/b3e9a1f72c04_radpostauth_extra_columns.py +22 -0
  17. monsterops-1.12.0/alembic/versions/b6f2d8a3e91c_vpn_tunnels.py +54 -0
  18. monsterops-1.12.0/alembic/versions/b7d3f1e92a05_radpostauth_station_class_columns.py +21 -0
  19. monsterops-1.12.0/alembic/versions/b7f2c9a4e1d3_nas_reachability.py +35 -0
  20. monsterops-1.12.0/alembic/versions/b8e3f1a2d9c4_firewall_set_managed_source.py +22 -0
  21. monsterops-1.12.0/alembic/versions/c1f7b4a9d2e6_keyset_pagination_indexes.py +40 -0
  22. monsterops-1.12.0/alembic/versions/c2a8f4e71b93_radacct_unique_index_and_nasreload.py +27 -0
  23. monsterops-1.12.0/alembic/versions/c3f1a8e20d74_nas_manager.py +59 -0
  24. monsterops-1.12.0/alembic/versions/c7a1e3f92b84_nas_groups.py +48 -0
  25. monsterops-1.12.0/alembic/versions/c9e4b1f2a8d5_phase14_integrations.py +50 -0
  26. monsterops-1.12.0/alembic/versions/d1e5f8a2c3b7_phase15_apikeys_scheduler.py +75 -0
  27. monsterops-1.12.0/alembic/versions/d2e8b3f1a9c7_mr_bulk_jobs.py +32 -0
  28. monsterops-1.12.0/alembic/versions/d3b7f0a15c92_firewall_block_event.py +38 -0
  29. monsterops-1.12.0/alembic/versions/d4b2f6c81e93_nas_config_history.py +57 -0
  30. monsterops-1.12.0/alembic/versions/e1f4a9c2b6d8_mr_webhook_subs.py +36 -0
  31. monsterops-1.12.0/alembic/versions/e3a7f1c90d52_group_access_types.py +28 -0
  32. monsterops-1.12.0/alembic/versions/e5c9a1f3d827_auth_framework.py +134 -0
  33. monsterops-1.12.0/alembic/versions/e7c3a9d15f84_firewall.py +93 -0
  34. monsterops-1.12.0/alembic/versions/e85388a04f39_initial_schema.py +162 -0
  35. monsterops-1.12.0/alembic/versions/f2a8c4d97b16_log_table_indexes.py +19 -0
  36. monsterops-1.12.0/alembic/versions/f3a7c1e2d9b4_mr_automation_rules.py +39 -0
  37. monsterops-1.12.0/alembic/versions/f4c8d2a91b37_phase9_auth_enrichment.py +23 -0
  38. monsterops-1.12.0/alembic/versions/fd99a6deb43d_add_audit_log.py +35 -0
  39. monsterops-1.12.0/alembic.ini +150 -0
  40. monsterops-1.12.0/assets/MonsterOpsDO.png +0 -0
  41. monsterops-1.12.0/assets/monsterops-logo.jpg +0 -0
  42. monsterops-1.12.0/deploy/freeradius/mods-available/sql +406 -0
  43. monsterops-1.12.0/deploy/freeradius/mods-config/sql/main/postgresql/queries.conf +753 -0
  44. monsterops-1.12.0/deploy/install.sh +408 -0
  45. monsterops-1.12.0/deploy/provision-ad.sh +276 -0
  46. monsterops-1.12.0/deploy/provision-sudoers.sh +85 -0
  47. monsterops-1.12.0/deploy/provision-vpn.sh +114 -0
  48. monsterops-1.12.0/deploy/upgrade.sh +222 -0
  49. monsterops-1.12.0/docker-compose.yml +35 -0
  50. monsterops-1.12.0/docs/active-directory-auth.md +255 -0
  51. monsterops-1.12.0/docs/reference.md +251 -0
  52. monsterops-1.12.0/docs/user-guide.md +464 -0
  53. monsterops-1.12.0/monsterops/__init__.py +7 -0
  54. monsterops-1.12.0/monsterops/app.py +246 -0
  55. monsterops-1.12.0/monsterops/cli.py +568 -0
  56. monsterops-1.12.0/monsterops/config.py +106 -0
  57. monsterops-1.12.0/monsterops/database.py +29 -0
  58. monsterops-1.12.0/monsterops/events.py +51 -0
  59. monsterops-1.12.0/monsterops/geo.py +108 -0
  60. monsterops-1.12.0/monsterops/keyrotate.py +71 -0
  61. monsterops-1.12.0/monsterops/limiter.py +6 -0
  62. monsterops-1.12.0/monsterops/modules/__init__.py +0 -0
  63. monsterops-1.12.0/monsterops/modules/accounting/__init__.py +0 -0
  64. monsterops-1.12.0/monsterops/modules/accounting/coa.py +172 -0
  65. monsterops-1.12.0/monsterops/modules/accounting/models.py +63 -0
  66. monsterops-1.12.0/monsterops/modules/accounting/radius.dict +17 -0
  67. monsterops-1.12.0/monsterops/modules/accounting/router.py +299 -0
  68. monsterops-1.12.0/monsterops/modules/accounting/schemas.py +60 -0
  69. monsterops-1.12.0/monsterops/modules/accounting/static/accounting.js +685 -0
  70. monsterops-1.12.0/monsterops/modules/accounting/static/manifest.json +12 -0
  71. monsterops-1.12.0/monsterops/modules/apikeys/__init__.py +0 -0
  72. monsterops-1.12.0/monsterops/modules/apikeys/models.py +27 -0
  73. monsterops-1.12.0/monsterops/modules/apikeys/router.py +210 -0
  74. monsterops-1.12.0/monsterops/modules/apikeys/schemas.py +30 -0
  75. monsterops-1.12.0/monsterops/modules/apikeys/static/apikeys.js +338 -0
  76. monsterops-1.12.0/monsterops/modules/apikeys/static/manifest.json +5 -0
  77. monsterops-1.12.0/monsterops/modules/apikeys/v1.py +754 -0
  78. monsterops-1.12.0/monsterops/modules/auth/__init__.py +0 -0
  79. monsterops-1.12.0/monsterops/modules/auth/models.py +40 -0
  80. monsterops-1.12.0/monsterops/modules/auth/router.py +333 -0
  81. monsterops-1.12.0/monsterops/modules/auth/schemas.py +71 -0
  82. monsterops-1.12.0/monsterops/modules/auth/utils.py +201 -0
  83. monsterops-1.12.0/monsterops/modules/auth_logs/__init__.py +0 -0
  84. monsterops-1.12.0/monsterops/modules/auth_logs/models.py +29 -0
  85. monsterops-1.12.0/monsterops/modules/auth_logs/router.py +383 -0
  86. monsterops-1.12.0/monsterops/modules/auth_logs/schemas.py +50 -0
  87. monsterops-1.12.0/monsterops/modules/auth_logs/static/auth_logs.js +821 -0
  88. monsterops-1.12.0/monsterops/modules/auth_logs/static/manifest.json +12 -0
  89. monsterops-1.12.0/monsterops/modules/automation/__init__.py +0 -0
  90. monsterops-1.12.0/monsterops/modules/automation/engine.py +335 -0
  91. monsterops-1.12.0/monsterops/modules/automation/models.py +23 -0
  92. monsterops-1.12.0/monsterops/modules/automation/router.py +169 -0
  93. monsterops-1.12.0/monsterops/modules/automation/static/automation.js +639 -0
  94. monsterops-1.12.0/monsterops/modules/automation/static/manifest.json +12 -0
  95. monsterops-1.12.0/monsterops/modules/dashboard/__init__.py +0 -0
  96. monsterops-1.12.0/monsterops/modules/dashboard/router.py +240 -0
  97. monsterops-1.12.0/monsterops/modules/dashboard/schemas.py +62 -0
  98. monsterops-1.12.0/monsterops/modules/dashboard/static/dashboard.js +1074 -0
  99. monsterops-1.12.0/monsterops/modules/dashboard/static/manifest.json +7 -0
  100. monsterops-1.12.0/monsterops/modules/firewall/__init__.py +0 -0
  101. monsterops-1.12.0/monsterops/modules/firewall/generator.py +203 -0
  102. monsterops-1.12.0/monsterops/modules/firewall/geoblock.py +149 -0
  103. monsterops-1.12.0/monsterops/modules/firewall/models.py +114 -0
  104. monsterops-1.12.0/monsterops/modules/firewall/nft.py +96 -0
  105. monsterops-1.12.0/monsterops/modules/firewall/presets.py +81 -0
  106. monsterops-1.12.0/monsterops/modules/firewall/router.py +665 -0
  107. monsterops-1.12.0/monsterops/modules/firewall/schemas.py +193 -0
  108. monsterops-1.12.0/monsterops/modules/firewall/service.py +543 -0
  109. monsterops-1.12.0/monsterops/modules/firewall/static/firewall.js +1048 -0
  110. monsterops-1.12.0/monsterops/modules/firewall/static/manifest.json +12 -0
  111. monsterops-1.12.0/monsterops/modules/firewall/validators.py +79 -0
  112. monsterops-1.12.0/monsterops/modules/firewall/worker.py +168 -0
  113. monsterops-1.12.0/monsterops/modules/groups/__init__.py +0 -0
  114. monsterops-1.12.0/monsterops/modules/groups/models.py +40 -0
  115. monsterops-1.12.0/monsterops/modules/groups/router.py +601 -0
  116. monsterops-1.12.0/monsterops/modules/groups/schemas.py +85 -0
  117. monsterops-1.12.0/monsterops/modules/groups/static/groups.js +1100 -0
  118. monsterops-1.12.0/monsterops/modules/groups/static/manifest.json +12 -0
  119. monsterops-1.12.0/monsterops/modules/health/__init__.py +0 -0
  120. monsterops-1.12.0/monsterops/modules/health/router.py +574 -0
  121. monsterops-1.12.0/monsterops/modules/health/schemas.py +36 -0
  122. monsterops-1.12.0/monsterops/modules/health/static/health.js +519 -0
  123. monsterops-1.12.0/monsterops/modules/health/static/manifest.json +12 -0
  124. monsterops-1.12.0/monsterops/modules/integrations/__init__.py +0 -0
  125. monsterops-1.12.0/monsterops/modules/integrations/graylog_client.py +108 -0
  126. monsterops-1.12.0/monsterops/modules/integrations/models.py +21 -0
  127. monsterops-1.12.0/monsterops/modules/integrations/router.py +257 -0
  128. monsterops-1.12.0/monsterops/modules/integrations/schemas.py +38 -0
  129. monsterops-1.12.0/monsterops/modules/integrations/static/img/graylog.svg +1 -0
  130. monsterops-1.12.0/monsterops/modules/integrations/static/img/zabbix.svg +1 -0
  131. monsterops-1.12.0/monsterops/modules/integrations/static/integrations.js +1166 -0
  132. monsterops-1.12.0/monsterops/modules/integrations/static/manifest.json +5 -0
  133. monsterops-1.12.0/monsterops/modules/integrations/zabbix_client.py +178 -0
  134. monsterops-1.12.0/monsterops/modules/ip_pools/__init__.py +0 -0
  135. monsterops-1.12.0/monsterops/modules/ip_pools/models.py +20 -0
  136. monsterops-1.12.0/monsterops/modules/ip_pools/router.py +253 -0
  137. monsterops-1.12.0/monsterops/modules/ip_pools/schemas.py +54 -0
  138. monsterops-1.12.0/monsterops/modules/ip_pools/static/ip_pools.js +942 -0
  139. monsterops-1.12.0/monsterops/modules/ip_pools/static/manifest.json +12 -0
  140. monsterops-1.12.0/monsterops/modules/nas/__init__.py +0 -0
  141. monsterops-1.12.0/monsterops/modules/nas/models.py +64 -0
  142. monsterops-1.12.0/monsterops/modules/nas/probe.py +142 -0
  143. monsterops-1.12.0/monsterops/modules/nas/radius_attr_hints.py +167 -0
  144. monsterops-1.12.0/monsterops/modules/nas/router.py +630 -0
  145. monsterops-1.12.0/monsterops/modules/nas/schemas.py +152 -0
  146. monsterops-1.12.0/monsterops/modules/nas/static/manifest.json +12 -0
  147. monsterops-1.12.0/monsterops/modules/nas/static/nas.js +1782 -0
  148. monsterops-1.12.0/monsterops/modules/nas_manager/__init__.py +0 -0
  149. monsterops-1.12.0/monsterops/modules/nas_manager/crypto.py +30 -0
  150. monsterops-1.12.0/monsterops/modules/nas_manager/history.py +126 -0
  151. monsterops-1.12.0/monsterops/modules/nas_manager/models.py +80 -0
  152. monsterops-1.12.0/monsterops/modules/nas_manager/radius_deploy.py +264 -0
  153. monsterops-1.12.0/monsterops/modules/nas_manager/router.py +873 -0
  154. monsterops-1.12.0/monsterops/modules/nas_manager/schemas.py +258 -0
  155. monsterops-1.12.0/monsterops/modules/nas_manager/service.py +125 -0
  156. monsterops-1.12.0/monsterops/modules/nas_manager/static/manifest.json +5 -0
  157. monsterops-1.12.0/monsterops/modules/nas_manager/static/nas_manager.js +1353 -0
  158. monsterops-1.12.0/monsterops/modules/nas_manager/vendor_map.py +71 -0
  159. monsterops-1.12.0/monsterops/modules/nas_manager/worker.py +89 -0
  160. monsterops-1.12.0/monsterops/modules/notifications/__init__.py +0 -0
  161. monsterops-1.12.0/monsterops/modules/notifications/channels.py +97 -0
  162. monsterops-1.12.0/monsterops/modules/notifications/models.py +61 -0
  163. monsterops-1.12.0/monsterops/modules/notifications/router.py +178 -0
  164. monsterops-1.12.0/monsterops/modules/notifications/schemas.py +81 -0
  165. monsterops-1.12.0/monsterops/modules/notifications/static/manifest.json +12 -0
  166. monsterops-1.12.0/monsterops/modules/notifications/static/notifications.js +881 -0
  167. monsterops-1.12.0/monsterops/modules/notifications/worker.py +208 -0
  168. monsterops-1.12.0/monsterops/modules/radius_logs/__init__.py +0 -0
  169. monsterops-1.12.0/monsterops/modules/radius_logs/static/manifest.json +5 -0
  170. monsterops-1.12.0/monsterops/modules/radius_logs/static/radius_logs.js +407 -0
  171. monsterops-1.12.0/monsterops/modules/realms/__init__.py +0 -0
  172. monsterops-1.12.0/monsterops/modules/realms/enforcement/__init__.py +16 -0
  173. monsterops-1.12.0/monsterops/modules/realms/enforcement/base.py +47 -0
  174. monsterops-1.12.0/monsterops/modules/realms/enforcement/freeradius.py +207 -0
  175. monsterops-1.12.0/monsterops/modules/realms/ldap_probe.py +132 -0
  176. monsterops-1.12.0/monsterops/modules/realms/ldap_sync.py +544 -0
  177. monsterops-1.12.0/monsterops/modules/realms/models.py +199 -0
  178. monsterops-1.12.0/monsterops/modules/realms/probe.py +111 -0
  179. monsterops-1.12.0/monsterops/modules/realms/proxyconf.py +135 -0
  180. monsterops-1.12.0/monsterops/modules/realms/radius.dict +4 -0
  181. monsterops-1.12.0/monsterops/modules/realms/router.py +1181 -0
  182. monsterops-1.12.0/monsterops/modules/realms/schemas.py +402 -0
  183. monsterops-1.12.0/monsterops/modules/realms/static/manifest.json +12 -0
  184. monsterops-1.12.0/monsterops/modules/realms/static/realms.js +1604 -0
  185. monsterops-1.12.0/monsterops/modules/reports/__init__.py +0 -0
  186. monsterops-1.12.0/monsterops/modules/reports/router.py +302 -0
  187. monsterops-1.12.0/monsterops/modules/reports/schemas.py +39 -0
  188. monsterops-1.12.0/monsterops/modules/reports/static/manifest.json +12 -0
  189. monsterops-1.12.0/monsterops/modules/reports/static/reports.js +552 -0
  190. monsterops-1.12.0/monsterops/modules/scheduler/__init__.py +0 -0
  191. monsterops-1.12.0/monsterops/modules/scheduler/jobs.py +455 -0
  192. monsterops-1.12.0/monsterops/modules/scheduler/models.py +45 -0
  193. monsterops-1.12.0/monsterops/modules/scheduler/router.py +160 -0
  194. monsterops-1.12.0/monsterops/modules/scheduler/schemas.py +56 -0
  195. monsterops-1.12.0/monsterops/modules/scheduler/service.py +172 -0
  196. monsterops-1.12.0/monsterops/modules/scheduler/static/manifest.json +5 -0
  197. monsterops-1.12.0/monsterops/modules/scheduler/static/scheduler.js +465 -0
  198. monsterops-1.12.0/monsterops/modules/system/__init__.py +0 -0
  199. monsterops-1.12.0/monsterops/modules/system/router.py +304 -0
  200. monsterops-1.12.0/monsterops/modules/system/static/manifest.json +12 -0
  201. monsterops-1.12.0/monsterops/modules/system/static/system.js +1006 -0
  202. monsterops-1.12.0/monsterops/modules/users/__init__.py +0 -0
  203. monsterops-1.12.0/monsterops/modules/users/models.py +58 -0
  204. monsterops-1.12.0/monsterops/modules/users/router.py +1205 -0
  205. monsterops-1.12.0/monsterops/modules/users/schemas.py +235 -0
  206. monsterops-1.12.0/monsterops/modules/users/static/manifest.json +12 -0
  207. monsterops-1.12.0/monsterops/modules/users/static/users.js +1817 -0
  208. monsterops-1.12.0/monsterops/modules/vpn/__init__.py +0 -0
  209. monsterops-1.12.0/monsterops/modules/vpn/backends/__init__.py +0 -0
  210. monsterops-1.12.0/monsterops/modules/vpn/backends/base.py +145 -0
  211. monsterops-1.12.0/monsterops/modules/vpn/backends/l2tp_ipsec.py +242 -0
  212. monsterops-1.12.0/monsterops/modules/vpn/backends/wireguard.py +128 -0
  213. monsterops-1.12.0/monsterops/modules/vpn/models.py +44 -0
  214. monsterops-1.12.0/monsterops/modules/vpn/router.py +268 -0
  215. monsterops-1.12.0/monsterops/modules/vpn/schemas.py +271 -0
  216. monsterops-1.12.0/monsterops/modules/vpn/service.py +32 -0
  217. monsterops-1.12.0/monsterops/modules/vpn/static/manifest.json +12 -0
  218. monsterops-1.12.0/monsterops/modules/vpn/static/vpn.js +618 -0
  219. monsterops-1.12.0/monsterops/modules/vpn/wgkeys.py +69 -0
  220. monsterops-1.12.0/monsterops/modules/vpn/worker.py +41 -0
  221. monsterops-1.12.0/monsterops/modules/webhooks/__init__.py +0 -0
  222. monsterops-1.12.0/monsterops/modules/webhooks/handler.py +122 -0
  223. monsterops-1.12.0/monsterops/modules/webhooks/models.py +21 -0
  224. monsterops-1.12.0/monsterops/modules/webhooks/router.py +225 -0
  225. monsterops-1.12.0/monsterops/modules/webhooks/static/manifest.json +5 -0
  226. monsterops-1.12.0/monsterops/modules/webhooks/static/webhooks.js +506 -0
  227. monsterops-1.12.0/monsterops/pagination.py +20 -0
  228. monsterops-1.12.0/monsterops/plugins/__init__.py +0 -0
  229. monsterops-1.12.0/monsterops/plugins/loader.py +49 -0
  230. monsterops-1.12.0/monsterops/radius_reload.py +115 -0
  231. monsterops-1.12.0/monsterops/static/css/theme.css +401 -0
  232. monsterops-1.12.0/monsterops/static/img/monsterops-mascot.png +0 -0
  233. monsterops-1.12.0/monsterops/static/index.html +25 -0
  234. monsterops-1.12.0/monsterops/static/js/api.js +131 -0
  235. monsterops-1.12.0/monsterops/static/js/app.js +199 -0
  236. monsterops-1.12.0/monsterops/static/js/components/app-confirm.js +145 -0
  237. monsterops-1.12.0/monsterops/static/js/components/app-sidebar.js +653 -0
  238. monsterops-1.12.0/monsterops/static/js/components/app-statusbar.js +187 -0
  239. monsterops-1.12.0/monsterops/static/js/components/app-toast.js +105 -0
  240. monsterops-1.12.0/monsterops/static/js/components/base-component.js +51 -0
  241. monsterops-1.12.0/monsterops/static/js/components/mr-card.js +93 -0
  242. monsterops-1.12.0/monsterops/static/js/components/mr-modal.js +179 -0
  243. monsterops-1.12.0/monsterops/static/js/components/server-console.js +519 -0
  244. monsterops-1.12.0/monsterops/static/js/components/signal-pulse.js +103 -0
  245. monsterops-1.12.0/monsterops/static/js/loader.js +22 -0
  246. monsterops-1.12.0/monsterops/static/js/router.js +49 -0
  247. monsterops-1.12.0/monsterops/static/js/utils/countries.js +263 -0
  248. monsterops-1.12.0/monsterops/static/js/utils/empty.js +151 -0
  249. monsterops-1.12.0/monsterops/static/js/utils/form.js +88 -0
  250. monsterops-1.12.0/monsterops/static/js/utils/geo.js +45 -0
  251. monsterops-1.12.0/monsterops/static/js/utils/poll.js +41 -0
  252. monsterops-1.12.0/monsterops/static/js/utils/sparkline.js +96 -0
  253. monsterops-1.12.0/monsterops/static/js/utils/table.js +186 -0
  254. monsterops-1.12.0/monsterops/static/js/views/login.js +167 -0
  255. monsterops-1.12.0/monsterops/static/js/views/setup.js +146 -0
  256. monsterops-1.12.0/monsterops/static/js/views/style_guide.js +289 -0
  257. monsterops-1.12.0/pyproject.toml +69 -0
  258. monsterops-1.12.0/scripts/mr-firewall-panic.sh +47 -0
@@ -0,0 +1,38 @@
1
+ # MonsterOps environment variables
2
+ # Copy this file to .env and fill in real values before starting.
3
+
4
+ # PostgreSQL connection string (asyncpg dialect)
5
+ MONSTEROPS_DATABASE_URL=postgresql+asyncpg://radius:CHANGE_ME@localhost/radius
6
+
7
+ # JWT signing secret — generate with: openssl rand -hex 32
8
+ MONSTEROPS_SECRET_KEY=CHANGE_ME_USE_32_RANDOM_BYTES
9
+
10
+ # Set to true only in development — exposes /docs and /redoc
11
+ MONSTEROPS_DEBUG=false
12
+
13
+ # Log level: debug | info | warning | error
14
+ MONSTEROPS_LOG_LEVEL=info
15
+
16
+ # Comma-separated allowed CORS origins (leave empty to disable CORS)
17
+ # MONSTEROPS_ALLOWED_ORIGINS=https://your-domain.com
18
+
19
+ # Directory where the VPN module writes WireGuard tunnel configs (mode 0600).
20
+ # Must be writable by the service user; the private key is stored here.
21
+ # MONSTEROPS_VPN_CONFIG_DIR=/etc/monsterops/vpn
22
+
23
+ # ── Database connection pool ──────────────────────────────────────────────────
24
+ # Steady pool + burst overflow. Raise pool size on busy instances with many
25
+ # concurrent admins/log streams; keep pool_size + max_overflow below the
26
+ # PostgreSQL max_connections budget for this app.
27
+ # MONSTEROPS_DB_POOL_SIZE=10
28
+ # MONSTEROPS_DB_MAX_OVERFLOW=20
29
+ # MONSTEROPS_DB_POOL_TIMEOUT=30
30
+ # MONSTEROPS_DB_POOL_RECYCLE=1800
31
+
32
+ # ── Log retention (days) ──────────────────────────────────────────────────────
33
+ # Used by the "Log Retention" scheduler job (create it under Scheduler → New
34
+ # Job). 0 = keep forever.
35
+ # MONSTEROPS_RETENTION_AUTH_LOG_DAYS=90 # radpostauth (RADIUS auth attempts)
36
+ # MONSTEROPS_RETENTION_AUDIT_LOG_DAYS=365 # audit_log (admin actions)
37
+ # MONSTEROPS_RETENTION_NOTIFICATION_DAYS=90 # notification history
38
+ # MONSTEROPS_RETENTION_DISPATCH_LOG_DAYS=180 # NAS command dispatch log
@@ -0,0 +1,21 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ dist/
5
+ build/
6
+ .venv/
7
+ venv/
8
+ .env
9
+ .env.local
10
+ *.sqlite3
11
+ .mypy_cache/
12
+ .ruff_cache/
13
+ .pytest_cache/
14
+ node_modules/
15
+ logs/
16
+ data/
17
+
18
+ # Editor / OS
19
+ .DS_Store
20
+ .idea/
21
+ .vscode/
@@ -0,0 +1,110 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ### Added
6
+
7
+ - **`pip install monsterops` now works end to end.** The database migrations ship
8
+ inside the package, and a new `monsterops migrate` command creates or upgrades the
9
+ schema — so you can install from PyPI, run `monsterops migrate`, then
10
+ `monsterops serve` without a source checkout. From a checkout, `alembic upgrade head`
11
+ still works too.
12
+
13
+ ### Fixed
14
+
15
+ - `monsterops.__version__` now reports the installed package version instead of a
16
+ stale hardcoded value.
17
+
18
+ ## v1.12.0 — 2026-07-20
19
+
20
+ ### Added
21
+
22
+ - **Point a NAS at this RADIUS server in one click.** A new **RADIUS Setup** tab
23
+ in NAS Manager generates the vendor-specific RADIUS-client config for a managed
24
+ device — you tick which services should authenticate (PPP/PPPoE, hotspot, admin
25
+ login, 802.1X), preview the exact commands, then push them over SSH. The running
26
+ config is snapshotted first for rollback. MikroTik (RouterOS v6 and v7) and
27
+ Huawei produce real, pushable config; other vendors get a preview-only reference
28
+ block. The generated MikroTik config also enables CoA/Disconnect so you can drop
29
+ a live session from the UI.
30
+ - **Automation can run a command on a NAS.** A new **Run NAS command** rule action
31
+ runs a single CLI command on a managed NAS over SSH when a matching event fires,
32
+ using the credentials NAS Manager already stores. Commands can reference the
33
+ triggering event (`{entity_id}`, `{actor}`, `{type}`, `{data.<key>}`) — for
34
+ example, kicking a user's live session the moment they're disabled.
35
+ - **Secret-key rotation.** A new `monsterops rotate-secret-key` command re-encrypts
36
+ every stored credential (NAS Manager SSH secrets and directory bind passwords)
37
+ when you change `MONSTEROPS_SECRET_KEY`, so rotating the key no longer orphans
38
+ them. It is abort-safe and supports a `--dry-run`.
39
+ - **Server Console command history.** The console's command palette now keeps a
40
+ "Recent runs" list — each command with its result and a timestamp — that persists
41
+ across page reloads.
42
+
43
+ ### Changed
44
+
45
+ - **The Server Console is now off by default.** Because its palette restarts
46
+ FreeRADIUS and runs migrations from the browser, it is opt-in: set
47
+ `MONSTEROPS_CONSOLE_ENABLED=true` to enable it. Installs that relied on the
48
+ console will need to set this.
49
+
50
+ ## v1.11.1 — 2026-07-16
51
+
52
+ ### Added
53
+
54
+ - **NAS reachability monitoring.** A background ICMP probe reports a true
55
+ reachable/unreachable state per NAS on the dashboard, distinct from the existing
56
+ activity-based "idle" — so a quiet device is shown *idle but up*, while one that
57
+ has genuinely dropped off the network is shown *down*. Subnet/wildcard clients
58
+ are marked *skipped*. Configurable via `MONSTEROPS_NAS_PROBE_ENABLED`.
59
+
60
+ ### Fixed
61
+
62
+ - **Delegated Active Directory logins after wiring the host.** The AD provisioning
63
+ script now restarts FreeRADIUS instead of reloading it, so the newly added
64
+ authentication module is loaded and delegated (live-AD-password) logins succeed.
65
+
66
+ ## v1.11.0 — 2026-07-16
67
+
68
+ ### Added
69
+
70
+ - **Per-realm authentication with Active Directory.** Authentication is now
71
+ configured per realm as an identity source plus a method: **Local password**
72
+ (MonsterOps owns each subscriber's password; works offline, any protocol) or
73
+ **Directory-delegated** (subscribers sign in with their real Active Directory
74
+ password, verified live against a Domain Controller via winbind/`ntlm_auth`).
75
+ Import all or selected users from AD, map AD groups to MonsterOps groups and
76
+ plans, and see each account's source (its AD realm, or Local) in the Users
77
+ view. Delegated realms show a **host: ready / needs join** indicator with the
78
+ exact one-time setup command. Full walkthrough in the
79
+ [Active Directory guide](docs/active-directory-auth.md).
80
+ - **Adaptive firewall access control.** The nftables firewall manager gained
81
+ brute-force auto-blocking with a structured audit trail and a dashboard
82
+ widget; **"allow only this country"** inverse blocking with layered
83
+ anti-lockout guards that keep management (SSH/web) and RADIUS reachable; and
84
+ self-lockout / NAS-impact warnings before a block takes effect, so a
85
+ fat-fingered blocklist entry can't cut off admin access or silently break a
86
+ NAS. A last-resort `scripts/mr-firewall-panic.sh` restores connectivity from
87
+ the shell.
88
+
89
+ ### Changed
90
+
91
+ - **Faster large-table browsing.** Live sessions, accounting, and auth logs use
92
+ keyset pagination for consistent performance on large datasets.
93
+
94
+ ### Fixed
95
+
96
+ - **Dashboard:** the header icons (drill-through chevron, refresh, settings
97
+ gear) no longer briefly flash oversized and blue when returning to the
98
+ Dashboard from another page.
99
+ - **Sidebar:** collapsing the sidebar to its icon rail now hides labels cleanly
100
+ and keeps the icons centred.
101
+
102
+ ## v1.10.0 — Initial public release
103
+
104
+ The first public release of MonsterOps — a self-hosted network operations
105
+ platform for FreeRADIUS environments. Includes user & group management, NAS
106
+ device and NAS SSH/Telnet management, IP pool management, live session
107
+ monitoring with CoA, auth logs & analytics, reports, RADIUS proxy & realms,
108
+ WireGuard and L2TP/IPsec VPN tunnels, an nftables firewall manager, automation
109
+ & scheduling, webhooks & event bus, a scoped REST API, and integrations
110
+ (Zabbix, Graylog, MaxMind GeoIP2).
@@ -0,0 +1,18 @@
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update \
6
+ && apt-get install -y --no-install-recommends postgresql-client \
7
+ && rm -rf /var/lib/apt/lists/*
8
+
9
+ COPY pyproject.toml LICENSE README.md ./
10
+ COPY monsterops/ monsterops/
11
+ COPY alembic/ alembic/
12
+ COPY alembic.ini .
13
+
14
+ RUN pip install --no-cache-dir -e .
15
+
16
+ EXPOSE 8000
17
+
18
+ CMD ["monsterops", "serve", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NLRI65000
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,138 @@
1
+ Metadata-Version: 2.4
2
+ Name: monsterops
3
+ Version: 1.12.0
4
+ Summary: A self-hosted network operations platform built around FreeRADIUS
5
+ Project-URL: Homepage, https://github.com/NLRI65000/MonsterOps
6
+ Project-URL: Repository, https://github.com/NLRI65000/MonsterOps
7
+ Project-URL: Issues, https://github.com/NLRI65000/MonsterOps/issues
8
+ Project-URL: Changelog, https://github.com/NLRI65000/MonsterOps/blob/main/CHANGELOG.md
9
+ Author-email: NLRI65000 <nlrigithub@hotmail.com>
10
+ License: MIT License
11
+
12
+ Copyright (c) 2026 NLRI65000
13
+
14
+ Permission is hereby granted, free of charge, to any person obtaining a copy
15
+ of this software and associated documentation files (the "Software"), to deal
16
+ in the Software without restriction, including without limitation the rights
17
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18
+ copies of the Software, and to permit persons to whom the Software is
19
+ furnished to do so, subject to the following conditions:
20
+
21
+ The above copyright notice and this permission notice shall be included in all
22
+ copies or substantial portions of the Software.
23
+
24
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30
+ SOFTWARE.
31
+ License-File: LICENSE
32
+ Keywords: aaa,authentication,daloradius,fastapi,freeradius,network,radius
33
+ Classifier: Development Status :: 4 - Beta
34
+ Classifier: Environment :: Web Environment
35
+ Classifier: Framework :: FastAPI
36
+ Classifier: Intended Audience :: System Administrators
37
+ Classifier: License :: OSI Approved :: MIT License
38
+ Classifier: Operating System :: POSIX :: Linux
39
+ Classifier: Programming Language :: Python :: 3
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Topic :: Internet
44
+ Classifier: Topic :: System :: Systems Administration :: Authentication/Directory
45
+ Requires-Python: >=3.11
46
+ Requires-Dist: alembic>=1.13.0
47
+ Requires-Dist: apscheduler<4,>=3.10
48
+ Requires-Dist: argon2-cffi>=23.1.0
49
+ Requires-Dist: asyncpg>=0.29.0
50
+ Requires-Dist: bcrypt>=4.0.0
51
+ Requires-Dist: cryptography>=42.0.0
52
+ Requires-Dist: fastapi>=0.111.0
53
+ Requires-Dist: geoip2>=4.8.0
54
+ Requires-Dist: httpx>=0.27.0
55
+ Requires-Dist: ldap3>=2.9.1
56
+ Requires-Dist: netmiko>=4.0.0
57
+ Requires-Dist: pydantic-settings>=2.3.0
58
+ Requires-Dist: pyjwt>=2.8.0
59
+ Requires-Dist: pyrad>=2.4
60
+ Requires-Dist: python-multipart>=0.0.9
61
+ Requires-Dist: slowapi>=0.1.9
62
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.0
63
+ Requires-Dist: uvicorn[standard]>=0.30.0
64
+ Description-Content-Type: text/markdown
65
+
66
+ <p align="center">
67
+ <img src="assets/MonsterOpsDO.png" alt="MonsterOps — Monitor. Manage. Automate." width="460" />
68
+ </p>
69
+
70
+ # MonsterOps
71
+
72
+ **MonsterOps** is a self-hosted network operations platform for ISPs, enterprise networks, and anyone running a FreeRADIUS environment — RADIUS users & groups, NAS devices, IP pools, sessions & accounting, auth analytics, RADIUS proxy/realms, VPN tunnels, a safe nftables firewall manager, automation, and a REST API, all in one dashboard.
73
+
74
+ Built with **FastAPI + PostgreSQL** and a **vanilla-JS Web Components** frontend — a single Python package, no Node.js, no build step.
75
+
76
+ ## Highlights
77
+
78
+ - **RADIUS users & groups** — full `radcheck`/`radreply`/`radusergroup` CRUD, bulk CSV, per-user session & auth history
79
+ - **NAS management** — vendor presets and NAS groups, ICMP reachability monitoring, plus an SSH/Telnet **NAS Manager** (pull, version, diff, and push config; one-click "point a NAS at RADIUS" deploy; encrypted credentials)
80
+ - **Firewall manager** — a dedicated nftables table with staged apply, snapshot + auto-rollback, and adaptive access control (brute-force / country blocking) built to keep you from locking yourself out
81
+ - **Sessions & analytics** — live sessions with CoA disconnect, accounting history, and auth logs with geo-location + anomaly detection
82
+ - **And more** — RADIUS proxy & realms, WireGuard / L2TP-IPsec VPN tunnels, automation & scheduling, webhooks, a scoped REST API, and integrations (Zabbix, Graylog, GeoIP2)
83
+
84
+ See the full capability list in the **[Reference](docs/reference.md)**.
85
+
86
+ ## Get Started
87
+
88
+ Requires **Python 3.11+** and a reachable **PostgreSQL 15+** database (the same one FreeRADIUS uses).
89
+
90
+ ### Production (recommended)
91
+
92
+ ```bash
93
+ git clone https://github.com/NLRI65000/MonsterOps.git
94
+ cd MonsterOps
95
+ sudo bash deploy/install.sh
96
+ ```
97
+
98
+ The installer sets up the service user, database, FreeRADIUS SQL integration, a systemd unit, and optional tooling (VPN backends, nftables, sudoers rules). Re-run `deploy/upgrade.sh` to update an existing install in place.
99
+
100
+ ### From PyPI
101
+
102
+ ```bash
103
+ pip install monsterops
104
+ export MONSTEROPS_DATABASE_URL=postgresql+asyncpg://user:pass@localhost/radius
105
+ export MONSTEROPS_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
106
+ monsterops migrate # create/upgrade the database schema
107
+ monsterops serve --host 0.0.0.0 --port 8000
108
+ ```
109
+
110
+ The migrations ship inside the package, so `monsterops migrate` works without a source checkout. (You can also put the settings in a `.env` file in the working directory instead of exporting them.)
111
+
112
+ ### From source (manual)
113
+
114
+ ```bash
115
+ git clone https://github.com/NLRI65000/MonsterOps.git
116
+ cd MonsterOps
117
+ pip install -e .
118
+ cp .env.example .env # set MONSTEROPS_DATABASE_URL and MONSTEROPS_SECRET_KEY
119
+ monsterops migrate # or, from a checkout: alembic upgrade head
120
+ monsterops serve --host 0.0.0.0 --port 8000
121
+ ```
122
+
123
+ Then open `http://localhost:8000` and complete the first-run wizard to create your superadmin account.
124
+
125
+ > **Before production:** change `MONSTEROPS_SECRET_KEY` from its default (the app warns until you do) and serve over HTTPS. See the [User Guide](docs/user-guide.md).
126
+
127
+ ## Documentation
128
+
129
+ - **[User Guide](docs/user-guide.md)** — install, configure, navigate the UI, core features (including firewall safety), and finding logs
130
+ - **[Reference](docs/reference.md)** — full feature list, configuration variables, roles, CLI, architecture, plugins, tech stack, and roadmap
131
+
132
+ ## Security
133
+
134
+ Found a security vulnerability? **Please don't open a public issue.** Report it privately by email to **nlrigithub@hotmail.com** — see [SECURITY.md](SECURITY.md).
135
+
136
+ ## License
137
+
138
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,73 @@
1
+ <p align="center">
2
+ <img src="assets/MonsterOpsDO.png" alt="MonsterOps — Monitor. Manage. Automate." width="460" />
3
+ </p>
4
+
5
+ # MonsterOps
6
+
7
+ **MonsterOps** is a self-hosted network operations platform for ISPs, enterprise networks, and anyone running a FreeRADIUS environment — RADIUS users & groups, NAS devices, IP pools, sessions & accounting, auth analytics, RADIUS proxy/realms, VPN tunnels, a safe nftables firewall manager, automation, and a REST API, all in one dashboard.
8
+
9
+ Built with **FastAPI + PostgreSQL** and a **vanilla-JS Web Components** frontend — a single Python package, no Node.js, no build step.
10
+
11
+ ## Highlights
12
+
13
+ - **RADIUS users & groups** — full `radcheck`/`radreply`/`radusergroup` CRUD, bulk CSV, per-user session & auth history
14
+ - **NAS management** — vendor presets and NAS groups, ICMP reachability monitoring, plus an SSH/Telnet **NAS Manager** (pull, version, diff, and push config; one-click "point a NAS at RADIUS" deploy; encrypted credentials)
15
+ - **Firewall manager** — a dedicated nftables table with staged apply, snapshot + auto-rollback, and adaptive access control (brute-force / country blocking) built to keep you from locking yourself out
16
+ - **Sessions & analytics** — live sessions with CoA disconnect, accounting history, and auth logs with geo-location + anomaly detection
17
+ - **And more** — RADIUS proxy & realms, WireGuard / L2TP-IPsec VPN tunnels, automation & scheduling, webhooks, a scoped REST API, and integrations (Zabbix, Graylog, GeoIP2)
18
+
19
+ See the full capability list in the **[Reference](docs/reference.md)**.
20
+
21
+ ## Get Started
22
+
23
+ Requires **Python 3.11+** and a reachable **PostgreSQL 15+** database (the same one FreeRADIUS uses).
24
+
25
+ ### Production (recommended)
26
+
27
+ ```bash
28
+ git clone https://github.com/NLRI65000/MonsterOps.git
29
+ cd MonsterOps
30
+ sudo bash deploy/install.sh
31
+ ```
32
+
33
+ The installer sets up the service user, database, FreeRADIUS SQL integration, a systemd unit, and optional tooling (VPN backends, nftables, sudoers rules). Re-run `deploy/upgrade.sh` to update an existing install in place.
34
+
35
+ ### From PyPI
36
+
37
+ ```bash
38
+ pip install monsterops
39
+ export MONSTEROPS_DATABASE_URL=postgresql+asyncpg://user:pass@localhost/radius
40
+ export MONSTEROPS_SECRET_KEY=$(python -c "import secrets; print(secrets.token_urlsafe(32))")
41
+ monsterops migrate # create/upgrade the database schema
42
+ monsterops serve --host 0.0.0.0 --port 8000
43
+ ```
44
+
45
+ The migrations ship inside the package, so `monsterops migrate` works without a source checkout. (You can also put the settings in a `.env` file in the working directory instead of exporting them.)
46
+
47
+ ### From source (manual)
48
+
49
+ ```bash
50
+ git clone https://github.com/NLRI65000/MonsterOps.git
51
+ cd MonsterOps
52
+ pip install -e .
53
+ cp .env.example .env # set MONSTEROPS_DATABASE_URL and MONSTEROPS_SECRET_KEY
54
+ monsterops migrate # or, from a checkout: alembic upgrade head
55
+ monsterops serve --host 0.0.0.0 --port 8000
56
+ ```
57
+
58
+ Then open `http://localhost:8000` and complete the first-run wizard to create your superadmin account.
59
+
60
+ > **Before production:** change `MONSTEROPS_SECRET_KEY` from its default (the app warns until you do) and serve over HTTPS. See the [User Guide](docs/user-guide.md).
61
+
62
+ ## Documentation
63
+
64
+ - **[User Guide](docs/user-guide.md)** — install, configure, navigate the UI, core features (including firewall safety), and finding logs
65
+ - **[Reference](docs/reference.md)** — full feature list, configuration variables, roles, CLI, architecture, plugins, tech stack, and roadmap
66
+
67
+ ## Security
68
+
69
+ Found a security vulnerability? **Please don't open a public issue.** Report it privately by email to **nlrigithub@hotmail.com** — see [SECURITY.md](SECURITY.md).
70
+
71
+ ## License
72
+
73
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,25 @@
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ **Please do not report security vulnerabilities through public GitHub issues.**
6
+
7
+ If you believe you have found a security vulnerability in MonsterOps, report it
8
+ privately by email:
9
+
10
+ **nlrigithub@hotmail.com**
11
+
12
+ Please include as much of the following as you can:
13
+
14
+ - A description of the issue and its potential impact
15
+ - Steps to reproduce, or a proof of concept
16
+ - The affected version or commit
17
+ - Any suggested remediation
18
+
19
+ You will receive an acknowledgement, and we will work with you on a fix and
20
+ coordinated disclosure. Please give a reasonable amount of time for the issue
21
+ to be addressed before any public disclosure.
22
+
23
+ ## Supported Versions
24
+
25
+ The latest released version receives security updates.
@@ -0,0 +1 @@
1
+ Generic single-database configuration.
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from logging.config import fileConfig
5
+
6
+ from sqlalchemy import pool
7
+ from sqlalchemy.ext.asyncio import async_engine_from_config
8
+
9
+ import monsterops.modules.accounting.models # noqa: F401
10
+ import monsterops.modules.apikeys.models # noqa: F401
11
+
12
+ import monsterops.modules.auth.models # noqa: F401
13
+ import monsterops.modules.auth_logs.models # noqa: F401
14
+ import monsterops.modules.automation.models # noqa: F401
15
+ import monsterops.modules.groups.models # noqa: F401
16
+ import monsterops.modules.integrations.models # noqa: F401
17
+ import monsterops.modules.ip_pools.models # noqa: F401
18
+ import monsterops.modules.nas.models # noqa: F401
19
+ import monsterops.modules.notifications.models # noqa: F401
20
+ import monsterops.modules.scheduler.models # noqa: F401
21
+ import monsterops.modules.users.models # noqa: F401
22
+ import monsterops.modules.webhooks.models # noqa: F401
23
+ from alembic import context
24
+ from monsterops.config import settings
25
+ from monsterops.database import Base
26
+
27
+ config = context.config
28
+ config.set_main_option("sqlalchemy.url", settings.database_url)
29
+
30
+ if config.config_file_name is not None:
31
+ fileConfig(config.config_file_name)
32
+
33
+ target_metadata = Base.metadata
34
+
35
+
36
+ def run_migrations_offline() -> None:
37
+ url = config.get_main_option("sqlalchemy.url")
38
+ context.configure(
39
+ url=url,
40
+ target_metadata=target_metadata,
41
+ literal_binds=True,
42
+ dialect_opts={"paramstyle": "named"},
43
+ )
44
+ with context.begin_transaction():
45
+ context.run_migrations()
46
+
47
+
48
+ _SKIP_INDEXES = {"radacct_calss_idx", "radpostauth_class_idx"}
49
+
50
+
51
+ def _include_object(obj, name, type_, reflected, compare_to):
52
+ if type_ == "index" and name in _SKIP_INDEXES:
53
+ return False
54
+ return True
55
+
56
+
57
+ def do_run_migrations(connection):
58
+ context.configure(
59
+ connection=connection,
60
+ target_metadata=target_metadata,
61
+ include_object=_include_object,
62
+ )
63
+ with context.begin_transaction():
64
+ context.run_migrations()
65
+
66
+
67
+ async def run_async_migrations() -> None:
68
+ connectable = async_engine_from_config(
69
+ config.get_section(config.config_ini_section, {}),
70
+ prefix="sqlalchemy.",
71
+ poolclass=pool.NullPool,
72
+ )
73
+ async with connectable.connect() as connection:
74
+ await connection.run_sync(do_run_migrations)
75
+ await connectable.dispose()
76
+
77
+
78
+ def run_migrations_online() -> None:
79
+ asyncio.run(run_async_migrations())
80
+
81
+
82
+ if context.is_offline_mode():
83
+ run_migrations_offline()
84
+ else:
85
+ run_migrations_online()
@@ -0,0 +1,28 @@
1
+ """${message}
2
+
3
+ Revision ID: ${up_revision}
4
+ Revises: ${down_revision | comma,n}
5
+ Create Date: ${create_date}
6
+
7
+ """
8
+ from typing import Sequence, Union
9
+
10
+ from alembic import op
11
+ import sqlalchemy as sa
12
+ ${imports if imports else ""}
13
+
14
+ # revision identifiers, used by Alembic.
15
+ revision: str = ${repr(up_revision)}
16
+ down_revision: Union[str, Sequence[str], None] = ${repr(down_revision)}
17
+ branch_labels: Union[str, Sequence[str], None] = ${repr(branch_labels)}
18
+ depends_on: Union[str, Sequence[str], None] = ${repr(depends_on)}
19
+
20
+
21
+ def upgrade() -> None:
22
+ """Upgrade schema."""
23
+ ${upgrades if upgrades else "pass"}
24
+
25
+
26
+ def downgrade() -> None:
27
+ """Downgrade schema."""
28
+ ${downgrades if downgrades else "pass"}