Example #1
0
    def test_report_unknown_service(self):
        prepay_entity_customer = {"customer_type": "entity", "detailed_info": {
            "name": "test prepay entity customer", "contract_number": "2015/4568",
            "contract_date": "2015-01-01", "organization_type": "OOO", "name": "Some Company",
            "full_organization_name": "OOO Some Company", "primary_state_registration_number": "159 8525 15552",
            "individual_tax_number": "52 59 5555555", "legal_address_country": "RU", "legal_address_city": "NN",
            "legal_address_address": "Ошарская, 13", "location_country": "RU", "location_city": "NN",
            "location_address": "Ошарская", "general_manager_name": "Васильев Е.В",
            "general_accountant_name": "Иванова В.Н", "contact_person_name": "Петров Василий"
        }}
        self.create_tariff("First Tariff", default=True)
        customer_info = self.create_customer("*****@*****.**", **prepay_entity_customer)
        customer_id = customer_info["customer_id"]

        customer = Customer.get_by_id(customer_id)
        tenant = Tenant.create(uuid.uuid4().hex, "test tenant")
        tenant_id = tenant.tenant_id
        customer.confirm_email()  # clear db session
        customer.os_tenant_id = tenant_id
        db.session.commit()

        start = datetime(2015, 4, 1)
        end = datetime(2015, 4, 1, 10) - timedelta(seconds=1)
        customer = Customer.get_by_id(customer_id)
        Customer.fake_usage(customer, start, end, "service_unknown", "unknown resource", 1)
        db.session.commit()

        report = self.get_customer_report(customer_id, start, end, "pdf", filename="unknown_service.pdf")
        self.assertTrue(report)

        report = self.get_customer_report(customer_id, start, end, "pdf", filename="unknown_service_detailed.pdf",
                                          report_type="detailed")
        self.assertTrue(report)
Example #2
0
def task_os_create_tenant_and_user(customer_id, email):
    # email is just for logs
    customer = Customer.get_by_id(customer_id)
    log.debug("task_os_create_tenant_and_user: {}", customer)
    if not customer:
        log.warning("Can't find customer {} {}. Possible customer was removed by system test", customer_id, email)
        return

    info = openstack.create_tenant_and_user(email, customer_id, customer.tariff.flavors(),
                                            password=customer.os_user_password, enabled=True)
    log.debug("Openstack info: {}", info)

    # Tests can delete customer already here, therefore no updates are required
    if not conf.test:
        db.session.commit()
        db.session.close()
    customer = Customer.get_by_id(customer_id)
    if customer:
        customer.update_os_credentials(info['tenant_id'], info['tenant_name'],
                                       info['user_id'], info["username"], info['password'])
        send_email_os_credentials(info['email'], info['name'], info['password'], info['tenant_id'],
                                  language=customer.locale_language())
        db.session.commit()
    else:
        final_delete_from_os(info['tenant_id'], info['user_id'])
Example #3
0
def update_quota(customer_id, user_id, quotas):
    from model import Customer, CustomerHistory

    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.warning("Customer id '{}' not found for quota update", customer_id)
        return

    customer = Customer.get_by_id(customer_id)
    openstack.change_tenant_quotas(customer.os_tenant_id, **quotas)
    CustomerHistory.quota_changed(customer, user_id, None)
Example #4
0
def update_quota(customer_id, user_id, quotas):
    from model import Customer, CustomerHistory

    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.warning("Customer id '{}' not found for quota update",
                        customer_id)
        return

    customer = Customer.get_by_id(customer_id)
    openstack.change_tenant_quotas(customer.os_tenant_id, **quotas)
    CustomerHistory.quota_changed(customer, user_id, None)
Example #5
0
    def test_collector_sequence(self):
        start_time = datetime.datetime(2015, 3, 20, 9, 12)
        end_time = datetime.datetime(2015, 3, 21)

        project = Tenant("boss", start_time)

        disk = Disk(project, "test_disk", start_time, 1234567890)
        hour_price = Decimal(self.image_size_price)*2

        t = start_time
        count = 0
        while t < end_time:
            disk.repeat_message(t, t + datetime.timedelta(hours=1))

            with mock.patch("os_interfaces.openstack_wrapper.openstack") as openstack:
                openstack.get_tenant_usage = project.usage
                project.prepare_messages()

                tenants_usage = self.collector.run_usage_collection(t + datetime.timedelta(hours=1, minutes=10))
                self.assertTrue(tenants_usage[project.project_id])
            t += datetime.timedelta(hours=1)
            count += 1

        account = Customer.get_by_id(project.customer_id).account_dict()["RUB"]
        hours = int((end_time - start_time).total_seconds() // 3600) + 1
        total_cost = hours * hour_price
        self.assertLess(abs(account["withdraw"] - total_cost), 0.0001)
Example #6
0
def clean_up_customer_service_usage(self, customer_id, end_date):
    from model import Customer
    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.warning("Customer id '{}' not found for cleaning up services usage", customer_id)
        return
    customer.clean_up_service_usage(end_date)
Example #7
0
File: simple.py Project: deti/boss
    def aggregate(self, report_id):
        logbook.info("Get customer usage aggregation for {}", report_id)
        customer = Customer.get_by_id(report_id.customer_id)
        if not customer:
            raise Exception("Customer %s not found" % report_id.customer_id)

        with timed("get_usage simple"):
            aggregated_usage = ServiceUsage.get_usage(customer, report_id.start, report_id.end)

        tariffs = {}
        services = set()
        for usage in aggregated_usage:
            service_id, tariff_id, cost, usage_volume = usage
            services.add(service_id)
            if not tariff_id:
                logbook.error("ServiceUsage {} is not completed. Tariff is not filled", usage)
                continue
            tariff = Tariff.get_by_id(tariff_id)
            tariff_report = tariffs.get(tariff_id)
            if tariff_report is None:
                tariff_report = self.tariff_report_type(tariff, customer)
                tariffs[tariff_id] = tariff_report

            tariff_report.add_usage(usage)

        total = Counter()
        for tariff_id, tariff in tariffs.items():
            total_tariff, currency = tariff.aggregate()
            total[currency] += total_tariff

        for t, value in total.items():
            total[t] = decimal_to_string(value)

        logbook.info("Aggregated {} for {}. Services: {}", total, customer, services)
        return self.prepare_result(list(tariffs.values()), total, customer, report_id.start, report_id.end)
Example #8
0
def get_used_quotas(customer_id):
    from model import Customer
    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.warning("Customer id '{}' not found for getting used quotas", customer_id)
        return
    customer.get_used_quotas()
Example #9
0
    def test_publish(self):
        Tariff.create_tariff(self.localized_name("tariff_for_balance"), "tariff!!!", "rub", None)
        customer_id = Customer.new_customer("*****@*****.**", "123qwe", self.admin_user.user_id).customer_id
        db.session.commit()
        customer = Customer.get_by_id(customer_id)
        news_id = self.admin_client.news.create(**self.test_news)['news_id']

        # check publish
        news = self.admin_client.news.publish(news_id, publish=True)
        self.assertTrue(news['published'])
        self.assertEqual(outbox[0].to, [customer.email])
        self.assertIn(self.test_news['subject'], outbox[0].subject)

        news_id = self.admin_client.news.create(subject='$test_subject', body='test_body')['news_id']
        self.admin_client.news.publish(news_id, publish=True)
        self.assertEqual(len(outbox), 1)

        # check unpublish
        news = self.admin_client.news.publish(news_id, publish=False)
        self.assertFalse(news['published'])
        self.assertEqual(len(outbox), 1)

        # check publish deleted news
        self.admin_client.news.delete(news_id)
        with self.expect_error(errors.RemovedNews):
            self.admin_client.news.publish(news_id, publish=True)
Example #10
0
    def make_action(cls, state, now=None):
        from model import Customer
        logbook.info("Try apply action: {}", state)

        now = now or utcnow().datetime

        machine = cls.machines[state.name]
        customer = Customer.get_by_id(state.customer_id)
        try:
            new_state_name = getattr(machine, state.action)(customer)
        except Exception as e:
            logbook.error("action {} failed: {}", state, e)
            state.remove()
            db.session.commit()
            raise

        state.step += 1
        if not new_state_name:
            if state.step >= len(machine.schedule):
                logbook.info("Actions {} are completed for {}", cls.name, customer)
                state.remove()
                db.session.commit()
                return

            new_state = machine.schedule[state.step]
        else:
            new_state = find_first(machine.schedule, lambda x: x[0] == new_state_name)
            if not new_state:
                state.remove()
                db.session.commit()
                raise Exception("Can't find new state %s for machine %s" % (new_state_name, cls.name))
        state.action = new_state[0]
        state.scheduled_at = now + timedelta(seconds=new_state[1])
        logbook.info("New action {} is scheduled", state)
Example #11
0
    def test_receipts_report(self):
        self.create_tariff("default_tariff", default=True)
        customer_info = self.create_customer_by_self("*****@*****.**")
        db.session.commit()
        customer_id = customer_info["customer_id"]
        self.admin_client.customer.update_balance(customer_id, "100", "test withdraw for test mode", "RUB")

        self.admin_client.customer.update(customer_id, detailed_info={"passport_series_number": "1234 567 890",
                                                                      "passport_issued_by": "UFMS Russia",
                                                                      "passport_issued_date": "2013-01-01"})
        customer_db = Customer.get_by_id(customer_id)
        customer_db.confirm_email()

        self.admin_client.customer.make_prod(customer_id)
        self.admin_client.customer.update_balance(customer_id, "100", "test withdraw for prod mode", "RUB")

        start = utcnow().datetime - timedelta(days=30)
        end = utcnow().datetime + timedelta(hours=1)

        report = self.get_report("receipts", start, end, "csv")
        self.assertTrue(report)
        self.assertGreater(report.count(b";"), 5)
        report = [row for row in report.split(b"\r\n") if row]
        self.assertEqual(len(report), 2)  # header + balance update after prod

        self.get_report("receipts", start, end, "tsv")
Example #12
0
    def payment_check(self, *args, **request_data):
        """Checks payment availability for customer
            Parameters must be sent as json object.

        :param Int TransactionId: Mandatory - System transaction number.
        :param Numeric Amount: Mandatory - Payment amount from widget. Dot as separator, two digits after dot.
        :param String Currency: Mandatory - Currency: RUB/USD/EUR/GBP from widget parameters.
        :param String InvoiceId: Not mandatory - Order number from widget parameters.
        :param String AccountId: Mandatory - Customer identifier from widget parameters.
        :param String SubscriptionId: Not mandatory - Subscription identifier from widget parameters (for recurrent payments).
        :param String Name: Not mandatory - Card holder name.
        :param String Email: Payer's e-mail
        :param DateTime: Mandatory - Payment creation date/time in UTC (yyyy-MM-dd HH:mm:ss).
        :param String IpAddress: Not mandatory - Payer IP-address
        :param String IpCountry: Not mandatory - Payer's country double-chars code (according to ISO3166-1)
        :param String IpCity: Not mandatory - Payer's city
        :param String IpRegion: Not mandatory - Payer's region.
        :param String IpDistrict: Not mandatory - Payer's district.
        :param String CardFirstSix: Mandatory - Credit card first 6 digits
        :param String CardLastFour: Mandatory - Credit card last 6 digits
        :param String CardType: Mandatory - Card payment system: Visa or MasterCard or Maestro
        :param String CardExpDate: Mandatory - Card expiration date MM/YY
        :param String Issuer: Not mandatory - Issuer bank name
        :param String IssuerBankCountry: Not mandatory - Issuer bank country double-char code (according to ISO3166-1)
        :param String Description: Not mandatory - Payment description from widget parameters.
        :param Json Data: Not mandatory - Any json-data from widget.
        :param Bit TestMode: Mandatory - Test mode flag (1 or 0)
        :param String Status: Mandatory - Payment status: Completed — for single-step, Authorized — for double-step.

        :return: Status code, looks like {'code': 0}
        """
        logbook.info("[payment_check] Request info:{}", request_data)
        short_payment_info = dict([(key, request_data.get(key)) for key in PaymentsApi.payment_info_fields])

        # Common validation
        validation_res, validation_info = self.validate_request(request_data, short_payment_info)
        if not validation_res:
            log_error("[payment_check] {} Payment info: {}", validation_info, short_payment_info)
            return {'code': self.ERROR_COMMON}

        # Currency validation
        currency = request_data['Currency']
        if not currency or currency not in conf.currency.active:
            log_error("[payment_check] Invalid or incompatible currency: {}. Payment info: {}",
                      currency, short_payment_info)
            return {'code': self.ERROR_COMMON}

        # Customer validation
        customer_id = request_data['AccountId']
        customer = Customer.get_by_id(customer_id, False)
        if not customer:
            log_error("[payment_check] Customer {} not found. Payment info: {}", customer_id, short_payment_info)
            return {'code': self.ERROR_COMMON}
        if customer.is_test_mode():
            # Payments in test mode is not allowed
            logbook.warning("[payment_check] Customer {} in test mode. Payment info {}", customer, short_payment_info)
            return {'code': self.ERROR_COMMON}

        return {'code': self.ERROR_OK}
Example #13
0
def get_used_quotas(customer_id):
    from model import Customer
    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.warning("Customer id '{}' not found for getting used quotas",
                        customer_id)
        return
    customer.get_used_quotas()
Example #14
0
def notify_managers_about_hdd(self, customer_id):
    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.error("Customer {} not found in notify manager", customer_id)
        return
    logbook.info("notify manager about hdd for removing for customer {}", customer)
    from model.account.customer_history import CustomerHistory
    block_event = CustomerHistory.get_last_block_event(customer)
    send_email_hdd_notification(get_customers_manager(customer),
                                block_event.date,
                                customer.email)
Example #15
0
    def test_usage_report(self):
        self.create_tariff("default_tariff", default=True)
        customer_info = self.create_customer_by_self("*****@*****.**")

        customer = Customer.get_by_id(customer_info["customer_id"])
        tenant = Tenant.create(uuid.uuid4().hex, "test tenant")

        customer.os_tenant_id = tenant.tenant_id
        db.session.commit()

        start = datetime(2015, 4, 1)
        end = datetime(2015, 4, 25)
        end_report = end + timedelta(hours=24)
        cost1 = Decimal(0)
        cost1 += Customer.fake_usage(customer, start, end, self.service_nano_id, uuid.uuid4().hex, 1)
        cost1 += Customer.fake_usage(customer, start + timedelta(days=5), end, self.service_micro_id, uuid.uuid4().hex, 1)
        cost1 += Customer.fake_usage(customer, start + timedelta(days=6), end, self.service_nano_id, uuid.uuid4().hex, 1)
        cost1 += Customer.fake_usage(customer, start, end, "storage.image", uuid.uuid4().hex, 60*conf.GIGA)

        customer2_info = self.create_customer("*****@*****.**")
        tenant2 = Tenant.create(uuid.uuid4().hex, "test tenant 2")
        customer2 = Customer.get_by_id(customer2_info["customer_id"])
        customer2.os_tenant_id = tenant2.tenant_id
        cost2 = Customer.fake_usage(customer2, start, end, self.service_nano_id, uuid.uuid4().hex, 1)
        db.session.commit()

        report = self.get_report("usage", start, end_report, "csv", locale="en_us")
        self.assertTrue(report)

        report = [row.decode("ascii") for row in report.split(b"\r\n") if row]

        parsed_report = csv.reader(report)
        cust_1 = [row for row in parsed_report if row[0] == '*****@*****.**']
        cust_1_cost = sum(Decimal(row[1]) for row in cust_1)
        parsed_report = csv.reader(report)
        cust_2 = [row for row in parsed_report if row[0] == '*****@*****.**']
        cust_2_cost = sum(Decimal(row[1]) for row in cust_2)
        self.assertEqual(len(cust_2), 1)
        self.assertEqual(len(cust_1), 1)
        self.assertEqual(cust_1_cost, cost1)
        self.assertEqual(cust_2_cost, cost2)
Example #16
0
def reset_user_password(customer_id):
    customer = Customer.get_by_id(customer_id)

    if not customer:
        log.warning("Can't find customer for reset user password {} {}. Possible customer was removed by system test",
                    customer_id)
        return

    password = openstack.reset_user_password(customer.os_user_id)
    customer.update_os_password(password)
    send_email_os_credentials(customer.email, customer.os_username, password, customer.os_tenant_id,
                              language=customer.locale_language())
Example #17
0
def notify_managers_about_new_service_in_tariff(self, customer_id, flavor_name):
    customer = Customer.get_by_id(customer_id)
    if not customer:
        logbook.error("Customer {} not found in notify manager", customer_id)
        return
    logbook.info("notify manager about adding new service to tariff {}", customer.tariff.name)
    from api.admin.user import UserApi
    service_edit_url = urljoin(request_base_url(), posixpath.join(UserApi.ADMIN_FRONTEND_PATH, "tariffs",
                                                                  str(customer.tariff.tariff_id), "services"))
    customer_url = urljoin(request_base_url(), posixpath.join(UserApi.ADMIN_FRONTEND_PATH, "index",
                                                              str(customer.customer_id), "info"))

    subject, body = MessageTemplate.get_rendered_message(MessageTemplate.NEW_SERVICE_IN_TARIFF,
                                                         language=preferred_language(),
                                                         account=customer.email,
                                                         flavor_name=flavor_name,
                                                         tariff=customer.tariff.name,
                                                         customer_url=customer_url,
                                                         service_edit_url=service_edit_url)

    logbook.info("Sending email notification to delete data of {}", customer.email)
    send_email.delay(get_customers_manager(customer), subject, body)
Example #18
0
File: metrics.py Project: deti/boss
def main():
    import docopt
    from model import Customer

    opt = docopt.docopt(__doc__)

    tenant_id = opt["--tenant"]
    customer_id = opt["--customer"]
    if customer_id:
        try:
            customer_id = int(customer_id)
            customer = Customer.get_by_id(customer_id)
        except ValueError:
            customer = Customer.get_by_email(customer_id)
        if not customer:
            logbook.warning("Customer {} not found", customer_id)
            return
        else:
            tenant_id = customer.tenant.tenant_id
    start = opt["--start"]
    end = opt["--end"]
    now = arrow.utcnow().date()

    start = arrow.get(start) if start else now - timedelta(minutes=15)
    end = arrow.get(end) if end else now

    metric = opt["--metric"]
    service = opt["--service"]
    if service:
        service_mapping = {data["service"]: name for name, data in conf.fitter.collection.meter_mappings.items()}
        if service not in service_mapping:
            logbook.warning("Service {} not found", service)
            return
        metric = service_mapping[service]

    samples = openstack.get_tenant_usage(tenant_id, metric, start, end, limit=int(opt["--limit"]))
    logbook.info("Found {} samples", len(samples))
    for s in samples:
        pprint(s._info)
Example #19
0
    def test_report_with_two_tariffs(self):
        prepay_entity_customer = {"customer_type": "entity", "detailed_info": {
            "name": "test prepay entity customer", "contract_number": "2015/4568",
            "contract_date": "2015-01-01", "organization_type": "OOO", "name": "Some Company",
            "full_organization_name": "OOO Some Company", "primary_state_registration_number": "159 8525 15552",
            "individual_tax_number": "52 59 5555555", "legal_address_country": "RU", "legal_address_city": "NN",
            "legal_address_address": "Ошарская, 13", "location_country": "RU", "location_city": "NN",
            "location_address": "Ошарская", "general_manager_name": "Васильев Е.В",
            "general_accountant_name": "Иванова В.Н", "contact_person_name": "Петров Василий"
        }}
        self.create_tariff("First Tariff", default=True)
        customer_info = self.create_customer("*****@*****.**", **prepay_entity_customer)
        customer_id = customer_info["customer_id"]

        customer = Customer.get_by_id(customer_id)
        tenant = Tenant.create(uuid.uuid4().hex, "test tenant")
        tenant_id = tenant.tenant_id

        customer.os_tenant_id = tenant_id
        db.session.commit()

        start = datetime(2015, 4, 1)
        middle_end = datetime(2015, 4, 1, 15) - timedelta(seconds=1)
        end = datetime(2015, 4, 2) - timedelta(seconds=1)
        end_second = datetime(2015, 4, 3) - timedelta(seconds=1)
        end_report = end_second + timedelta(hours=24)
        vm_nano = uuid.uuid4().hex
        vm_small = uuid.uuid4().hex
        vm_nano2 = "nano2"

        storage_id = "disk1"

        Customer.fake_usage(customer, start, end, self.service_nano_id, vm_nano, 1, resource_name="nano1")
        Customer.fake_usage(customer, start, end, self.service_small_id, vm_small, 1, resource_name="my little pony")
        Customer.fake_usage(customer, start, middle_end , self.service_nano_id, vm_nano2, 1, resource_name="pico")
        Customer.fake_usage(customer, start, middle_end, "storage.volume", storage_id, 1237852421)
        Customer.fake_usage(customer, middle_end + timedelta(hours=1), end, "storage.volume", storage_id, 77777777777)
        Customer.fake_usage(customer, start, end, "net.allocated_ip", "ip_floating_1", 3, resource_name="192.168.1.1")
        Customer.fake_usage(customer, start, end, "net.allocated_ip", "ip_floating_2", 7)
        db.session.commit()

        second_tariff = self.create_tariff("Second Tariff", default=True)
        self.admin_client.customer.update(customer_id, tariff=second_tariff["tariff_id"])

        customer = Customer.get_by_id(customer_id)
        customer.confirm_email()  # clear db session

        customer = Customer.get_by_id(customer_id)
        customer.os_tenant_id = tenant_id  # confirm email cleared tenant id
        Customer.fake_usage(customer, end + timedelta(minutes=1), end_second, self.service_nano_id, vm_nano, 1,
                            resource_name="nano1")
        db.session.commit()

        report_tsv = self.get_customer_report(customer_id, start, end_report, "tsv", "detailed")
        report_csv = self.get_customer_report(customer_id, start, end_report, "csv", "detailed")

        report = self.get_customer_report(customer_id, start, end_report, "pdf", "detailed", filename="detailed.pdf")

        report_json = self.get_customer_report(customer_id, start, end_report, "json", "detailed")

        nano_cost = self.service_cost("2.23", start, end)
        nano2_cost = self.service_cost("2.23", start, middle_end)
        small_cost = self.service_cost("12.23", start, end)
        ip_floating_1_cost = self.service_cost("43.45", start, end)*3
        ip_floating_2_cost = self.service_cost("43.45", start, end)*7

        t1_cost = nano_cost + small_cost + nano2_cost + ip_floating_1_cost + ip_floating_2_cost
        self.assertEqual(len(report_json["tariffs"]), 2)
        self.assertEqual(Decimal(report_json["tariffs"][0]["total_cost"]), t1_cost)

        t2_cost = self.service_cost("2.23", end + timedelta(minutes=1), end_second)
        self.assertEqual(Decimal(report_json["tariffs"][1]["total_cost"]), t2_cost)

        self.assertEqual(Decimal(report_json["total"]["RUB"]), t1_cost + t2_cost)


        report = self.get_customer_report(customer_id, start, end_report, "pdf", filename="two_tariff.pdf")
        self.assertTrue(report)

        report = self.get_customer_report(customer_id, start, end_report, "csv", filename="two_tariff.csv")
        self.assertTrue(report)

        report = self.get_customer_report(customer_id, start, end_report, "tsv", filename="two_tariff.tsv")
        self.assertTrue(report)

        report_simple_json = self.get_customer_report(customer_id, start, end_report, "json", filename="two_tariff.pdf")
        self.assertTrue(report_simple_json)

        self.assertEqual(Decimal(report_simple_json["total"]["RUB"]), t1_cost + t2_cost)

        report = self.get_customer_report(customer_id, start, end_report, "pdf", "acceptance_act")

        report = self.get_customer_report(customer_id, end_report + timedelta(days=1),
                                          end_second + timedelta(days=31), "pdf", filename="empty.pdf")
Example #20
0
    def payment_pay(self, *args, **request_data):
        """Checks payment availability for customer.
        Parameters must be sent as json object. Request data looks like:
        {
              'AccountId': '1000', # Customer ID here
              'Amount': '10.00',
              'AuthCode': 'A1B2C3',
              'CardExpDate': '10/15',
              'CardFirstSix': '424242',
              'CardLastFour': '4242',
              'CardType': 'Visa',
              'Currency': 'RUB',
              'Data': '{"myProp":"myProp value"}',
              'DateTime': '2015-08-05 06:54:46',
              'Description': 'Payment description',
              'Email': '*****@*****.**',
              'InvoiceId': '1234567',
              'IpAddress': '46.251.83.16',
              'IpCity': 'Moscow',
              'IpCountry': 'RU',
              'IpDistrict': 'Moscow federal district',
              'IpLatitude': '56.329918',
              'IpLongitude': '44.009193',
              'IpRegion': 'Moscow district',
              'Name': 'CARDHOLDER NAME',
              'PaymentAmount': '10.00',  # Not found in documentation but exist in request
              'PaymentCurrency': 'RUB',  # No in docs
              'Status': 'Completed',
              'TestMode': '1',
              'Token': '477BBA133C182267FE5F086924ABDC5DB71F77BFC27F01F2843F2CDC69D89F05',
              'TransactionId': '1211506'
        }

        :param Int TransactionId: Mandatory - System transaction number.
        :param Numeric Amount: Mandatory - Payment amount from widget. Dot as separator, two digits after dot.
        :param String Currency: Mandatory - Currency: RUB/USD/EUR/GBP from widget parameters.
        :param String InvoiceId: Not mandatory - Order number from widget parameters.
        :param String AccountId: Mandatory - Customer identifier from widget parameters.
        :param String SubscriptionId: Not mandatory - Subscription identifier from widget parameters (for recurrent payments).
        :param String Name: Not mandatory - Card holder name.
        :param String Email: Payer's e-mail
        :param DateTime: Mandatory - Payment creation date/time in UTC (yyyy-MM-dd HH:mm:ss).
        :param String IpAddress: Not mandatory - Payer IP-address
        :param String IpCountry: Not mandatory - Payer's country double-chars code (according to ISO3166-1)
        :param String IpCity: Not mandatory - Payer's city
        :param String IpRegion: Not mandatory - Payer's region.
        :param String IpDistrict: Not mandatory - Payer's district.
        :param String CardFirstSix: Mandatory - Credit card first 6 digits
        :param String CardLastFour: Mandatory - Credit card last 6 digits
        :param String CardType: Mandatory - Card payment system: Visa or MasterCard or Maestro
        :param String CardExpDate: Mandatory - Card expiration date MM/YY
        :param String Issuer: Not mandatory - Issuer bank name
        :param String IssuerBankCountry: Not mandatory - Issuer bank country double-char code (according to ISO3166-1)
        :param String Description: Not mandatory - Payment description from widget parameters.
        :param Json Data: Not mandatory - Any json-data from widget.
        :param Bit TestMode: Mandatory - Test mode flag (1 or 0)
        :param String Status: Mandatory - Payment status: Completed — for single-step, Authorized — for double-step.
        :param String Token: Not mandatory - Card token for recurrent payments without card data.

        :return: Status code, looks like {'code': 0}
        """
        logbook.info("[payment_pay] Request info:{}", request_data)
        short_payment_info = dict([(key, request_data.get(key)) for key in PaymentsApi.payment_info_fields])

        # Common validation
        validation_res, validation_info = self.validate_request(request_data, short_payment_info)
        if not validation_res:
            log_error("[payment_pay] {} Payment info: {}", validation_info, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        # Currency validation
        currency = request_data['Currency']
        if not currency or currency not in conf.currency.active:
            log_error("[payment_pay] Invalid or incompatible currency: {}. Payment info: {}",
                      currency, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        # Customer validation
        customer_id = request_data['AccountId']
        customer = Customer.get_by_id(customer_id, False)
        if not customer:
            log_error("[payment_pay] Customer id '{}' not found. Payment info: {}",
                      customer_id, short_payment_info)
            # Expected successful code (no other codes were accepted for pay)
            return {"code": self.ERROR_OK}

        if customer.is_test_mode():
            # Payments in test mode is not allowed
            logbook.warning("[payment_pay] Customer {} in test mode. Payment info {}", customer, short_payment_info)
            return {'code': self.ERROR_OK}

        # Transaction validation
        transaction_id = request_data['TransactionId']
        transaction_count = customer.check_account_history_transaction(transaction_id)
        if transaction_count:
            # This transaction already processed
            logbook.warning("[payment_pay] Customer {}. Transaction already processed. Payment info {}",
                            customer, short_payment_info)
            return {'code': self.ERROR_OK}

        payment_description = _("Balance recharge via CloudPayments. Transaction: {}")

        # Process payment
        amount = Decimal(request_data['Amount'])
        customer.modify_balance(amount, currency, None,
                                payment_description.format(request_data['TransactionId']),
                                transaction_id=transaction_id)

        # Save customer's payment card for automated payments
        aux_data = request_data.get('Data')
        if aux_data and aux_data.get('saveAsDefault', False) is True:
            card_token = request_data.get("Token")
            if not card_token:
                log_error("[payment_pay] Customer {} wants to save card, but Token empty. Payment info: {}",
                          customer, short_payment_info)
            else:
                card = CustomerCard.add_card(customer_id, request_data['CardLastFour'], request_data['CardType'],
                                             card_token, active=True)
                logbook.info("[payment_pay] Customer {}. Add payment card: {}",
                             customer, card.display())

        # Expected successful code (no other codes were accepted for pay)
        return {"code": 0}
Example #21
0
    def test_hour_stat(self, wrp_get_volumes, wrp_get_images, wrp_get_floating_ips,
                       wrp_get_nova_servers, wrp_get_nova_flavors, wrp_get_snapshots,
                       wrp_get_tenants, wrp_get_nova_limits, wrp_get_ceilometer_samples):
        self.create_tariff("stat")
        self.create_customer("*****@*****.**")

        blocked = self.create_customer("*****@*****.**")
        self.admin_client.customer.block(blocked["customer_id"])

        entity = self.create_customer("*****@*****.**")
        self.admin_client.customer.update(entity["customer_id"], customer_type="entity")
        customer_info = self.create_customer("*****@*****.**", make_prod=True)

        tenant = ModelTenant.create("fake tenant_id", "fake tenant")
        customer = Customer.get_by_id(customer_info["customer_id"])
        customer.os_tenant_id = tenant.tenant_id
        db.session.add(tenant)
        db.session.flush()

        deleted = self.create_customer("*****@*****.**", make_prod=True)
        self.admin_client.customer.delete(deleted["customer_id"])

        from task.notifications import hour_stats
        from keystoneclient.v2_0.tenants import Tenant
        from novaclient.v2.flavors import Flavor
        from novaclient.v2.servers import Server
        from cinderclient.v2.volume_snapshots import Snapshot
        from cinderclient.v2.volumes import Volume
        from ceilometerclient.v2.samples import Sample

        info_flavors = [
            {'OS-FLV-DISABLED:disabled': False,
             'OS-FLV-EXT-DATA:ephemeral': 0,
             'disk': 30,
             'id': 'flavor_id_1',
             'links': [{
                           'href': 'http://openstack.org:8774/v2/2a870d56e2b9411a86fd1736f2217c10/flavors/0316748f-a62f-49ce-a5fe-22e84fb9ad62',
                           'rel': 'self'},
                       {
                           'href': 'http://openstack.org:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/0316748f-a62f-49ce-a5fe-22e84fb9ad62',
                           'rel': 'bookmark'}],
             'name': 'Medium',
             'os-flavor-access:is_public': False,
             'ram': 8192,
             'rxtx_factor': 1.0,
             'swap': '',
             'vcpus': 2},

            {'OS-FLV-DISABLED:disabled': False,
             'OS-FLV-EXT-DATA:ephemeral': 0,
             'disk': 30,
             'id': 'flavor_id_2',
             'links': [{
                           'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/flavors/25e56f22-0ead-41d3-8485-e07af3114de0',
                           'rel': 'self'},
                       {
                           'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/25e56f22-0ead-41d3-8485-e07af3114de0',
                           'rel': 'bookmark'}],
             'name': 'M.Large',
             'os-flavor-access:is_public': False,
             'ram': 24576,
             'rxtx_factor': 1.0,
             'swap': '',
             'vcpus': 4}
        ]

        info_servers = [
            {'OS-DCF:diskConfig': 'AUTO',
             'OS-EXT-AZ:availability_zone': 'zone',
             'OS-EXT-SRV-ATTR:host': 'qk-9',
             'OS-EXT-SRV-ATTR:hypervisor_hostname': 'qk-9.domain.tld',
             'OS-EXT-SRV-ATTR:instance_name': 'instance-00000ef3',
             'OS-EXT-STS:power_state': 1,
             'OS-EXT-STS:task_state': None,
             'OS-EXT-STS:vm_state': 'active',
             'OS-SRV-USG:launched_at': '2015-10-01T20:23:32.000000',
             'OS-SRV-USG:terminated_at': None,
             'accessIPv4': '',
             'accessIPv6': '',
             'addresses': {'Internet-IPs': [{'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:e7:13:b3',
                                             'OS-EXT-IPS:type': 'fixed',
                                             'addr': '192.168.19.63',
                                             'version': 4}]},
             'config_drive': '',
             'created': '2015-10-01T20:23:15Z',
             'flavor': {
                 'id': 'flavor_id_1',
                 'links': [{
                               'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/6214ea5e-8d51-4025-885c-e14821b220cc',
                               'rel': 'bookmark'}]},
             'hostId': 'cb111a482618c143ca7a28c87ff0a93a1fb19283192509ac22c32af0',
             'id': '4eda7eb2-e1c9-4f92-b32f-663c11d2deb0',
             'image': '',
             'key_name': None,
             'links': [{
                           'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/servers/4eda7eb2-e1c9-4f92-b32f-663c11d2deb0',
                           'rel': 'self'},
                       {
                           'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/servers/4eda7eb2-e1c9-4f92-b32f-663c11d2deb0',
                           'rel': 'bookmark'}],
             'metadata': {},
             'name': 'active_test',
             'os-extended-volumes:volumes_attached': [{'id': '115feaa7-1126-461d-ad60-067da6dff7c9'}],
             'progress': 0,
             'security_groups': [{'name': 'default'}],
             'status': 'ACTIVE',
             'tenant_id': 'tenant_id_1',
             'updated': '2015-10-01T20:23:32Z',
             'user_id': '25640457f00a485698caabf72bba5f8a'},

            {'OS-DCF:diskConfig': 'AUTO',
             'OS-EXT-AZ:availability_zone': 'zone',
             'OS-EXT-SRV-ATTR:host': 'qk-13',
             'OS-EXT-SRV-ATTR:hypervisor_hostname': 'qk-13.domain.tld',
             'OS-EXT-SRV-ATTR:instance_name': 'instance-00000ef0',
             'OS-EXT-STS:power_state': 1,
             'OS-EXT-STS:task_state': None,
             'OS-EXT-STS:vm_state': 'active',
             'OS-SRV-USG:launched_at': '2015-10-01T20:21:17.000000',
             'OS-SRV-USG:terminated_at': None,
             'accessIPv4': '',
             'accessIPv6': '',
             'addresses': {
                 'Internet-IPs': [{'OS-EXT-IPS-MAC:mac_addr': 'fa:16:3e:c6:e1:ac',
                                   'OS-EXT-IPS:type': 'fixed',
                                   'addr': '192.169.19.62',
                                   'version': 4}]},
             'config_drive': '',
             'created': '2015-10-01T20:21:01Z',
             'flavor': {'id': 'flavor_id_2',
                        'links': [
                            {
                                'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/flavors/6214ea5e-8d51-4025-885c-e14821b220cc',
                                'rel': 'bookmark'}
                        ]},
             'hostId': 'ccf318ebe253336d47f9bc105c723af000579aa2bc3111262e43e032',
             'id': 'c7856a12-a749-47f2-8c7a-e4ee6e310ef6',
             'image': '',
             'key_name': 'testtesttest',
             'links': [{
                           'href': 'http://openstack.ru:8774/v2/2a870d56e2b9411a86fd1736f2217c10/servers/c7856a12-a749-47f2-8c7a-e4ee6e310ef6',
                           'rel': 'self'},
                       {
                           'href': 'http://openstack.ru:8774/2a870d56e2b9411a86fd1736f2217c10/servers/c7856a12-a749-47f2-8c7a-e4ee6e310ef6',
                           'rel': 'bookmark'}],
             'metadata': {},
             'name': 'testtesttest',
             'os-extended-volumes:volumes_attached': [{'id': 'eac9cfdf-6f88-4ab9-b005-0e4f2534bc08'}],
             'progress': 0,
             'security_groups': [{'name': 'default'}],
             'status': 'stopped',
             'tenant_id': 'tenant_id_2',
             'updated': '2015-10-01T20:21:18Z',
             'user_id': '25640457f00a485698caabf72bba5f8a'}
        ]

        info_floating_ips = [
            {'fixed_ip_address': None,
             'floating_ip_address': '192.168.122.220',
             'floating_network_id': '14d12e05-6e0f-4b1c-b8cd-43747eb5b8c5',
             'id': '9a31e9ff-6b23-43e6-afad-ddd3ba194597',
             'port_id': None,
             'router_id': None,
             'status': 'DOWN',
             'tenant_id': 'd31e2dbfe716428daddbd4631bb73ab0'},
            {'fixed_ip_address': None,
             'floating_ip_address': '192.168.122.220',
             'floating_network_id': '14d12e05-6e0f-4b1c-b8cd-43747eb5b8c5',
             'id': '9a31e9ff-6b23-43e6-afad-ddd3ba194597',
             'port_id': None,
             'router_id': None,
             'status': 'UP',
             'tenant_id': 'd31e2dbfe716428daddbd4631bb73ab0'}]

        info_images = [
            {
                'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6',
                'container_format': 'bare',
                'created_at': '2015-08-05T10:24:00Z',
                'disk_format': 'qcow2',
                'file': '/v2/images/cf70343a-54a7-46e8-9707-330f149d16ef/file',
                'id': 'cf70343a-54a7-46e8-9707-330f149d16ef',
                'min_disk': 0,
                'min_ram': 0,
                'name': 'cirros-0.3.4-x86_64',
                'owner': '514c60f95d9240508be98d1bf20fdccb',
                'protected': False,
                'schema': '/v2/schemas/image',
                'size': 5,
                'status': 'active',
                'tags': [],
                'updated_at': '2015-08-05T10:24:00Z',
                'virtual_size': None,
                'visibility': 'public'
            },
            {
                'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6',
                'container_format': 'bare',
                'created_at': '2015-08-05T10:24:00Z',
                'disk_format': 'qcow2',
                'file': '/v2/images/cf70343a-54a7-46e8-9707-330f149d16ef/file',
                'id': 'cf70343a-54a7-46e8-9707-330f149d16ef',
                'min_disk': 0,
                'min_ram': 0,
                'name': 'cirros-0.3.4-x86_64',
                'owner': '514c60f95d9240508be98d1bf20fdccb',
                'protected': False,
                'schema': '/v2/schemas/image',
                'size': 7,
                'status': 'active',
                'tags': [],
                'updated_at': '2015-08-05T10:24:00Z',
                'virtual_size': None,
                'visibility': 'private'
            }]
        info_volumes = [
            {
                'attachments': [],
                'availability_zone': 'nova',
                'bootable': 'false',
                'consistencygroup_id': None,
                'created_at': '2015-10-08T15:24:22.000000',
                'description': None,
                'encrypted': False,
                'id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc',
                'links': [
                    {
                        'href': 'http://192.168.3.101:8776/v2/514c60f95d9240508be98d1bf20fdccb/volumes/a5514296-4c70-426c-ba74-3e1ffc29bffc',
                        'rel': 'self'},
                    {
                        'href': 'http://192.168.3.101:8776/514c60f95d9240508be98d1bf20fdccb/volumes/a5514296-4c70-426c-ba74-3e1ffc29bffc',
                        'rel': 'bookmark'}],
                'metadata': {},
                'multiattach': False,
                'name': 'denis_test_volume_1',
                'os-vol-host-attr:host': 'ubuntu-kilo#GlusterFS',
                'os-vol-mig-status-attr:migstat': None,
                'os-vol-mig-status-attr:name_id': None,
                'os-vol-tenant-attr:tenant_id': 'aee181ad99394b9e81ecad5d61d09261',
                'os-volume-replication:driver_data': None,
                'os-volume-replication:extended_status': None,
                'replication_status': 'disabled',
                'size': 7,
                'snapshot_id': None,
                'source_volid': None,
                'status': 'available',
                'user_id': '5f796d5bee7f424180c6ba79f55811fe',
                'volume_type': None
            },
            {'attachments': [{'attachment_id': '6464d0e4-7bfa-4284-87bd-85d151e4fdfd',
                              'device': '/dev/vda',
                              'host_name': None,
                              'id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c',
                              'server_id': 'a96aa81d-c5e9-4b05-8e6d-9db7838cf94d',
                              'volume_id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c'}],
             'availability_zone': 'nova',
             'bootable': 'true',
             'consistencygroup_id': None,
             'created_at': '2015-10-08T14:14:19.000000',
             'description': 'hdisk1 hdisk1 hdisk1',
             'encrypted': False,
             'id': '51e36e6b-aa99-4adc-8f50-e6066a8c885c',
             'links': [{
                           'href': 'http://192.168.3.101:8776/v2/514c60f95d9240508be98d1bf20fdccb/volumes/51e36e6b-aa99-4adc-8f50-e6066a8c885c',
                           'rel': 'self'},
                       {
                           'href': 'http://192.168.3.101:8776/514c60f95d9240508be98d1bf20fdccb/volumes/51e36e6b-aa99-4adc-8f50-e6066a8c885c',
                           'rel': 'bookmark'}],
             'metadata': {'attached_mode': 'rw', 'readonly': 'False'},
             'multiattach': False,
             'name': 'hdisk1',
             'os-vol-host-attr:host': 'ubuntu-kilo#GlusterFS',
             'os-vol-mig-status-attr:migstat': None,
             'os-vol-mig-status-attr:name_id': None,
             'os-vol-tenant-attr:tenant_id': '8e165ea202e346299280cb7afd9ef828',
             'os-volume-replication:driver_data': None,
             'os-volume-replication:extended_status': None,
             'replication_status': 'disabled',
             'size': 9,
             'snapshot_id': None,
             'source_volid': None,
             'status': 'in-use',
             'user_id': '392b8565a7ad497793d6bd826db6dbc9',
             'volume_image_metadata': {'checksum': 'ee1eca47dc88f4879d8a229cc70a07c6',
                                       'container_format': 'bare',
                                       'disk_format': 'qcow2',
                                       'image_id': 'cf70343a-54a7-46e8-9707-330f149d16ef',
                                       'image_name': 'cirros-0.3.4-x86_64',
                                       'min_disk': '0',
                                       'min_ram': '0',
                                       'size': '13287936'}, }
        ]
        info_snapshots = [
            {
                'created_at': '2015-10-08T15:25:00.000000',
                'description': '',
                'id': '055f5dc8-2224-47eb-8a55-9c3ecf2f74a0',
                'metadata': {},
                'name': 'test_snapshot_1',
                'os-extended-snapshot-attributes:progress': '100%',
                'os-extended-snapshot-attributes:project_id': 'aee181ad99394b9e81ecad5d61d09261',
                'size': 3,
                'status': 'available',
                'volume_id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc'
            }, {
                'created_at': '2015-10-08T15:25:00.000000',
                'description': '',
                'id': '055f5dc8-2224-47eb-8a55-9c3ecf2f74a0',
                'metadata': {},
                'name': 'test_snapshot_2',
                'os-extended-snapshot-attributes:progress': '100%',
                'os-extended-snapshot-attributes:project_id': 'aee181ad99394b9e81ecad5d61d09261',
                'size': 5,
                'status': 'available',
                'volume_id': 'a5514296-4c70-426c-ba74-3e1ffc29bffc'
            }
        ]
        info_tenants = [
            {'description': 'Unit test tenant - 1',
             'enabled': True,
             'id': 'tenant_id_1',
             'name': 'tenant_name_1'},
            {'description': 'Unit test tenant - 2',
             'enabled': True,
             'id': 'tenant_id_2',
             'name': 'tenant_name_2'},
            {'description': 'Unit test tenant - 3',
             'enabled': True,
             'id': 'tenant_id_3',
             'name': 'tenant_name_3'},
        ]
        info_nova_limits = {
            'maxImageMeta': 128,
            'maxPersonality': 5,
            'maxPersonalitySize': 10240,
            'maxSecurityGroupRules': 20,
            'maxSecurityGroups': 10,
            'maxServerGroupMembers': 10,
            'maxServerGroups': 10,
            'maxServerMeta': 128,
            'maxTotalCores': 20,
            'maxTotalFloatingIps': 10,
            'maxTotalInstances': 20,
            'maxTotalKeypairs': 10,
            'maxTotalRAMSize': 20480,
            'totalCoresUsed': 1,
            'totalFloatingIpsUsed': 0,
            'totalInstancesUsed': 1,
            'totalRAMUsed': 8192,
            'totalSecurityGroupsUsed': 1,
            'totalServerGroupsUsed': 0
        }

        info_bandwidth = [
            {'id': 'c9510474-5e04-11e5-920d-fa163e4b35b4',
             'metadata': {'fref': 'None',
                          'instance_id': '1b02a1c2-7a6e-404a-b355-d2840d295677',
                          'instance_type': 'ef9a407d-742d-4f23-9055-decbccb143d9',
                          'mac': 'fa:16:3e:9e:18:12',
                          'name': 'tap345a6b63-eb'},
             'meter': 'network.incoming.bytes',
             'project_id': '03926f96177e4df9a0fc5c77f6e674d8',
             'recorded_at': '2015-09-18T12:57:15.769000',
             'resource_id': 'instance-00000018-1b02a1c2-7a6e-404a-b355-d2840d295677-tap345a6b63-eb',
             'source': 'openstack',
             'timestamp': '2015-09-18T12:57:15',
             'type': 'cumulative',
             'unit': 'B',
             'user_id': 'c1ef3d08d9694acb8740ccb66d0ba945',
             'volume': 11.0
             },
        ]

        wrp_get_ceilometer_samples.return_value = [Sample(None, s) for s in info_bandwidth]
        wrp_get_images.return_value = info_images
        wrp_get_floating_ips.return_value = info_floating_ips
        wrp_get_tenants.return_value = [Tenant(None, t) for t in info_tenants]
        wrp_get_nova_servers.return_value = [Server(None, s) for s in info_servers]
        wrp_get_nova_flavors.return_value = [Flavor(None, f) for f in info_flavors]
        wrp_get_volumes.return_value = [Volume(None, volume) for volume in info_volumes]
        wrp_get_snapshots.return_value = [Snapshot(None, snapshot) for snapshot in info_snapshots]
        wrp_get_nova_limits.return_value = info_nova_limits

        # Run stat collection
        hour_stats()

        expected_stats = {
            "stats.flavor.total": 2,
            "stats.flavor.Medium": 1,

            'stats.ip.floating.active_customer': 6,
            'stats.ip.floating.blocked_customer': 2,
            'stats.ip.floating.customer_mode-production': 2,
            'stats.ip.floating.customer_mode-test': 6,
            'stats.ip.floating.customer_type-entity': 2,
            'stats.ip.floating.customer_type-private': 6,
            'stats.ip.floating.ip_status-DOWN': 4,
            'stats.ip.floating.ip_status-UP': 4,
            'stats.ip.floating.total': 8,

            'stats.storage.image.total': 2,
            'stats.storage.image.total_size': 12,
            'stats.storage.image.visibility-public': 1,
            'stats.storage.image.visibility-private': 1,
            'stats.storage.image.status-active': 2,

            'stats.storage.volume.total': 2,
            'stats.storage.volume.total_size': 16,
            'stats.storage.volume.volume-bootable': 2,
            'stats.storage.volume.status-available': 1,
            'stats.storage.volume.status-in-use': 1,

            'stats.storage.snapshots.total': 2,
            'stats.storage.snapshots.total_size': 8,
            'stats.storage.snapshots.available': 2,

            'stats.resources.totalRAMUsed': 8192*1,
            'stats.resources.totalCoresUsed': 1,
            'stats.resources.flavor.Medium.ram': 8192,
            'stats.resources.flavor.Medium.vcpus': 2,

            'stats.network.outgoing.bytes': info_bandwidth[0]['volume'] * len(info_tenants),
            'stats.network.incoming.bytes': info_bandwidth[0]['volume'] * len(info_tenants),

        }
        for k, v in expected_stats.items():
            self.verify_metric(k, v)
Example #22
0
def customer_auto_report(customer_id, time_now):
    from model import Customer, ScheduledTask
    from task.mail import send_email
    customer = Customer.get_by_id(customer_id)

    if not customer:
        logbook.error("Can't find customer {} for report generation", customer_id)
        return

    report_task = ScheduledTask.get_by_customer(customer_id, Customer.AUTO_REPORT_TASK)
    if not report_task:
        logbook.error("Can't find auto report task for customer {}", customer_id)
        return

    logbook.debug("Start auto-report task for customer {}: {}", customer, report_task)

    report_task.start()

    previous_next_send = report_task.next_scheduled.replace(tzinfo=utc)
    if previous_next_send is None or previous_next_send > time_now:
        logbook.warning("Looks like report for customer {} already sent. Next send: {}, current time {}",
                        customer, previous_next_send, time_now)
        report_task.completed(now=time_now)
        return

    report_begin = day_start(report_task.last or time_now)
    _, report_end = report_task.task_range(time_now, previous_interval=True)
    report_end = day_start(report_end)

    report_id = CustomerReportId(customer.customer_id, report_begin, report_end,
                                 conf.customer.report.type, conf.customer.report.format, customer.locale)
    report_file_generate(report_id)

    # report_file_generate closed session so we should initialize customer again
    customer = Customer.get_by_id(customer_id)
    report_task = ScheduledTask.get_by_customer(customer_id, Customer.AUTO_REPORT_TASK)

    report_cache = ReportCache()

    report = report_cache.get_report_aggregated(report_id)

    if not report or not report["tariffs"]:
        logbook.info("Report is empty for customer {}", customer)
        report_task.completed(now=time_now)
        return

    report_file = report_cache.get_report(report_id)

    if not report_file:
        logbook.error("Report generation failed")
        report_task.completed(False)
        return

    filename = Report.generate_file_name(customer.get_name(), report_begin, report_end, conf.customer.report.format)

    subject, body = MessageTemplate.get_rendered_message(
        MessageTemplate.CUSTOMER_AUTO_REPORT, customer.locale_language(),
        customer_name=customer.get_name(), currency=customer.tariff.currency,
        report_start=report_begin, report_end=report_end)


    subscription_info = customer.subscription_info()['billing']

    if subscription_info["enable"]:
        send_email.delay(subscription_info["email"], subject, body, attachments=[(filename, report_file)])

    report_task.completed(now=time_now)
    comment_fmt = "%s - %s" % (report_begin.strftime('%Y-%m-%d'), report_end.strftime('%Y-%m-%d'))

    for currency, amount in report["total"].items():
        amount = Decimal(amount)
        customer.modify_balance(-amount, currency, None, comment_fmt)
        account = customer.get_account(currency)
        account.charge(-amount)

    db.session.commit()
Example #23
0
    def test_collector(self):
        start_time = datetime.datetime(2015, 3, 20, 9, 12)
        end_time = datetime.datetime(2015, 5, 1)
        project = Tenant("boss", start_time)

        disk = Disk(project, "test_disk", start_time, 1234567890)
        disk2 = Disk(project, "test_disk2", start_time, 3456)
        volume = Volume(project, "figvam", datetime.datetime.now(), 2)
        vm = Instance(project, "teamcity", "Nano")
        vm2 = Instance(project, "teamcity1", "TestFlavor")

        disk.repeat_message(start_time, end_time)
        disk2.repeat_message(start_time, end_time)
        vm.repeat_message(start_time, end_time)
        vm2.repeat_message(start_time, end_time)
        volume.repeat_message(start_time, end_time)

        hour_price = Decimal(self.volume_size_price) * 2 + Decimal(self.image_size_price) * 3 + \
             + Decimal(self.nano_price)

        with mock.patch("os_interfaces.openstack_wrapper.openstack") as openstack:
            openstack.get_tenant_usage = project.usage
            project.prepare_messages()

            tenants_usage = self.collector.run_usage_collection(end_time + datetime.timedelta(hours=10))
            tenant_usage = next(iter(tenants_usage.values()))
            self.assertTrue(tenant_usage)
            self.assertEqual(self.collector.errors, 0)
            for time_label, time_label_usage in tenant_usage.items():
                withdraw = time_label_usage[1]
                self.assertLess(withdraw - hour_price, 1e-6)
                for usage in time_label_usage[0]:
                    if usage["service_id"] == "image.size":
                        self.assertEqual(usage.volume, 1234567890)
                    if usage['service_id'] == "volume.size":
                        self.assertEqual(usage.volume, 2 * 1073741824) # 2GB

        self.assertEqual(outbox[1].subject, '%s: Notice on service adding notification' % conf.provider.cloud_name)

        account = Customer.get_by_id(project.customer_id).account_dict()["RUB"]
        self.assertEqual(account["balance"], Decimal(project.start_balance))
        hours = int((end_time - start_time).total_seconds() // 3600) + 1
        total_cost = hours * hour_price
        self.assertLess(abs(account["withdraw"] - total_cost), 0.0001)

        report = self.get_report(project.customer_id, start_time, end_time, "json")
        self.assertEqual(report["total"]["RUB"], decimal_to_string(total_cost))

        report = self.get_report(project.customer_id, start_time, end_time, "json", report_is_ready=True)

        report_ru = self.get_report(project.customer_id, start_time, end_time, "csv")
        customer = Customer.get_by_id(project.customer_id)
        customer.locale = "en_us"
        db.session.commit()
        report_en = self.get_report(project.customer_id, start_time, end_time, "csv", filename="report_en.csv")
        self.assertNotEqual(report_ru, report_en)
        self.assertGreater(report_ru.count(b";"), 0)
        self.assertEqual(report_en.count(b";"), 0)

        # pdf en
        self.get_report(project.customer_id, start_time, end_time, "pdf")
        customer = Customer.get_by_id(project.customer_id)
        customer.locale = "ru_ru"
        db.session.commit()

        # pdf ru
        self.get_report(project.customer_id, start_time, end_time, "pdf")
        # json after pdf
        json_report = self.get_report(project.customer_id, start_time, end_time, "json", report_is_ready=True)

        self.cabinet_client.auth(project.customer_email, project.customer_password)
        customer_report = self.get_report_me(start_time, end_time, "json", report_is_ready=True)
        self.assertEqual(json_report, customer_report)

        self.get_report_me(start_time - datetime.timedelta(days=30), start_time, "csv", filename="empty.csv")
        self.get_report_me(start_time - datetime.timedelta(days=30), start_time, "pdf", filename="empty.pdf")