Exemple #1
0
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)
Exemple #2
0
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)
Exemple #3
0
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)
Exemple #4
0
    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]