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]
def process(dbsession: DbSession, record: bytes) -> None: log.debug('Processing metric v2 record: %s', record) request_builder = RequestBuilder.parse_bytes(record) request = request_builder.build_request() dbsession.add(request) for event_variant in request_builder.singulars: singular_event = new_singular_event(request, event_variant, dbsession) if singular_event is not None: log.debug('Inserting singular metric:\n%s', singular_event) for event_variant in request_builder.aggregates: aggregate_event = new_aggregate_event(request, event_variant, dbsession) log.debug('Inserting aggregate metric:\n%s', aggregate_event) for event_variant in request_builder.sequences: sequence_event = new_sequence_event(request, event_variant, dbsession) if sequence_event is not None: log.debug('Inserting sequence event:\n%s', sequence_event) try: dbsession.commit() except IntegrityError as e: # FIXME: This is fragile, can we do better? if "uq_metrics_request_v2_sha512" in str(e): log.debug('Request had already been processed in the past') return # FIXME: Given how the request is built, this shouldn't ever happen; if it does though, we # absolutely need an integration test raise # pragma: no cover