scripts/vidispine-no-nearlineid/requeue-missing-nearlineid.py (130 lines of code) (raw):

#!/usr/bin/env python3 from gnmvidispine.vs_search import * from gnmvidispine.vs_shape import VSShape from argparse import ArgumentParser import pika import logging import json import uuid import sys from os.path import join from urllib.parse import urlparse logging.basicConfig(level=logging.ERROR) logger = logging.getLogger(__name__) logger.level = logging.DEBUG def send_message(conn, vsid:str): msg = json.dumps({ "field": [ { "key": "itemId", "value": vsid } ] }) msg_id = uuid.uuid4() props = pika.BasicProperties(content_type="application/json",content_encoding="utf8",message_id=msg_id.hex) conn.basic_publish("vidispine-events", "vidispine.itemneedsbackup", msg, props) def load_vs_credentials(basepath:str) -> (str, str): """ loads in vidispine credentials from a mounted secret :param basepath: base path where the credentials are mounted :return: a tuple of (username, password). Raises an exception on error """ logger.info("Reading vidispine credentials from {0}".format(basepath)) try: with open(join(basepath, "vsuser")) as f: username = f.read() with open(join(basepath, "vspass")) as f: pwd = f.read() return username, pwd except FileNotFoundError: with open(join(basepath, "vidispine_admin_user")) as f: username = f.read() with open(join(basepath, "vidispine_admin_password")) as f: pwd = f.read() return username, pwd class RMQCredentials(object): def __init__(self, host:str, port:int, vhost:str, user:str, passwd:str): self.host = host self.port = port self.vhost = vhost self.user = user self.passwd = passwd def validate(self): if self.host=="": raise ValueError("RabbitMQ host is not set") if self.port==0: raise ValueError("RabbitMQ port is not set") if self.vhost=="": raise ValueError("RabbitMQ vhost is not set") if self.user=="": raise ValueError("RabbitMQ user is not set") if self.passwd=="": raise ValueError("RabbitMQ password is not set") @staticmethod def load_from_file(basepath:str) -> (str, str): """ loads in rabbitmq credentials from a mounted secret :param basepath: :return: """ logger.info("Reading RabbitMQ credentials from {0}".format(basepath)) with open(join(basepath, "rabbitmq_client_uri")) as f: urlcontent = f.read() parsed = urlparse(urlcontent) return RMQCredentials( host=parsed.hostname, port=parsed.port if parsed.port is not None else 5672, vhost=parsed.path.lstrip("/") if parsed.path is not None and parsed.path != "/" else "default", user=parsed.username, passwd=parsed.password ) def vsshape_has_files(shape:VSShape) -> bool: """ Returns True if the given VSShape has any file URIs on it, or false otherwise. Note that this does NOT include any non-file:// style URIs. :param shape: VSShape :return: True if the shape has at least one non-file:// URI present. Existence of the file is NOT checked. """ for f in shape.fileURIs(): if f!="": return True return False ##START MAIN parser = ArgumentParser(description="Searches Vidispine for items that have no gnm_vidispine_id and requests updates for them") parser.add_argument("--vshost", default="localhost", help="Vidispine host") parser.add_argument("--vsport", default=8080, help="Port number for vidispine") parser.add_argument("--vscreds", default=None, help="Path to retrieve Vidispine credentials") parser.add_argument("--https", default=False, action="store_true", help="use https communication") parser.add_argument("--rmq", default="localhost", help="RabbitMQ host") parser.add_argument("--rmqcreds", default=None, help="Path to retrieve RabbitMQ credentials. Expects text files called `rabbitmq_user` and `rabbitmq_passwd`") parser.add_argument("--rmquser", default="admin", help="RabbitMQ user, as an alternative to using rmq-credentials") parser.add_argument("--rmqpasswd", default="admin", help="RabbitMQ password, as an alternative to using rmq-credentials") parser.add_argument("--vhost", default="pluto-ng", help="RabbitMQ VHhost") parser.add_argument("--limit", default=None, help="Only process up to this many items") parser.add_argument("--count", default=False, action="store_true", help="Don't add anything to a queue, just count the number of items") args = parser.parse_args() if not args.rmquser or not args.rmqpasswd: parser.print_usage() sys.exit(1) logger.info("Connecting to rabbitmq...") if args.rmqcreds: logger.info("Loading credentials from file...") rmqcreds = RMQCredentials.load_from_file(args.rmqcreds) else: logger.info("Using commandline credentials") rmqcreds = RMQCredentials(host=args.rmq, port=5672, vhost=args.vhost, user=args.rmquser, passwd=args.rmqpasswd) credentials = pika.PlainCredentials(rmqcreds.user, rmqcreds.passwd) rmq_conn = pika.BlockingConnection( pika.ConnectionParameters(host=rmqcreds.host, port=rmqcreds.port, virtual_host=rmqcreds.vhost, credentials=credentials) ) rmq_chan = rmq_conn.channel() logger.info("Done.") vscreds = load_vs_credentials(args.vscreds) search = VSSearch(host=args.vshost, port=args.vsport, https=args.https, user=vscreds[0], passwd=vscreds[1]) search.addCriterion({"gnm_nearline_id": ""}) action = search.execute() logger.info("Found {0} items without gnm_nearline_id".format(action.totalItems)) if args.count: sys.exit(0) ctr = 0 for item in action.results(shouldPopulate=False): try: orig = item.get_shape("original") if not vsshape_has_files(orig): logger.info("Original shape exists on {0} but without a file URI".format(item.name)) continue ctr += 1 logger.info("Sending event {0}/{1} for {2}....".format(ctr, action.totalItems, item.name)) send_message(rmq_chan, item.name) if args.limit is not None and ctr>=int(args.limit): logger.info("Hit limit of {0} items, completing".format(args.limit)) break except VSNotFound: logger.info("No original shape on {0}, skipping it".format(item.name)) logger.info("All done.")