feat: Proxmox management suite — hardware, firewall, pools, disks, storage, access, node admin
- VM/LXC hardware editor with PCI/USB passthrough (BIOS/OVMF + efidisk, machine type, VGA, SCSI controller, CPU sockets); passthrough locked while running - Firewall at datacenter/node/VM levels: rules, security groups, IP sets, aliases, options, log — with rule dialog referencing security groups - Resource pools (CRUD + membership) and per-instance tags editor - Node disks: physical disk list, SMART viewer, ZFS pool create/destroy, wipe - Storage: add LVM/LVM-thin/ZFS/RBD/CephFS types + enable/disable toggle - PVE Access: API tokens (create with one-time secret, delete) and realms (LDAP/AD/OpenID) - Node admin: systemd services (start/stop/restart), APT updates & repositories - Shared: SelectTrigger defaults to full width (fixes narrow dropdowns) Also bundles related in-progress work: auth screen refresh, node shell console page, server-updates badge, and node:*/access:* RBAC permissions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ NEW_DEFAULT_ROLES = [
|
||||
"server:update": True,
|
||||
"server:delete": True,
|
||||
"server:manage": True,
|
||||
"cluster:manage": True,
|
||||
# VMs
|
||||
"vm:view": True,
|
||||
"vm:create": True,
|
||||
@@ -57,9 +58,26 @@ NEW_DEFAULT_ROLES = [
|
||||
# Storage
|
||||
"storage:view": True,
|
||||
"storage:manage": True,
|
||||
# Firewall
|
||||
"firewall:view": True,
|
||||
"firewall:manage": True,
|
||||
# Networking (interfaces + SDN)
|
||||
"network:view": True,
|
||||
"network:manage": True,
|
||||
# Node administration (services, APT, upgrade)
|
||||
"node:view": True,
|
||||
"node:manage": True,
|
||||
"node:upgrade": True,
|
||||
# Resource pools
|
||||
"pool:view": True,
|
||||
"pool:manage": True,
|
||||
# PVE access (realms & API tokens)
|
||||
"access:view": True,
|
||||
"access:manage": True,
|
||||
# Backups
|
||||
"backup:view": True,
|
||||
"backup:create": True,
|
||||
"backup:restore": True,
|
||||
"backup:delete": True,
|
||||
"backup:manage": True,
|
||||
# IPAM
|
||||
@@ -115,6 +133,10 @@ NEW_DEFAULT_ROLES = [
|
||||
"lxc:console": True,
|
||||
"template:view": True,
|
||||
"storage:view": True,
|
||||
"firewall:view": True,
|
||||
"network:view": True,
|
||||
"node:view": True,
|
||||
"pool:view": True,
|
||||
"backup:view": True,
|
||||
"backup:create": True,
|
||||
"ipam:view": True,
|
||||
@@ -146,6 +168,10 @@ NEW_DEFAULT_ROLES = [
|
||||
"lxc:console": True,
|
||||
"template:view": True,
|
||||
"storage:view": True,
|
||||
"firewall:view": True,
|
||||
"network:view": True,
|
||||
"node:view": True,
|
||||
"pool:view": True,
|
||||
"ipam:view": True,
|
||||
"setting:view": True,
|
||||
"notification:view": True,
|
||||
@@ -164,6 +190,10 @@ NEW_DEFAULT_ROLES = [
|
||||
"lxc:view": True,
|
||||
"template:view": True,
|
||||
"storage:view": True,
|
||||
"firewall:view": True,
|
||||
"network:view": True,
|
||||
"node:view": True,
|
||||
"pool:view": True,
|
||||
"ipam:view": True,
|
||||
}
|
||||
},
|
||||
@@ -446,3 +476,67 @@ def ensure_default_roles_new_format(conn) -> None:
|
||||
}
|
||||
)
|
||||
logger.info(f"Created role '{role_data['name']}' with new permission format")
|
||||
|
||||
|
||||
# Granular permissions introduced after RBAC v2. For existing deployments the
|
||||
# corresponding features used to be gated behind umbrella permissions
|
||||
# (server:view / server:manage / vm:view / user:manage). Backfill the new
|
||||
# granular keys for any role that already holds the umbrella permission so that
|
||||
# custom roles do not silently lose access after the split.
|
||||
GRANULAR_BACKFILL = [
|
||||
# (umbrella permission, [granular permissions implied by it])
|
||||
("server:view", ["firewall:view", "network:view", "node:view", "storage:view"]),
|
||||
("vm:view", ["pool:view", "firewall:view"]),
|
||||
("server:manage", [
|
||||
"firewall:view", "firewall:manage",
|
||||
"network:view", "network:manage",
|
||||
"node:view", "node:manage", "node:upgrade",
|
||||
"storage:view", "storage:manage",
|
||||
"pool:view", "pool:manage",
|
||||
]),
|
||||
("user:manage", ["access:view", "access:manage"]),
|
||||
]
|
||||
|
||||
|
||||
def backfill_granular_permissions(conn) -> int:
|
||||
"""
|
||||
Add granular permission keys to roles that already have the matching
|
||||
umbrella permission. Only adds missing keys — never overrides an explicit
|
||||
grant/deny — so it is idempotent and safe to run on every startup.
|
||||
|
||||
Returns the number of roles updated.
|
||||
"""
|
||||
import json
|
||||
|
||||
result = conn.execute(text("SELECT id, name, permissions FROM roles"))
|
||||
roles = result.fetchall()
|
||||
|
||||
updated = 0
|
||||
for role_id, role_name, permissions in roles:
|
||||
if isinstance(permissions, str):
|
||||
try:
|
||||
permissions = json.loads(permissions)
|
||||
except Exception:
|
||||
continue
|
||||
if not isinstance(permissions, dict) or not permissions:
|
||||
continue
|
||||
|
||||
additions = {}
|
||||
for umbrella, implied in GRANULAR_BACKFILL:
|
||||
if permissions.get(umbrella) is True:
|
||||
for perm in implied:
|
||||
if perm not in permissions:
|
||||
additions[perm] = True
|
||||
|
||||
if additions:
|
||||
merged = {**permissions, **additions}
|
||||
conn.execute(
|
||||
text("UPDATE roles SET permissions = :perms WHERE id = :id"),
|
||||
{"perms": json.dumps(merged), "id": role_id},
|
||||
)
|
||||
logger.info(
|
||||
f"Backfilled {len(additions)} granular permission(s) for role '{role_name}'"
|
||||
)
|
||||
updated += 1
|
||||
|
||||
return updated
|
||||
|
||||
@@ -638,7 +638,89 @@ def _create_permissions() -> PermissionRegistry:
|
||||
category="Notifications",
|
||||
requires=["notification:view"]
|
||||
))
|
||||
|
||||
|
||||
# Firewall permissions (datacenter / node / VM firewall)
|
||||
registry.register(Permission(
|
||||
resource="firewall", action="view",
|
||||
display_name="View Firewall",
|
||||
description="View firewall rules, groups and options",
|
||||
category="Firewall"
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="firewall", action="manage",
|
||||
display_name="Manage Firewall",
|
||||
description="Manage firewall rules, security groups, IP sets and options",
|
||||
category="Firewall",
|
||||
requires=["firewall:view"]
|
||||
))
|
||||
|
||||
# Networking permissions (node interfaces + SDN)
|
||||
registry.register(Permission(
|
||||
resource="network", action="view",
|
||||
display_name="View Networking",
|
||||
description="View node network interfaces and SDN configuration",
|
||||
category="Networking"
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="network", action="manage",
|
||||
display_name="Manage Networking",
|
||||
description="Manage node network interfaces, bridges and SDN (zones, vnets, subnets)",
|
||||
category="Networking",
|
||||
requires=["network:view"]
|
||||
))
|
||||
|
||||
# Node administration permissions (services, APT, upgrade)
|
||||
registry.register(Permission(
|
||||
resource="node", action="view",
|
||||
display_name="View Node Administration",
|
||||
description="View node services, APT updates and repositories",
|
||||
category="Node Administration"
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="node", action="manage",
|
||||
display_name="Manage Node Administration",
|
||||
description="Control systemd services and manage APT repositories/refresh",
|
||||
category="Node Administration",
|
||||
requires=["node:view"]
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="node", action="upgrade",
|
||||
display_name="Upgrade Node Packages",
|
||||
description="Run apt dist-upgrade via the node console (root shell)",
|
||||
category="Node Administration",
|
||||
requires=["node:view"]
|
||||
))
|
||||
|
||||
# Resource pool permissions
|
||||
registry.register(Permission(
|
||||
resource="pool", action="view",
|
||||
display_name="View Pools",
|
||||
description="View resource pools and their members",
|
||||
category="Resource Pools"
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="pool", action="manage",
|
||||
display_name="Manage Pools",
|
||||
description="Create/delete pools and manage pool membership",
|
||||
category="Resource Pools",
|
||||
requires=["pool:view"]
|
||||
))
|
||||
|
||||
# PVE access permissions (authentication realms & API tokens)
|
||||
registry.register(Permission(
|
||||
resource="access", action="view",
|
||||
display_name="View PVE Access",
|
||||
description="View Proxmox authentication realms and API tokens",
|
||||
category="PVE Access"
|
||||
))
|
||||
registry.register(Permission(
|
||||
resource="access", action="manage",
|
||||
display_name="Manage PVE Access",
|
||||
description="Manage Proxmox authentication realms and API tokens",
|
||||
category="PVE Access",
|
||||
requires=["access:view"]
|
||||
))
|
||||
|
||||
return registry
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user