Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions goosebit/api/v1/devices/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ async def devices_patch(_: Request, config: DevicesPatchRequest) -> StatusRespon
if await Device.get_or_none(id=dev_id) is None:
raise HTTPException(404, f"Device with ID {dev_id} not found")
device = await DeviceManager.get_device(dev_id)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.software is not None:
if config.software == "rollout":
await DeviceManager.update_update(device, UpdateModeEnum.ROLLOUT, None)
Expand All @@ -71,8 +73,6 @@ async def devices_patch(_: Request, config: DevicesPatchRequest) -> StatusRespon
await DeviceManager.update_update(device, UpdateModeEnum.PINNED, None)
if config.name is not None:
await DeviceManager.update_name(device, config.name)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.force_update is not None:
await DeviceManager.update_force_update(device, config.force_update)
if config.auth_token is not None:
Expand All @@ -87,6 +87,8 @@ async def devices_patch(_: Request, config: DevicesPatchRequest) -> StatusRespon
async def devices_put(_: Request, config: DevicesPutRequest) -> StatusResponse:
for dev_id in config.devices:
device = await DeviceManager.get_device(dev_id)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.software is not None:
if config.software == "rollout":
await DeviceManager.update_update(device, UpdateModeEnum.ROLLOUT, None)
Expand All @@ -99,8 +101,6 @@ async def devices_put(_: Request, config: DevicesPutRequest) -> StatusResponse:
await DeviceManager.update_update(device, UpdateModeEnum.PINNED, None)
if config.name is not None:
await DeviceManager.update_name(device, config.name)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.force_update is not None:
await DeviceManager.update_force_update(device, config.force_update)
if config.auth_token is not None:
Expand Down
83 changes: 83 additions & 0 deletions goosebit/db/migrations/models/5_20250619090242_null_feed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
from tortoise import BaseDBAsyncClient


async def upgrade(db: BaseDBAsyncClient) -> str:
dialect = db.schema_generator.DIALECT

if dialect == "postgres":
return """
ALTER TABLE "device" ALTER COLUMN "feed" DROP NOT NULL;"""

return """PRAGMA foreign_keys=off;

CREATE TABLE "device_new" (
"id" CHAR(255) NOT NULL PRIMARY KEY,
"name" CHAR(255),
"assigned_software_id" INT,
"force_update" INT NOT NULL DEFAULT 0,
"sw_version" CHAR(255),
"hardware_id" INT NOT NULL,
"feed" CHAR(255) DEFAULT 'default', -- NULL allowed here
"update_mode" INT NOT NULL DEFAULT 0,
"last_state" INT NOT NULL DEFAULT 0,
"progress" INT,
"last_log" TEXT,
"last_seen" BIGINT,
"last_ip" CHAR(15),
"last_ipv6" CHAR(40),
"auth_token" CHAR(32)
);

INSERT INTO "device_new" SELECT
id, name, assigned_software_id, force_update, sw_version,
hardware_id, feed, update_mode, last_state, progress,
last_log, last_seen, last_ip, last_ipv6, auth_token
FROM "device";

DROP TABLE "device";

ALTER TABLE "device_new" RENAME TO "device";

PRAGMA foreign_keys=on;
"""


async def downgrade(db: BaseDBAsyncClient) -> str:
dialect = db.schema_generator.DIALECT

if dialect == "postgres":
return """
ALTER TABLE "device" ALTER COLUMN "feed" SET NOT NULL;"""

return """PRAGMA foreign_keys=off;

CREATE TABLE "device_old" (
"id" CHAR(255) NOT NULL PRIMARY KEY,
"name" CHAR(255),
"assigned_software_id" INT,
"force_update" INT NOT NULL DEFAULT 0,
"sw_version" CHAR(255),
"hardware_id" INT NOT NULL,
"feed" CHAR(255) NOT NULL DEFAULT 'default', -- NOT NULL again
"update_mode" INT NOT NULL DEFAULT 0,
"last_state" INT NOT NULL DEFAULT 0,
"progress" INT,
"last_log" TEXT,
"last_seen" BIGINT,
"last_ip" CHAR(15),
"last_ipv6" CHAR(40),
"auth_token" CHAR(32)
);

INSERT INTO "device_old" SELECT
id, name, assigned_software_id, force_update, sw_version,
hardware_id, feed, update_mode, last_state, progress,
last_log, last_seen, last_ip, last_ipv6, auth_token
FROM "device";

DROP TABLE "device";

ALTER TABLE "device_old" RENAME TO "device";

PRAGMA foreign_keys=on;
"""
6 changes: 5 additions & 1 deletion goosebit/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Device(Model):
force_update = fields.BooleanField(default=False)
sw_version = fields.CharField(max_length=255, null=True)
hardware = fields.ForeignKeyField("models.Hardware", related_name="devices")
feed = fields.CharField(max_length=255, default="default")
feed = fields.CharField(max_length=255, default="default", null=True)
update_mode = fields.IntEnumField(UpdateModeEnum, default=UpdateModeEnum.ROLLOUT)
last_state = fields.IntEnumField(UpdateStateEnum, default=UpdateStateEnum.UNKNOWN)
progress = fields.IntField(null=True)
Expand All @@ -76,6 +76,10 @@ class Device(Model):
tags = fields.ManyToManyField("models.Tag", related_name="devices", through="device_tags")

async def save(self, *args, **kwargs):
# ensure if using rollout that feed is set
if self.update_mode == UpdateModeEnum.ROLLOUT:
if self.feed is None:
raise ValidationError("Feed must be set in order to use rollout.")
# Check if the software is compatible with the hardware before saving
if self.assigned_software and self.hardware:
# Check if the assigned software is compatible with the hardware
Expand Down
4 changes: 3 additions & 1 deletion goosebit/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ async def update_last_connection(device: Device, last_seen: int, last_ip: str |
async def update_update(device: Device, update_mode: UpdateModeEnum, software: Software | None):
device.assigned_software = software
device.update_mode = update_mode
await DeviceManager.save_device(device, update_fields=["assigned_software_id", "update_mode"])
if not update_mode == UpdateModeEnum.ROLLOUT:
device.feed = None
await DeviceManager.save_device(device, update_fields=["assigned_software_id", "update_mode", "feed"])

@staticmethod
async def update_name(device: Device, name: str):
Expand Down
2 changes: 1 addition & 1 deletion goosebit/schema/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class DeviceSchema(BaseModel):
assigned_software: SoftwareSchema | None = Field(exclude=True)
hardware: HardwareSchema | None = Field(exclude=True)

feed: str
feed: str | None
progress: int | None
last_state: Annotated[UpdateStateSchema, BeforeValidator(UpdateStateSchema.convert)] # type: ignore[valid-type]
update_mode: Annotated[UpdateModeSchema, BeforeValidator(UpdateModeSchema.convert)] # type: ignore[valid-type]
Expand Down
4 changes: 2 additions & 2 deletions goosebit/ui/bff/devices/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ async def devices_patch(_: Request, config: DevicesPatchRequest) -> StatusRespon
if await Device.get_or_none(id=dev_id) is None:
raise HTTPException(404, f"Device with ID {dev_id} not found")
device = await get_device(dev_id)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.software is not None:
if config.software == "rollout":
await DeviceManager.update_update(device, UpdateModeEnum.ROLLOUT, None)
Expand All @@ -80,8 +82,6 @@ async def devices_patch(_: Request, config: DevicesPatchRequest) -> StatusRespon
await DeviceManager.update_update(device, UpdateModeEnum.PINNED, None)
if config.name is not None:
await DeviceManager.update_name(device, config.name)
if config.feed is not None:
await DeviceManager.update_feed(device, config.feed)
if config.force_update is not None:
await DeviceManager.update_force_update(device, config.force_update)
if config.auth_token is not None:
Expand Down
Loading