monsterops 1.12.0__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.
- monsterops/__init__.py +7 -0
- monsterops/alembic/README +1 -0
- monsterops/alembic/env.py +85 -0
- monsterops/alembic/script.py.mako +28 -0
- monsterops/alembic/versions/a2f9c4b1e837_phase13_notifications.py +122 -0
- monsterops/alembic/versions/a4d1c7e6b520_firewall_autoblock.py +37 -0
- monsterops/alembic/versions/a9d4e7f2c1b5_realms_proxy.py +115 -0
- monsterops/alembic/versions/a9f3e2b1c0d8_retrograde_stop_trigger.py +39 -0
- monsterops/alembic/versions/b3e9a1f72c04_radpostauth_extra_columns.py +22 -0
- monsterops/alembic/versions/b6f2d8a3e91c_vpn_tunnels.py +54 -0
- monsterops/alembic/versions/b7d3f1e92a05_radpostauth_station_class_columns.py +21 -0
- monsterops/alembic/versions/b7f2c9a4e1d3_nas_reachability.py +35 -0
- monsterops/alembic/versions/b8e3f1a2d9c4_firewall_set_managed_source.py +22 -0
- monsterops/alembic/versions/c1f7b4a9d2e6_keyset_pagination_indexes.py +40 -0
- monsterops/alembic/versions/c2a8f4e71b93_radacct_unique_index_and_nasreload.py +27 -0
- monsterops/alembic/versions/c3f1a8e20d74_nas_manager.py +59 -0
- monsterops/alembic/versions/c7a1e3f92b84_nas_groups.py +48 -0
- monsterops/alembic/versions/c9e4b1f2a8d5_phase14_integrations.py +50 -0
- monsterops/alembic/versions/d1e5f8a2c3b7_phase15_apikeys_scheduler.py +75 -0
- monsterops/alembic/versions/d2e8b3f1a9c7_mr_bulk_jobs.py +32 -0
- monsterops/alembic/versions/d3b7f0a15c92_firewall_block_event.py +38 -0
- monsterops/alembic/versions/d4b2f6c81e93_nas_config_history.py +57 -0
- monsterops/alembic/versions/e1f4a9c2b6d8_mr_webhook_subs.py +36 -0
- monsterops/alembic/versions/e3a7f1c90d52_group_access_types.py +28 -0
- monsterops/alembic/versions/e5c9a1f3d827_auth_framework.py +134 -0
- monsterops/alembic/versions/e7c3a9d15f84_firewall.py +93 -0
- monsterops/alembic/versions/e85388a04f39_initial_schema.py +162 -0
- monsterops/alembic/versions/f2a8c4d97b16_log_table_indexes.py +19 -0
- monsterops/alembic/versions/f3a7c1e2d9b4_mr_automation_rules.py +39 -0
- monsterops/alembic/versions/f4c8d2a91b37_phase9_auth_enrichment.py +23 -0
- monsterops/alembic/versions/fd99a6deb43d_add_audit_log.py +35 -0
- monsterops/alembic.ini +150 -0
- monsterops/app.py +246 -0
- monsterops/cli.py +568 -0
- monsterops/config.py +106 -0
- monsterops/database.py +29 -0
- monsterops/events.py +51 -0
- monsterops/geo.py +108 -0
- monsterops/keyrotate.py +71 -0
- monsterops/limiter.py +6 -0
- monsterops/modules/__init__.py +0 -0
- monsterops/modules/accounting/__init__.py +0 -0
- monsterops/modules/accounting/coa.py +172 -0
- monsterops/modules/accounting/models.py +63 -0
- monsterops/modules/accounting/radius.dict +17 -0
- monsterops/modules/accounting/router.py +299 -0
- monsterops/modules/accounting/schemas.py +60 -0
- monsterops/modules/accounting/static/accounting.js +685 -0
- monsterops/modules/accounting/static/manifest.json +12 -0
- monsterops/modules/apikeys/__init__.py +0 -0
- monsterops/modules/apikeys/models.py +27 -0
- monsterops/modules/apikeys/router.py +210 -0
- monsterops/modules/apikeys/schemas.py +30 -0
- monsterops/modules/apikeys/static/apikeys.js +338 -0
- monsterops/modules/apikeys/static/manifest.json +5 -0
- monsterops/modules/apikeys/v1.py +754 -0
- monsterops/modules/auth/__init__.py +0 -0
- monsterops/modules/auth/models.py +40 -0
- monsterops/modules/auth/router.py +333 -0
- monsterops/modules/auth/schemas.py +71 -0
- monsterops/modules/auth/utils.py +201 -0
- monsterops/modules/auth_logs/__init__.py +0 -0
- monsterops/modules/auth_logs/models.py +29 -0
- monsterops/modules/auth_logs/router.py +383 -0
- monsterops/modules/auth_logs/schemas.py +50 -0
- monsterops/modules/auth_logs/static/auth_logs.js +821 -0
- monsterops/modules/auth_logs/static/manifest.json +12 -0
- monsterops/modules/automation/__init__.py +0 -0
- monsterops/modules/automation/engine.py +335 -0
- monsterops/modules/automation/models.py +23 -0
- monsterops/modules/automation/router.py +169 -0
- monsterops/modules/automation/static/automation.js +639 -0
- monsterops/modules/automation/static/manifest.json +12 -0
- monsterops/modules/dashboard/__init__.py +0 -0
- monsterops/modules/dashboard/router.py +240 -0
- monsterops/modules/dashboard/schemas.py +62 -0
- monsterops/modules/dashboard/static/dashboard.js +1074 -0
- monsterops/modules/dashboard/static/manifest.json +7 -0
- monsterops/modules/firewall/__init__.py +0 -0
- monsterops/modules/firewall/generator.py +203 -0
- monsterops/modules/firewall/geoblock.py +149 -0
- monsterops/modules/firewall/models.py +114 -0
- monsterops/modules/firewall/nft.py +96 -0
- monsterops/modules/firewall/presets.py +81 -0
- monsterops/modules/firewall/router.py +665 -0
- monsterops/modules/firewall/schemas.py +193 -0
- monsterops/modules/firewall/service.py +543 -0
- monsterops/modules/firewall/static/firewall.js +1048 -0
- monsterops/modules/firewall/static/manifest.json +12 -0
- monsterops/modules/firewall/validators.py +79 -0
- monsterops/modules/firewall/worker.py +168 -0
- monsterops/modules/groups/__init__.py +0 -0
- monsterops/modules/groups/models.py +40 -0
- monsterops/modules/groups/router.py +601 -0
- monsterops/modules/groups/schemas.py +85 -0
- monsterops/modules/groups/static/groups.js +1100 -0
- monsterops/modules/groups/static/manifest.json +12 -0
- monsterops/modules/health/__init__.py +0 -0
- monsterops/modules/health/router.py +574 -0
- monsterops/modules/health/schemas.py +36 -0
- monsterops/modules/health/static/health.js +519 -0
- monsterops/modules/health/static/manifest.json +12 -0
- monsterops/modules/integrations/__init__.py +0 -0
- monsterops/modules/integrations/graylog_client.py +108 -0
- monsterops/modules/integrations/models.py +21 -0
- monsterops/modules/integrations/router.py +257 -0
- monsterops/modules/integrations/schemas.py +38 -0
- monsterops/modules/integrations/static/img/graylog.svg +1 -0
- monsterops/modules/integrations/static/img/zabbix.svg +1 -0
- monsterops/modules/integrations/static/integrations.js +1166 -0
- monsterops/modules/integrations/static/manifest.json +5 -0
- monsterops/modules/integrations/zabbix_client.py +178 -0
- monsterops/modules/ip_pools/__init__.py +0 -0
- monsterops/modules/ip_pools/models.py +20 -0
- monsterops/modules/ip_pools/router.py +253 -0
- monsterops/modules/ip_pools/schemas.py +54 -0
- monsterops/modules/ip_pools/static/ip_pools.js +942 -0
- monsterops/modules/ip_pools/static/manifest.json +12 -0
- monsterops/modules/nas/__init__.py +0 -0
- monsterops/modules/nas/models.py +64 -0
- monsterops/modules/nas/probe.py +142 -0
- monsterops/modules/nas/radius_attr_hints.py +167 -0
- monsterops/modules/nas/router.py +630 -0
- monsterops/modules/nas/schemas.py +152 -0
- monsterops/modules/nas/static/manifest.json +12 -0
- monsterops/modules/nas/static/nas.js +1782 -0
- monsterops/modules/nas_manager/__init__.py +0 -0
- monsterops/modules/nas_manager/crypto.py +30 -0
- monsterops/modules/nas_manager/history.py +126 -0
- monsterops/modules/nas_manager/models.py +80 -0
- monsterops/modules/nas_manager/radius_deploy.py +264 -0
- monsterops/modules/nas_manager/router.py +873 -0
- monsterops/modules/nas_manager/schemas.py +258 -0
- monsterops/modules/nas_manager/service.py +125 -0
- monsterops/modules/nas_manager/static/manifest.json +5 -0
- monsterops/modules/nas_manager/static/nas_manager.js +1353 -0
- monsterops/modules/nas_manager/vendor_map.py +71 -0
- monsterops/modules/nas_manager/worker.py +89 -0
- monsterops/modules/notifications/__init__.py +0 -0
- monsterops/modules/notifications/channels.py +97 -0
- monsterops/modules/notifications/models.py +61 -0
- monsterops/modules/notifications/router.py +178 -0
- monsterops/modules/notifications/schemas.py +81 -0
- monsterops/modules/notifications/static/manifest.json +12 -0
- monsterops/modules/notifications/static/notifications.js +881 -0
- monsterops/modules/notifications/worker.py +208 -0
- monsterops/modules/radius_logs/__init__.py +0 -0
- monsterops/modules/radius_logs/static/manifest.json +5 -0
- monsterops/modules/radius_logs/static/radius_logs.js +407 -0
- monsterops/modules/realms/__init__.py +0 -0
- monsterops/modules/realms/enforcement/__init__.py +16 -0
- monsterops/modules/realms/enforcement/base.py +47 -0
- monsterops/modules/realms/enforcement/freeradius.py +207 -0
- monsterops/modules/realms/ldap_probe.py +132 -0
- monsterops/modules/realms/ldap_sync.py +544 -0
- monsterops/modules/realms/models.py +199 -0
- monsterops/modules/realms/probe.py +111 -0
- monsterops/modules/realms/proxyconf.py +135 -0
- monsterops/modules/realms/radius.dict +4 -0
- monsterops/modules/realms/router.py +1181 -0
- monsterops/modules/realms/schemas.py +402 -0
- monsterops/modules/realms/static/manifest.json +12 -0
- monsterops/modules/realms/static/realms.js +1604 -0
- monsterops/modules/reports/__init__.py +0 -0
- monsterops/modules/reports/router.py +302 -0
- monsterops/modules/reports/schemas.py +39 -0
- monsterops/modules/reports/static/manifest.json +12 -0
- monsterops/modules/reports/static/reports.js +552 -0
- monsterops/modules/scheduler/__init__.py +0 -0
- monsterops/modules/scheduler/jobs.py +455 -0
- monsterops/modules/scheduler/models.py +45 -0
- monsterops/modules/scheduler/router.py +160 -0
- monsterops/modules/scheduler/schemas.py +56 -0
- monsterops/modules/scheduler/service.py +172 -0
- monsterops/modules/scheduler/static/manifest.json +5 -0
- monsterops/modules/scheduler/static/scheduler.js +465 -0
- monsterops/modules/system/__init__.py +0 -0
- monsterops/modules/system/router.py +304 -0
- monsterops/modules/system/static/manifest.json +12 -0
- monsterops/modules/system/static/system.js +1006 -0
- monsterops/modules/users/__init__.py +0 -0
- monsterops/modules/users/models.py +58 -0
- monsterops/modules/users/router.py +1205 -0
- monsterops/modules/users/schemas.py +235 -0
- monsterops/modules/users/static/manifest.json +12 -0
- monsterops/modules/users/static/users.js +1817 -0
- monsterops/modules/vpn/__init__.py +0 -0
- monsterops/modules/vpn/backends/__init__.py +0 -0
- monsterops/modules/vpn/backends/base.py +145 -0
- monsterops/modules/vpn/backends/l2tp_ipsec.py +242 -0
- monsterops/modules/vpn/backends/wireguard.py +128 -0
- monsterops/modules/vpn/models.py +44 -0
- monsterops/modules/vpn/router.py +268 -0
- monsterops/modules/vpn/schemas.py +271 -0
- monsterops/modules/vpn/service.py +32 -0
- monsterops/modules/vpn/static/manifest.json +12 -0
- monsterops/modules/vpn/static/vpn.js +618 -0
- monsterops/modules/vpn/wgkeys.py +69 -0
- monsterops/modules/vpn/worker.py +41 -0
- monsterops/modules/webhooks/__init__.py +0 -0
- monsterops/modules/webhooks/handler.py +122 -0
- monsterops/modules/webhooks/models.py +21 -0
- monsterops/modules/webhooks/router.py +225 -0
- monsterops/modules/webhooks/static/manifest.json +5 -0
- monsterops/modules/webhooks/static/webhooks.js +506 -0
- monsterops/pagination.py +20 -0
- monsterops/plugins/__init__.py +0 -0
- monsterops/plugins/loader.py +49 -0
- monsterops/radius_reload.py +115 -0
- monsterops/static/css/theme.css +401 -0
- monsterops/static/img/monsterops-mascot.png +0 -0
- monsterops/static/index.html +25 -0
- monsterops/static/js/api.js +131 -0
- monsterops/static/js/app.js +199 -0
- monsterops/static/js/components/app-confirm.js +145 -0
- monsterops/static/js/components/app-sidebar.js +653 -0
- monsterops/static/js/components/app-statusbar.js +187 -0
- monsterops/static/js/components/app-toast.js +105 -0
- monsterops/static/js/components/base-component.js +51 -0
- monsterops/static/js/components/mr-card.js +93 -0
- monsterops/static/js/components/mr-modal.js +179 -0
- monsterops/static/js/components/server-console.js +519 -0
- monsterops/static/js/components/signal-pulse.js +103 -0
- monsterops/static/js/loader.js +22 -0
- monsterops/static/js/router.js +49 -0
- monsterops/static/js/utils/countries.js +263 -0
- monsterops/static/js/utils/empty.js +151 -0
- monsterops/static/js/utils/form.js +88 -0
- monsterops/static/js/utils/geo.js +45 -0
- monsterops/static/js/utils/poll.js +41 -0
- monsterops/static/js/utils/sparkline.js +96 -0
- monsterops/static/js/utils/table.js +186 -0
- monsterops/static/js/views/login.js +167 -0
- monsterops/static/js/views/setup.js +146 -0
- monsterops/static/js/views/style_guide.js +289 -0
- monsterops-1.12.0.dist-info/METADATA +138 -0
- monsterops-1.12.0.dist-info/RECORD +240 -0
- monsterops-1.12.0.dist-info/WHEEL +4 -0
- monsterops-1.12.0.dist-info/entry_points.txt +2 -0
- monsterops-1.12.0.dist-info/licenses/LICENSE +21 -0
monsterops/__init__.py
ADDED
|
@@ -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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
|
|
2
|
+
from typing import Sequence, Union
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
from sqlalchemy.dialects import postgresql
|
|
6
|
+
|
|
7
|
+
from alembic import op
|
|
8
|
+
|
|
9
|
+
revision: str = "a2f9c4b1e837"
|
|
10
|
+
down_revision: Union[str, Sequence[str], None] = "e3a7f1c90d52"
|
|
11
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
12
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def upgrade() -> None:
|
|
16
|
+
op.create_table(
|
|
17
|
+
"mr_notification_channels",
|
|
18
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
|
19
|
+
sa.Column("name", sa.Text(), nullable=False),
|
|
20
|
+
sa.Column("type", sa.Text(), nullable=False),
|
|
21
|
+
sa.Column(
|
|
22
|
+
"config",
|
|
23
|
+
postgresql.JSONB(astext_type=sa.Text()),
|
|
24
|
+
server_default="{}",
|
|
25
|
+
nullable=False,
|
|
26
|
+
),
|
|
27
|
+
sa.Column("enabled", sa.Boolean(), nullable=False, default=True),
|
|
28
|
+
sa.Column(
|
|
29
|
+
"created_at",
|
|
30
|
+
sa.TIMESTAMP(timezone=True),
|
|
31
|
+
server_default=sa.text("now()"),
|
|
32
|
+
nullable=False,
|
|
33
|
+
),
|
|
34
|
+
sa.Column(
|
|
35
|
+
"updated_at",
|
|
36
|
+
sa.TIMESTAMP(timezone=True),
|
|
37
|
+
server_default=sa.text("now()"),
|
|
38
|
+
nullable=False,
|
|
39
|
+
),
|
|
40
|
+
sa.PrimaryKeyConstraint("id"),
|
|
41
|
+
sa.UniqueConstraint("name"),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
op.create_table(
|
|
45
|
+
"mr_notification_rules",
|
|
46
|
+
sa.Column("id", sa.Integer(), nullable=False),
|
|
47
|
+
sa.Column("name", sa.Text(), nullable=False),
|
|
48
|
+
sa.Column("event_type", sa.Text(), nullable=False),
|
|
49
|
+
sa.Column(
|
|
50
|
+
"config",
|
|
51
|
+
postgresql.JSONB(astext_type=sa.Text()),
|
|
52
|
+
server_default="{}",
|
|
53
|
+
nullable=False,
|
|
54
|
+
),
|
|
55
|
+
sa.Column("channel_id", sa.Integer(), nullable=True),
|
|
56
|
+
sa.Column("cooldown_minutes", sa.Integer(), nullable=False, server_default="60"),
|
|
57
|
+
sa.Column("enabled", sa.Boolean(), nullable=False, server_default="true"),
|
|
58
|
+
sa.Column("last_triggered", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
59
|
+
sa.Column(
|
|
60
|
+
"created_at",
|
|
61
|
+
sa.TIMESTAMP(timezone=True),
|
|
62
|
+
server_default=sa.text("now()"),
|
|
63
|
+
nullable=False,
|
|
64
|
+
),
|
|
65
|
+
sa.Column(
|
|
66
|
+
"updated_at",
|
|
67
|
+
sa.TIMESTAMP(timezone=True),
|
|
68
|
+
server_default=sa.text("now()"),
|
|
69
|
+
nullable=False,
|
|
70
|
+
),
|
|
71
|
+
sa.ForeignKeyConstraint(
|
|
72
|
+
["channel_id"],
|
|
73
|
+
["mr_notification_channels.id"],
|
|
74
|
+
ondelete="SET NULL",
|
|
75
|
+
),
|
|
76
|
+
sa.PrimaryKeyConstraint("id"),
|
|
77
|
+
)
|
|
78
|
+
op.create_index("ix_notification_rules_event_type", "mr_notification_rules", ["event_type"])
|
|
79
|
+
|
|
80
|
+
op.create_table(
|
|
81
|
+
"mr_notification_history",
|
|
82
|
+
sa.Column("id", sa.BigInteger(), nullable=False),
|
|
83
|
+
sa.Column("rule_id", sa.Integer(), nullable=True),
|
|
84
|
+
sa.Column("rule_name", sa.Text(), nullable=True),
|
|
85
|
+
sa.Column("channel_id", sa.Integer(), nullable=True),
|
|
86
|
+
sa.Column("channel_name", sa.Text(), nullable=True),
|
|
87
|
+
sa.Column("event_type", sa.Text(), nullable=False),
|
|
88
|
+
sa.Column("subject", sa.Text(), nullable=False),
|
|
89
|
+
sa.Column("message", sa.Text(), nullable=False),
|
|
90
|
+
sa.Column("status", sa.Text(), nullable=False),
|
|
91
|
+
sa.Column("error", sa.Text(), nullable=True),
|
|
92
|
+
sa.Column(
|
|
93
|
+
"created_at",
|
|
94
|
+
sa.TIMESTAMP(timezone=True),
|
|
95
|
+
server_default=sa.text("now()"),
|
|
96
|
+
nullable=False,
|
|
97
|
+
),
|
|
98
|
+
sa.ForeignKeyConstraint(
|
|
99
|
+
["channel_id"],
|
|
100
|
+
["mr_notification_channels.id"],
|
|
101
|
+
ondelete="SET NULL",
|
|
102
|
+
),
|
|
103
|
+
sa.ForeignKeyConstraint(
|
|
104
|
+
["rule_id"],
|
|
105
|
+
["mr_notification_rules.id"],
|
|
106
|
+
ondelete="SET NULL",
|
|
107
|
+
),
|
|
108
|
+
sa.PrimaryKeyConstraint("id"),
|
|
109
|
+
)
|
|
110
|
+
op.create_index(
|
|
111
|
+
"ix_notification_history_created_at",
|
|
112
|
+
"mr_notification_history",
|
|
113
|
+
["created_at"],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def downgrade() -> None:
|
|
118
|
+
op.drop_index("ix_notification_history_created_at", table_name="mr_notification_history")
|
|
119
|
+
op.drop_table("mr_notification_history")
|
|
120
|
+
op.drop_index("ix_notification_rules_event_type", table_name="mr_notification_rules")
|
|
121
|
+
op.drop_table("mr_notification_rules")
|
|
122
|
+
op.drop_table("mr_notification_channels")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "a4d1c7e6b520"
|
|
9
|
+
down_revision = "f2a8c4d97b16"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
op.add_column(
|
|
16
|
+
"mr_firewall_config",
|
|
17
|
+
sa.Column("autoblock_enabled", sa.Boolean(), nullable=False, server_default=sa.false()),
|
|
18
|
+
)
|
|
19
|
+
op.add_column(
|
|
20
|
+
"mr_firewall_config",
|
|
21
|
+
sa.Column("autoblock_threshold", sa.Integer(), nullable=False, server_default="10"),
|
|
22
|
+
)
|
|
23
|
+
op.add_column(
|
|
24
|
+
"mr_firewall_config",
|
|
25
|
+
sa.Column("autoblock_window", sa.Integer(), nullable=False, server_default="10"),
|
|
26
|
+
)
|
|
27
|
+
op.add_column(
|
|
28
|
+
"mr_firewall_config",
|
|
29
|
+
sa.Column("autoblock_ban_seconds", sa.Integer(), nullable=False, server_default="3600"),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def downgrade() -> None:
|
|
34
|
+
op.drop_column("mr_firewall_config", "autoblock_ban_seconds")
|
|
35
|
+
op.drop_column("mr_firewall_config", "autoblock_window")
|
|
36
|
+
op.drop_column("mr_firewall_config", "autoblock_threshold")
|
|
37
|
+
op.drop_column("mr_firewall_config", "autoblock_enabled")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "a9d4e7f2c1b5"
|
|
9
|
+
down_revision = "f3a7c1e2d9b4"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
op.create_table(
|
|
16
|
+
"mr_home_server",
|
|
17
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
18
|
+
sa.Column("name", sa.String(64), nullable=False, unique=True),
|
|
19
|
+
sa.Column("host", sa.Text(), nullable=False),
|
|
20
|
+
sa.Column("auth_port", sa.Integer(), nullable=False, server_default="1812"),
|
|
21
|
+
sa.Column("acct_port", sa.Integer(), nullable=False, server_default="1813"),
|
|
22
|
+
sa.Column("secret", sa.Text(), nullable=False),
|
|
23
|
+
sa.Column("type", sa.String(8), nullable=False, server_default="auth"),
|
|
24
|
+
sa.Column("response_window", sa.Integer(), nullable=False, server_default="20"),
|
|
25
|
+
sa.Column("zombie_period", sa.Integer(), nullable=False, server_default="40"),
|
|
26
|
+
sa.Column("revive_interval", sa.Integer(), nullable=False, server_default="120"),
|
|
27
|
+
sa.Column("vpn_interface", sa.String(32), nullable=True),
|
|
28
|
+
sa.Column("status", sa.String(16), nullable=False, server_default="unknown"),
|
|
29
|
+
sa.Column("last_rtt_ms", sa.Float(), nullable=True),
|
|
30
|
+
sa.Column("last_seen_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
31
|
+
sa.Column("last_probe_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
32
|
+
sa.Column(
|
|
33
|
+
"created_at",
|
|
34
|
+
sa.TIMESTAMP(timezone=True),
|
|
35
|
+
nullable=False,
|
|
36
|
+
server_default=sa.text("now()"),
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
op.create_table(
|
|
41
|
+
"mr_home_server_pool",
|
|
42
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
43
|
+
sa.Column("name", sa.String(64), nullable=False, unique=True),
|
|
44
|
+
sa.Column("pool_type", sa.String(24), nullable=False, server_default="fail-over"),
|
|
45
|
+
sa.Column(
|
|
46
|
+
"created_at",
|
|
47
|
+
sa.TIMESTAMP(timezone=True),
|
|
48
|
+
nullable=False,
|
|
49
|
+
server_default=sa.text("now()"),
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
op.create_table(
|
|
54
|
+
"mr_home_server_pool_member",
|
|
55
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
56
|
+
sa.Column(
|
|
57
|
+
"pool_id",
|
|
58
|
+
sa.Integer(),
|
|
59
|
+
sa.ForeignKey("mr_home_server_pool.id", ondelete="CASCADE"),
|
|
60
|
+
nullable=False,
|
|
61
|
+
),
|
|
62
|
+
sa.Column(
|
|
63
|
+
"server_id",
|
|
64
|
+
sa.Integer(),
|
|
65
|
+
sa.ForeignKey("mr_home_server.id", ondelete="CASCADE"),
|
|
66
|
+
nullable=False,
|
|
67
|
+
),
|
|
68
|
+
sa.Column("position", sa.Integer(), nullable=False, server_default="0"),
|
|
69
|
+
sa.UniqueConstraint("pool_id", "server_id", name="uq_pool_server"),
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
op.create_table(
|
|
73
|
+
"mr_realm",
|
|
74
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
75
|
+
sa.Column("name", sa.String(128), nullable=False, unique=True),
|
|
76
|
+
sa.Column(
|
|
77
|
+
"pool_id",
|
|
78
|
+
sa.Integer(),
|
|
79
|
+
sa.ForeignKey("mr_home_server_pool.id", ondelete="SET NULL"),
|
|
80
|
+
nullable=True,
|
|
81
|
+
),
|
|
82
|
+
sa.Column("strip_username", sa.Boolean(), nullable=False, server_default="true"),
|
|
83
|
+
sa.Column(
|
|
84
|
+
"created_at",
|
|
85
|
+
sa.TIMESTAMP(timezone=True),
|
|
86
|
+
nullable=False,
|
|
87
|
+
server_default=sa.text("now()"),
|
|
88
|
+
),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
op.create_table(
|
|
92
|
+
"mr_nas_group_realm",
|
|
93
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
94
|
+
sa.Column(
|
|
95
|
+
"nas_group_id",
|
|
96
|
+
sa.Integer(),
|
|
97
|
+
sa.ForeignKey("mr_nas_group.id", ondelete="CASCADE"),
|
|
98
|
+
nullable=False,
|
|
99
|
+
),
|
|
100
|
+
sa.Column(
|
|
101
|
+
"realm_id",
|
|
102
|
+
sa.Integer(),
|
|
103
|
+
sa.ForeignKey("mr_realm.id", ondelete="CASCADE"),
|
|
104
|
+
nullable=False,
|
|
105
|
+
),
|
|
106
|
+
sa.UniqueConstraint("nas_group_id", "realm_id", name="uq_nasgroup_realm"),
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def downgrade() -> None:
|
|
111
|
+
op.drop_table("mr_nas_group_realm")
|
|
112
|
+
op.drop_table("mr_realm")
|
|
113
|
+
op.drop_table("mr_home_server_pool_member")
|
|
114
|
+
op.drop_table("mr_home_server_pool")
|
|
115
|
+
op.drop_table("mr_home_server")
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from typing import Sequence, Union
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision: str = "a9f3e2b1c0d8"
|
|
9
|
+
down_revision: Union[str, Sequence[str], None] = "d1e5f8a2c3b7"
|
|
10
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
11
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def upgrade() -> None:
|
|
16
|
+
op.execute("""
|
|
17
|
+
CREATE OR REPLACE FUNCTION fn_prevent_retrograde_stop()
|
|
18
|
+
RETURNS TRIGGER AS $$
|
|
19
|
+
BEGIN
|
|
20
|
+
IF NEW.acctstoptime IS NOT NULL AND NEW.acctstoptime < NEW.acctstarttime THEN
|
|
21
|
+
NEW.acctstoptime := NULL;
|
|
22
|
+
NEW.acctsessiontime := NULL;
|
|
23
|
+
NEW.acctterminatecause := '';
|
|
24
|
+
END IF;
|
|
25
|
+
RETURN NEW;
|
|
26
|
+
END;
|
|
27
|
+
$$ LANGUAGE plpgsql
|
|
28
|
+
""")
|
|
29
|
+
op.execute("DROP TRIGGER IF EXISTS trg_prevent_retrograde_stop ON radacct")
|
|
30
|
+
op.execute("""
|
|
31
|
+
CREATE TRIGGER trg_prevent_retrograde_stop
|
|
32
|
+
BEFORE INSERT OR UPDATE ON radacct
|
|
33
|
+
FOR EACH ROW EXECUTE FUNCTION fn_prevent_retrograde_stop()
|
|
34
|
+
""")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def downgrade() -> None:
|
|
38
|
+
op.execute("DROP TRIGGER IF EXISTS trg_prevent_retrograde_stop ON radacct")
|
|
39
|
+
op.execute("DROP FUNCTION IF EXISTS fn_prevent_retrograde_stop()")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
from sqlalchemy.dialects.postgresql import INET
|
|
6
|
+
|
|
7
|
+
from alembic import op
|
|
8
|
+
|
|
9
|
+
revision = "b3e9a1f72c04"
|
|
10
|
+
down_revision = "c7a1e3f92b84"
|
|
11
|
+
branch_labels = None
|
|
12
|
+
depends_on = None
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def upgrade() -> None:
|
|
16
|
+
op.add_column("radpostauth", sa.Column("nasipaddress", INET(), nullable=True))
|
|
17
|
+
op.add_column("radpostauth", sa.Column("nasidentifier", sa.Text(), nullable=True))
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def downgrade() -> None:
|
|
21
|
+
op.drop_column("radpostauth", "nasidentifier")
|
|
22
|
+
op.drop_column("radpostauth", "nasipaddress")
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "b6f2d8a3e91c"
|
|
9
|
+
down_revision = "a9d4e7f2c1b5"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
op.create_table(
|
|
16
|
+
"mr_vpn_tunnel",
|
|
17
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
18
|
+
sa.Column("name", sa.String(15), nullable=False, unique=True),
|
|
19
|
+
sa.Column("type", sa.String(16), nullable=False, server_default="wireguard"),
|
|
20
|
+
sa.Column("enabled", sa.Boolean(), nullable=False, server_default="false"),
|
|
21
|
+
sa.Column("description", sa.String(120), nullable=True),
|
|
22
|
+
sa.Column("routes", sa.Text(), nullable=False, server_default=""),
|
|
23
|
+
sa.Column("wg_private_key", sa.Text(), nullable=True),
|
|
24
|
+
sa.Column("wg_public_key", sa.Text(), nullable=True),
|
|
25
|
+
sa.Column("wg_address", sa.Text(), nullable=True),
|
|
26
|
+
sa.Column("wg_listen_port", sa.Integer(), nullable=True),
|
|
27
|
+
sa.Column("wg_peer_public_key", sa.Text(), nullable=True),
|
|
28
|
+
sa.Column("wg_peer_host", sa.Text(), nullable=True),
|
|
29
|
+
sa.Column("wg_peer_port", sa.Integer(), nullable=True, server_default="51820"),
|
|
30
|
+
sa.Column("wg_persistent_keepalive", sa.Integer(), nullable=True),
|
|
31
|
+
sa.Column("wg_mtu", sa.Integer(), nullable=True),
|
|
32
|
+
sa.Column("wg_dns", sa.Text(), nullable=True),
|
|
33
|
+
sa.Column("l2tp_gateway", sa.Text(), nullable=True),
|
|
34
|
+
sa.Column("l2tp_psk", sa.Text(), nullable=True),
|
|
35
|
+
sa.Column("l2tp_username", sa.Text(), nullable=True),
|
|
36
|
+
sa.Column("l2tp_password", sa.Text(), nullable=True),
|
|
37
|
+
sa.Column("oper_state", sa.String(16), nullable=False, server_default="unknown"),
|
|
38
|
+
sa.Column("iface", sa.String(32), nullable=True),
|
|
39
|
+
sa.Column("rx_bytes", sa.BigInteger(), nullable=True),
|
|
40
|
+
sa.Column("tx_bytes", sa.BigInteger(), nullable=True),
|
|
41
|
+
sa.Column("last_handshake_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
42
|
+
sa.Column("last_error", sa.Text(), nullable=True),
|
|
43
|
+
sa.Column("last_status_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
44
|
+
sa.Column(
|
|
45
|
+
"created_at",
|
|
46
|
+
sa.TIMESTAMP(timezone=True),
|
|
47
|
+
nullable=False,
|
|
48
|
+
server_default=sa.text("now()"),
|
|
49
|
+
),
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def downgrade() -> None:
|
|
54
|
+
op.drop_table("mr_vpn_tunnel")
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from alembic import op
|
|
5
|
+
|
|
6
|
+
revision = "b7d3f1e92a05"
|
|
7
|
+
down_revision = "a9f3e2b1c0d8"
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
op.execute("ALTER TABLE radpostauth ADD COLUMN IF NOT EXISTS calledstationid text")
|
|
14
|
+
op.execute("ALTER TABLE radpostauth ADD COLUMN IF NOT EXISTS callingstationid text")
|
|
15
|
+
op.execute('ALTER TABLE radpostauth ADD COLUMN IF NOT EXISTS "class" text')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def downgrade() -> None:
|
|
19
|
+
op.execute('ALTER TABLE radpostauth DROP COLUMN IF EXISTS "class"')
|
|
20
|
+
op.execute("ALTER TABLE radpostauth DROP COLUMN IF EXISTS callingstationid")
|
|
21
|
+
op.execute("ALTER TABLE radpostauth DROP COLUMN IF EXISTS calledstationid")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "b7f2c9a4e1d3"
|
|
9
|
+
down_revision = "e5c9a1f3d827"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
op.create_table(
|
|
16
|
+
"mr_nas_reachability",
|
|
17
|
+
sa.Column("id", sa.Integer(), primary_key=True, autoincrement=True),
|
|
18
|
+
sa.Column(
|
|
19
|
+
"nas_id",
|
|
20
|
+
sa.Integer(),
|
|
21
|
+
sa.ForeignKey("nas.id", ondelete="CASCADE"),
|
|
22
|
+
nullable=False,
|
|
23
|
+
),
|
|
24
|
+
sa.Column("status", sa.String(16), nullable=False, server_default="unknown"),
|
|
25
|
+
sa.Column("method", sa.String(8), nullable=False, server_default="icmp"),
|
|
26
|
+
sa.Column("last_rtt_ms", sa.Float(), nullable=True),
|
|
27
|
+
sa.Column("last_seen_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
28
|
+
sa.Column("last_probe_at", sa.TIMESTAMP(timezone=True), nullable=True),
|
|
29
|
+
sa.Column("detail", sa.Text(), nullable=True),
|
|
30
|
+
)
|
|
31
|
+
op.create_unique_constraint("uq_mr_nas_reachability_nas_id", "mr_nas_reachability", ["nas_id"])
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def downgrade() -> None:
|
|
35
|
+
op.drop_table("mr_nas_reachability")
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import sqlalchemy as sa
|
|
5
|
+
|
|
6
|
+
from alembic import op
|
|
7
|
+
|
|
8
|
+
revision = "b8e3f1a2d9c4"
|
|
9
|
+
down_revision = "a4d1c7e6b520"
|
|
10
|
+
branch_labels = None
|
|
11
|
+
depends_on = None
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def upgrade() -> None:
|
|
15
|
+
op.add_column(
|
|
16
|
+
"mr_firewall_set",
|
|
17
|
+
sa.Column("managed_source", sa.String(length=48), nullable=True),
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def downgrade() -> None:
|
|
22
|
+
op.drop_column("mr_firewall_set", "managed_source")
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from alembic import op
|
|
5
|
+
|
|
6
|
+
revision = "c1f7b4a9d2e6"
|
|
7
|
+
down_revision = "b8e3f1a2d9c4"
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
with op.get_context().autocommit_block():
|
|
14
|
+
op.create_index(
|
|
15
|
+
"ix_radacct_keyset",
|
|
16
|
+
"radacct",
|
|
17
|
+
["acctstarttime", "radacctid"],
|
|
18
|
+
postgresql_concurrently=True,
|
|
19
|
+
if_not_exists=True,
|
|
20
|
+
)
|
|
21
|
+
op.create_index(
|
|
22
|
+
"ix_radpostauth_keyset",
|
|
23
|
+
"radpostauth",
|
|
24
|
+
["authdate", "id"],
|
|
25
|
+
postgresql_concurrently=True,
|
|
26
|
+
if_not_exists=True,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def downgrade() -> None:
|
|
31
|
+
with op.get_context().autocommit_block():
|
|
32
|
+
op.drop_index(
|
|
33
|
+
"ix_radpostauth_keyset",
|
|
34
|
+
table_name="radpostauth",
|
|
35
|
+
postgresql_concurrently=True,
|
|
36
|
+
if_exists=True,
|
|
37
|
+
)
|
|
38
|
+
op.drop_index(
|
|
39
|
+
"ix_radacct_keyset", table_name="radacct", postgresql_concurrently=True, if_exists=True
|
|
40
|
+
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from alembic import op
|
|
5
|
+
|
|
6
|
+
revision = "c2a8f4e71b93"
|
|
7
|
+
down_revision = "b7d3f1e92a05"
|
|
8
|
+
branch_labels = None
|
|
9
|
+
depends_on = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def upgrade() -> None:
|
|
13
|
+
op.execute("""
|
|
14
|
+
CREATE UNIQUE INDEX IF NOT EXISTS radacct_acctuniqueid
|
|
15
|
+
ON radacct (acctuniqueid)
|
|
16
|
+
""")
|
|
17
|
+
op.execute("""
|
|
18
|
+
CREATE TABLE IF NOT EXISTS nasreload (
|
|
19
|
+
nasipaddress inet PRIMARY KEY,
|
|
20
|
+
reloadtime timestamp with time zone NOT NULL
|
|
21
|
+
)
|
|
22
|
+
""")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade() -> None:
|
|
26
|
+
op.execute("DROP TABLE IF EXISTS nasreload")
|
|
27
|
+
op.execute("DROP INDEX IF EXISTS radacct_acctuniqueid")
|