feat(cloud): add edge host enrollment

This commit is contained in:
2026-07-13 13:54:16 +08:00
parent cd56facbbf
commit e61dcca801
40 changed files with 2302 additions and 48 deletions
@@ -0,0 +1,96 @@
"""Add durable Host and device enrollment identity."""
from __future__ import annotations
from alembic import op
import sqlalchemy as sa
revision = "0002_edge_host_enrollment"
down_revision = "0001_cloud_repository"
branch_labels = None
depends_on = None
HOST_ENROLLMENT_COLUMNS = (
sa.Column("agent_instance_id", sa.String(), nullable=True),
sa.Column("credential_digest", sa.String(), nullable=True),
sa.Column("enrollment_token_digest", sa.String(), nullable=True),
sa.Column("display_name", sa.String(), nullable=True),
sa.Column("enrolled_at", sa.String(), nullable=True),
sa.Column("revoked_at", sa.String(), nullable=True),
)
def upgrade() -> None:
inspector = sa.inspect(op.get_bind())
existing_columns = {
column["name"] for column in inspector.get_columns("host_registrations")
}
with op.batch_alter_table("host_registrations") as batch:
for column in HOST_ENROLLMENT_COLUMNS:
if column.name not in existing_columns:
batch.add_column(column)
inspector = sa.inspect(op.get_bind())
indexes = {index["name"] for index in inspector.get_indexes("host_registrations")}
with op.batch_alter_table("host_registrations") as batch:
for name, column in (
("uq_host_registrations_agent_instance_id", "agent_instance_id"),
("uq_host_registrations_credential_digest", "credential_digest"),
(
"uq_host_registrations_enrollment_token_digest",
"enrollment_token_digest",
),
):
if name not in indexes:
batch.create_unique_constraint(name, [column])
inspector = sa.inspect(op.get_bind())
if "device_enrollments" not in inspector.get_table_names():
op.create_table(
"device_enrollments",
sa.Column("device_id", sa.String(), primary_key=True),
sa.Column("host_id", sa.String(), nullable=False),
sa.Column("local_device_id", sa.String(), nullable=False),
sa.Column("driver_type", sa.String(), nullable=False),
sa.Column("name", sa.String(), nullable=True),
sa.Column("capability_tags_json", sa.Text(), nullable=False),
sa.Column("enrolled_at", sa.String(), nullable=False),
sa.Column("revoked_at", sa.String(), nullable=True),
sa.UniqueConstraint(
"host_id",
"local_device_id",
name="uq_device_enrollments_host_local",
),
)
op.create_index(
"ix_device_enrollments_host_id",
"device_enrollments",
["host_id"],
)
def downgrade() -> None:
inspector = sa.inspect(op.get_bind())
if "device_enrollments" in inspector.get_table_names():
op.drop_index(
"ix_device_enrollments_host_id",
table_name="device_enrollments",
)
op.drop_table("device_enrollments")
inspector = sa.inspect(op.get_bind())
existing_columns = {
column["name"] for column in inspector.get_columns("host_registrations")
}
with op.batch_alter_table("host_registrations") as batch:
for name in (
"uq_host_registrations_enrollment_token_digest",
"uq_host_registrations_credential_digest",
"uq_host_registrations_agent_instance_id",
):
batch.drop_constraint(name, type_="unique")
for column in reversed(HOST_ENROLLMENT_COLUMNS):
if column.name in existing_columns:
batch.drop_column(column.name)