Esempio n. 1
0
def regenerate_sales_order_range(tenant_id, start, end):
    """For all sales orders in a given range, generate sales order dicts,
       and return them."""
    session = Session()
    db = database.Database(session)
    rates = RatesFile(config.rates_config)

    valid_tenant = validate_tenant_id(tenant_id, session)
    if isinstance(valid_tenant, tuple):
        return valid_tenant

    sales_orders = db.get_sales_orders(tenant_id, start, end)

    tenants = []
    for sales_order in sales_orders:
        usage = db.usage(sales_order.start, sales_order.end, tenant_id)

        # Transform the query result into a billable dict.
        tenant_dict = build_tenant_dict(valid_tenant, usage, db)
        tenant_dict = add_costs_for_tenant(tenant_dict, rates)

        # add sales order range:
        tenant_dict['start'] = str(sales_order.start)
        tenant_dict['end'] = str(sales_order.end)

        tenants.append(tenant_dict)

    return 200, tenants
Esempio n. 2
0
def regenerate_sales_order(tenant_id, target):
    """Finds a sales order entry nearest to the target,
       and returns a salesorder dict based on the entry."""
    session = Session()
    db = database.Database(session)
    rates = RatesFile(config.rates_config)

    valid_tenant = validate_tenant_id(tenant_id, session)
    if isinstance(valid_tenant, tuple):
        return valid_tenant

    try:
        sales_order = db.get_sales_orders(tenant_id, target, target)[0]
    except IndexError:
        return 400, {"errors": ["Given date not in existing sales orders."]}

    usage = db.usage(sales_order.start, sales_order.end, tenant_id)

    # Transform the query result into a billable dict.
    tenant_dict = build_tenant_dict(valid_tenant, usage, db)
    tenant_dict = add_costs_for_tenant(tenant_dict, rates)

    # add sales order range:
    tenant_dict['start'] = str(sales_order.start)
    tenant_dict['end'] = str(sales_order.end)

    return 200, tenant_dict
Esempio n. 3
0
def get_usage():
    """
    Get raw aggregated usage for a tenant, in a given timespan.
        - No rates are applied.
        - No conversion from collection unit to billing unit
        - No rounding
    """
    tenant_id = flask.request.args.get('tenant')
    start = flask.request.args.get('start')
    end = flask.request.args.get('end')

    LOG.info("get_usage for %s %s %s" % (tenant_id, start, end))

    try:
        start_dt = datetime.strptime(end, iso_time)
    except ValueError:
        return 400, {'error': 'Invalid start datetime'}

    try:
        end_dt = datetime.strptime(end, iso_time)
    except ValueError:
        return 400, {'error': 'Invalid end datetime'}

    if end_dt < start_dt:
        return 400, {'error': 'End must be after start'}

    session = Session()
    db = database.Database(session)

    valid_tenant = validate_tenant_id(tenant_id, session)
    if isinstance(valid_tenant, tuple):
        return valid_tenant

    LOG.info("parameter validation ok")

    if memcache is not None:
        key = make_key("raw_usage", tenant_id, start, end)

        data = memcache.get(key)
        if data is not None:
            LOG.info("Returning memcache raw data for %s in range: %s - %s" %
                     (tenant_id, start, end))
            return 200, data

    LOG.info("Calculating raw data for %s in range: %s - %s" %
             (tenant_id, start, end))

    # aggregate usage
    usage = db.usage(start, end, tenant_id)
    tenant_dict = build_tenant_dict(valid_tenant, usage, db)

    response_json = json.dumps({'usage': make_serializable(tenant_dict)})

    if memcache is not None:
        memcache.set(key, response_json)

    return 200, response_json
Esempio n. 4
0
    def test_get_from_db(self):
        """Test to ensure the data in the database matches the data entered."""
        num_resources = 32
        num_tenants = 5

        utils.init_db(self.session, num_tenants, num_resources, self.end)

        db = database.Database(self.session)

        for i in range(num_tenants):
            usage = db.usage(self.start, self.start + timedelta(days=60),
                             "tenant_id_" + str(i))
            self.assertEqual(usage.count(), num_resources)
Esempio n. 5
0
def run_usage_collection():
    """Run usage collection on all tenants present in Keystone."""
    try:
        log.info("Usage collection run started.")

        session = Session()

        interface = Interface()

        reset_cache()

        db = database.Database(session)

        end = datetime.utcnow().\
            replace(minute=0, second=0, microsecond=0)

        tenants = interface.tenants

        resp = {"tenants": [], "errors": 0}
        run_once = False

        for tenant in tenants:
            if collect_usage(tenant, db, session, resp, end):
                run_once = True

        if (run_once):
            session.begin()
            last_run = session.query(_Last_Run)
            if last_run.count() == 0:
                last_run = _Last_Run(last_run=end)
                session.add(last_run)
                session.commit()
            else:
                last_run[0].last_run = end
                session.commit()

        session.close()
        log.info("Usage collection run complete.")
        return json.dumps(resp)

    except Exception as e:
        import traceback
        trace = traceback.format_exc()
        log.critical('Exception escaped! %s \nTrace: \n%s' % (e, trace))
Esempio n. 6
0
def calculate_rated_data(tenant, start, end, session):
    """Calculate a rated data dict from the given range."""

    db = database.Database(session)

    global RATES
    if not RATES:
        RATES = RatesFile(config.rates_config)

    usage = db.usage(start, end, tenant.id)

    # Transform the query result into a billable dict.
    tenant_dict = build_tenant_dict(tenant, usage, db)
    tenant_dict = add_costs_for_tenant(tenant_dict, RATES)

    # add sales order range:
    tenant_dict['start'] = str(start)
    tenant_dict['end'] = str(end)

    return tenant_dict
Esempio n. 7
0
def get_usage():
    """
    Get raw aggregated usage for a tenant, in a given timespan.
        - No rates are applied.
        - No conversion from collection unit to billing unit
        - No rounding
    """
    tenant_id = flask.request.args.get('tenant')
    start = flask.request.args.get('start')
    end = flask.request.args.get('end')

    log.info("get_usage for %s %s %s" % (tenant_id, start, end))

    try:
        start_dt = datetime.strptime(end, iso_time)
    except ValueError:
        return 400, {'error': 'Invalid start datetime'}

    try:
        end_dt = datetime.strptime(end, iso_time)
    except ValueError:
        return 400, {'error': 'Invalid end datetime'}

    if end_dt < start_dt:
        return 400, {'error': 'End must be after start'}

    session = Session()
    db = database.Database(session)

    valid_tenant = validate_tenant_id(tenant_id, session)
    if isinstance(valid_tenant, tuple):
        return valid_tenant

    log.info("parameter validation ok")

    # aggregate usage
    usage = db.usage(start, end, tenant_id)
    tenant_dict = build_tenant_dict(valid_tenant, usage, db)

    return 200, {'usage': make_serializable(tenant_dict)}
Esempio n. 8
0
def generate_sales_order(draft, tenant_id, end):
    """Generates a sales order dict, and unless draft is true,
       creates a database entry for sales_order."""
    session = Session()
    db = database.Database(session)

    valid_tenant = validate_tenant_id(tenant_id, session)
    if isinstance(valid_tenant, tuple):
        return valid_tenant

    rates = RatesFile(config.rates_config)

    # Get the last sales order for this tenant, to establish
    # the proper ranging
    start = session.query(func.max(SalesOrder.end).label('end')).\
        filter(SalesOrder.tenant_id == tenant_id).first().end
    if not start:
        start = dawn_of_time

    # these coditionals need work, also some way to
    # ensure all given timedate values are in UTC?
    if end <= start:
        return 400, {
            "errors": [
                "end date must be greater than " +
                "the end of the last sales order range."
            ]
        }
    if end > datetime.utcnow():
        return 400, {"errors": ["end date cannot be a future date."]}

    usage = db.usage(start, end, tenant_id)

    session.begin()
    if not draft:
        order = SalesOrder(tenant_id=tenant_id, start=start, end=end)
        session.add(order)

    try:
        # Commit the record before we generate the bill, to mark this as a
        # billed region of data. Avoids race conditions by marking a tenant
        # BEFORE we start to generate the data for it.
        session.commit()

        # Transform the query result into a billable dict.
        tenant_dict = build_tenant_dict(valid_tenant, usage, db)
        tenant_dict = add_costs_for_tenant(tenant_dict, rates)

        # add sales order range:
        tenant_dict['start'] = str(start)
        tenant_dict['end'] = str(end)
        session.close()
        if not draft:
            log.info("Sales Order #%s Generated for %s in range: %s - %s" %
                     (order.id, tenant_id, start, end))
        return 200, tenant_dict
    except (IntegrityError, OperationalError):
        session.rollback()
        session.close()
        log.warning("IntegrityError creating sales-order for " +
                    "%s %s in range: %s - %s " %
                    (valid_tenant.name, valid_tenant.id, start, end))
        return 400, {
            "id": tenant_id,
            "error": "IntegrityError, existing sales_order overlap."
        }