Пример #1
0
def cleanup_orphaned_matchqueues():
    """
    Find matches who have been reserved by the match queue but not joined
    for 10 minutes and make them available to other players
    """
    logger = get_task_logger("cleanup_orphaned_matchqueues")

    tier_name = get_tier_name()
    tenants = driftbase.tasks.get_tenants()
    logger.info("Cleaning up match queues for %s tenants...", len(tenants))
    for tenant_config in tenants:
        tenant_name = tenant_config["name"]
        if tenant_config.get("name", "*") == "*":
            continue
        try:
            this_conn_string = get_connection_string(tenant_config,
                                                     None,
                                                     tier_name=tier_name)

        except TenantNotFoundError:
            continue

        with sqlalchemy_session(this_conn_string) as session:
            sql = """
            SELECT m.* FROM gs_matches m
                INNER JOIN gs_servers s ON s.server_id = m.server_id
            WHERE m.status = 'queue' AND
                  m.status_date::timestamp < now()::timestamp - interval '5 minutes' AND
                  s.heartbeat_date::timestamp >= now()::timestamp - interval '2 minutes'
             ORDER BY m.match_id DESC
            """
            result = session.execute(sql)
            orphaned_matches = set()
            match = result.fetchone()
            while match:
                orphaned_matches.add(match.match_id)
                match = result.fetchone()
            if orphaned_matches:
                log.info("Tenant '%s' has %s orphaned matches", tenant_name,
                         len(orphaned_matches))
            for match_id in orphaned_matches:
                match = session.query(Match).get(match_id)
                match.status = "idle"
                match.status_date = utcnow()
                matchqueueplayers = session.query(MatchQueuePlayer) \
                                           .filter(MatchQueuePlayer.match_id == match_id)
                for p in matchqueueplayers:
                    session.delete(p)
                logger.info(
                    "Cleaning up orphaned match '%s' in tenant '%s' and putting it "
                    "back into the pool", match_id, tenant_name)
            session.commit()

            # if we cleaned up any matches we should process the match queue in
            # case there are any players waiting
            if orphaned_matches:
                logger.info("Processing match queue")
                redis = RedisCache(tenant=tenant_config["name"],
                                   redis_server=tenant_config['redis_server'])
                process_match_queue(redis, session)
Пример #2
0
def get_mock_tenants():
    t = {"name": os.environ.get("drift_test_database"),
         "db_server": "localhost",
         "redis_server": "localhost",
         "heartbeat_timeout": 0,
         }
    conn_string = get_connection_string(t, None, tier_name=get_tier_name())
    t["conn_string"] = conn_string
    return [t]
Пример #3
0
def db_check(tenant_config):
    from drift.tenant import get_connection_string

    try:
        conn_string = get_connection_string(tenant_config)
        engine = create_engine(conn_string, echo=False)
        engine.execute("SELECT 1=1")
    except Exception as e:
        return repr(e)
    return None
Пример #4
0
def tenant_report(tenant_config):
    from drift.tenant import get_connection_string

    conn_string = get_connection_string(tenant_config)
    print "Tenant configuration for '{}' on tier '{}':" \
          .format(tenant_config["name"], get_tier_name())
    for k in sorted(tenant_config.keys()):
        print "  {} = {}".format(k, tenant_config[k])
    print "Connection string:\n  {}".format(conn_string)
    print "Database check... "
    db_error = db_check(tenant_config)
    if db_error:
        if "does not exist" in db_error:
            print Fore.RED + "  FAIL! DB does not exist"
            print "  You can create this database by running this " \
                  "command again with the action 'create'"
        else:
            print Fore.RED + "  {}".format(db_error)
    else:
        print Fore.GREEN + "  OK! Database is online and reachable"
Пример #5
0
def update_online_statistics():
    """

    """
    logger = get_task_logger("update_statistics")

    tier_name = get_tier_name()
    config = load_config()
    tenants = config.get("tenants", [])
    logger.info("Updating statistics for %s tenants...", len(tenants))
    num_updated = 0
    for tenant_config in tenants:
        if tenant_config.get("name", "*") == "*":
            continue
        try:
            this_conn_string = get_connection_string(tenant_config, None, tier_name=tier_name)

        except TenantNotFoundError:
            continue

        with sqlalchemy_session(this_conn_string) as session:
            result = session.execute("""SELECT COUNT(DISTINCT(player_id)) AS cnt
                                          FROM ck_clients
                                         WHERE heartbeat > NOW() - INTERVAL '1 minutes'""")
            cnt = result.fetchone()[0]
            if cnt:
                num_updated += 1
                tenant_name = tenant_config["name"]
                name = 'backend.numonline'
                row = session.query(Counter).filter(Counter.name == name).first()
                if not row:
                    row = Counter(name=name, counter_type="absolute")
                    session.add(row)
                    session.commit()
                counter_id = row.counter_id
                timestamp = datetime.datetime.utcnow()
                add_count(counter_id, 0, timestamp, cnt, is_absolute=True, db_session=session)
                session.commit()
                print "Updated num_online for %s to %s" % (tenant_name, cnt)

    logger.info("Updated %s tenants with online user count", num_updated)
Пример #6
0
def get_tenants():
    tier_name = get_tier_name()
    config = load_config()
    _tenants = config.get("tenants", [])
    tenants = []
    for t in _tenants:
        t["heartbeat_timeout"] = config.get("heartbeat_timeout",
                                            DEFAULT_HEARTBEAT_TIMEOUT)
        if t.get("name", "*") == "*":
            continue
        try:
            this_conn_string = get_connection_string(t,
                                                     None,
                                                     tier_name=tier_name)
        except TenantNotFoundError:
            continue
        t["conn_string"] = this_conn_string
        if config.get("redis_server", None):
            t["redis_server"] = config.get("redis_server")
        tenants.append(t)
    return tenants
Пример #7
0
def get_engines():
    if conn_string:
        engines = {
            "dude": {
                "engine":
                create_engine(conn_string, echo=False,
                              poolclass=pool.NullPool),
                "url":
                conn_string
            }
        }
        return engines
    engines = {}
    from drift.tenant import get_connection_string
    config = load_config()
    tenants = []
    pick_tenant = None
    if sys.argv[1] == '-x':
        pick_tenant = sys.argv[2]
        print 'picking tenant %s' % pick_tenant
    for tier in config["tiers"]:
        tier_name = tier["name"]
        config = load_config(tier_name)
        tenant_names = []
        for t in config.get("tenants", []):
            if not t.get("db_server"):
                continue
            name = t["name"]
            t["tier_name"] = tier_name
            if not (pick_tenant and name != pick_tenant) and name != "*":
                tenants.append(t)
                tenant_names.append(name)
        logger.info("Gathering tenants for tier %s: %s", tier_name,
                    (", ".join(tenant_names) or "(none)"))

    db_servers = set([])
    for tenant_config in tenants:
        from drift.flaskfactory import TenantNotFoundError
        try:
            conn_info = {"user": "******", "password": "******"}
            this_conn_string = get_connection_string(
                tenant_config, conn_info, tier_name=tenant_config["tier_name"])
        except TenantNotFoundError:
            logger.info("Tenant '{}' on tier '{}' not found".format(
                tenant_config["name"], tenant_config["tier_name"]))
            continue
        if this_conn_string not in [e["url"] for e in engines.itervalues()]:
            engines["{}.{}".format(tenant_config["tier_name"],
                                   tenant_config["name"])] = rec = {
                                       "url": this_conn_string
                                   }

    # quick and dirty connectivity test before trying to upgrade all db's
    print "Checking connectivity..."
    db_servers = set()
    for key, engine in engines.iteritems():
        server = engine["url"].split("/")
        db_servers.add(server[2].split("@")[1].lower())
    err = False
    for db_server in db_servers:
        port = 5432
        sys.stdout.write(db_server + "... ")
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2)
        result = sock.connect_ex((db_server, port))
        if result != 0:
            print "Unable to connect to server '%s' on port %s" % (db_server,
                                                                   port)
            err = True
        else:
            print "OK"
    if err:
        raise Exception(
            "Unable to connect to one or more db servers. Bailing out!")

    for key in engines.keys():
        rec = engines[key]
        connection_string = rec["url"]
        logger.info("Connecting '{}'...".format(connection_string))
        rec['engine'] = create_engine(connection_string,
                                      echo=False,
                                      poolclass=pool.NullPool)
        rec['url'] = connection_string
    return engines
Пример #8
0
def run_command(args):
    print
    from drift import tenant
    tenant_name = args.tenant
    if not tenant_name:
        tenants_report()
        return
    tier_name = get_tier_name()
    config = load_config()
    tenant_config = {}
    for tenant_config in config.get("tenants", []):
        if tenant_config["name"].lower() == tenant_name.lower():
            # get the right casing from config
            tenant_name = tenant_config["name"]
            break
    else:
        print Fore.RED + "ERROR! Tenant '{}' is not registered in config for tier '{}'" \
                         .format(tenant_name, tier_name)
        print "Please add the tenant into config/config_{}.json and " \
              "then run this command again\n".format(tier_name)
        return

    if not args.action:
        tenant_report(tenant_config)
        return

    db_host = tenant_config["db_server"]
    if ":" not in db_host:
        db_host += ":{}".format(POSTGRES_PORT)

    # TODO validation
    db_name = None
    if "recreate" in args.action:
        actions = ["drop", "create"]
        print "Recreating db for tenant '{}'".format(tenant_name)
    else:
        actions = [args.action]

    if "drop" in actions:
        print "Dropping tenant {} on {}...".format(tenant_name, db_host)
        db_error = db_check(tenant_config)
        if db_error:
            print "ERROR: You cannot drop the db because it is not reachable: {}".format(
                db_error)
            return
        else:
            tenant.drop_db(tenant_name, db_host, tier_name)

    if "create" in args.action:
        print "Creating tenant '{}' on server '{}'...".format(
            tenant_name, db_host)
        db_notfound_error = db_check(tenant_config)
        if not db_notfound_error:
            print "ERROR: You cannot create the database because it already exists"
            print "Use the command 'recreate' if you want to drop and create the db"
            from drift.tenant import get_connection_string
            conn_string = get_connection_string(tenant_config)
            print "conn_string = " + conn_string
        else:
            tenant.create_db(tenant_name, db_host, tier_name)
            tenant_report(tenant_config)