def upsert_machine_location(dbsession: DbSession, machine_id: str, info: Union[Dict[str, Any], List[Any]]) -> None: """Update the relevant Machine record with information from a LocationLabel event. Although the info is guaranteed to be a `Dict[str, str]` when received from the client, the database column is of type JSONB, so the `LocationLabel.info` field has a more general type. As a result, the function parameter also has a more general type, and this runtime type check is needed to satisfy mypy. """ if isinstance(info, dict): location_columns = [ column.name for column in Machine.__table__.columns ] values = { f'location_{key}': value for key, value in info.items() if f'location_{key}' in location_columns } stmt = insert(Machine.__table__).values(machine_id=machine_id, location=info, **values) stmt = stmt.on_conflict_do_update( constraint='uq_metrics_machine_machine_id', set_=values) dbsession.connection().execute(stmt) else: # pragma: no cover log.warning('Data received for machine location is not a dict: %r', info)
def upsert_machine_dualboot(dbsession: DbSession, machine_id: str) -> None: stmt = insert(Machine.__table__).values(machine_id=machine_id, dualboot=True) stmt = stmt.on_conflict_do_update( constraint='uq_metrics_machine_machine_id', set_={'dualboot': True}) dbsession.connection().execute(stmt)
def upsert_machine_image(dbsession: DbSession, machine_id: str, image_id: str) -> None: image_values: Dict[str, Any] = { 'image_id': image_id, **parse_endless_os_image(image_id) } stmt = insert(Machine.__table__).values(machine_id=machine_id, **image_values) stmt = stmt.on_conflict_do_update( constraint='uq_metrics_machine_machine_id', set_=image_values) dbsession.connection().execute(stmt)
def id_from_serialized(cls, serialized: bytes, dbsession: DbSession) -> int: record = json.loads(serialized.decode('utf-8')) columns = inspect(cls).attrs record = {k: v for (k, v) in record.items() if k in columns} record['vendor'] = normalize_vendor(record.get('vendor', 'unknown')) # Let's make the case of a missing "image" fail at the SQL level if 'image' in record: # pragma: no branch record.update(**parse_endless_os_image(record['image'])) # Postgresql's 'INSERT … ON CONFLICT …' is not available at the ORM layer, so let's # drop down to the SQL layer stmt = insert(PingConfiguration.__table__).values(**record) stmt = stmt.returning(PingConfiguration.__table__.c.id) # We have to use 'ON CONFLICT … DO UPDATE …' because 'ON CONFLICT DO NOTHING' does not # return anything, and we need to get the id back; in addition we have to actually # update something, anything, so let's arbitrarily update the image to its existing value stmt = stmt.on_conflict_do_update( constraint='uq_ping_configuration_v1_image_vendor_product_dualboot', set_={'image': record['image']} ) result = dbsession.connection().execute(stmt) dbsession.commit() return result.first()[0]