def test_populate_monthly_cost_cluster_supplementary_cost(self): """Test that the monthly infrastructure cost row for clusters in the summary table is populated.""" self.cluster_id = self.ocp_provider.authentication.provider_resource_name cluster_rate = random.randrange(1, 100) dh = DateHelper() start_date = dh.this_month_start end_date = dh.this_month_end first_month, _ = month_date_range_tuple(start_date) cluster_alias = "test_cluster_alias" self.accessor.populate_monthly_cost( "Cluster", "Supplementary", cluster_rate, start_date, end_date, self.cluster_id, cluster_alias ) monthly_cost_rows = ( self.accessor._get_db_obj_query(OCPUsageLineItemDailySummary) .filter(usage_start=first_month, supplementary_monthly_cost__isnull=False) .all() ) with schema_context(self.schema): self.assertEquals(monthly_cost_rows.count(), 1) for monthly_cost_row in monthly_cost_rows: self.assertEquals(monthly_cost_row.supplementary_monthly_cost, cluster_rate)
def test_remove_monthly_cost(self): """Test that the monthly cost row in the summary table is removed.""" self.cluster_id = self.ocp_provider.authentication.provider_resource_name node_rate = random.randrange(1, 100) dh = DateHelper() start_date = dh.this_month_start end_date = dh.this_month_end first_month, first_next_month = month_date_range_tuple(start_date) cluster_alias = "test_cluster_alias" cost_type = "Node" rate_type = metric_constants.SUPPLEMENTARY_COST_TYPE self.accessor.populate_monthly_cost( cost_type, rate_type, node_rate, start_date, end_date, self.cluster_id, cluster_alias ) monthly_cost_rows = ( self.accessor._get_db_obj_query(OCPUsageLineItemDailySummary) .filter(usage_start=first_month, supplementary_monthly_cost__isnull=False) .all() ) with schema_context(self.schema): self.assertTrue(monthly_cost_rows.exists()) self.accessor.remove_monthly_cost(start_date, first_next_month, self.cluster_id, cost_type) with schema_context(self.schema): self.assertFalse(monthly_cost_rows.exists())
def remove_monthly_cost(self): """Delete all the monthly costs of a customer.""" # start_date should be the first month this ocp was used start_date = OCPUsageLineItemDailySummary.objects.aggregate( Min("usage_start"))["usage_start__min"] # If end_date is not provided, recalculate till the latest month end_date = OCPUsageLineItemDailySummary.objects.aggregate( Max("usage_end"))["usage_end__max"] LOG.info("Removing monthly costs from %s to %s.", start_date, end_date) first_month = start_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0) with schema_context(self.schema): # Calculate monthly cost for every month for curr_month in rrule(freq=MONTHLY, until=end_date, dtstart=first_month): first_curr_month, _ = month_date_range_tuple(curr_month) # Remove existing monthly costs OCPUsageLineItemDailySummary.objects.filter( usage_start=first_curr_month, monthly_cost__isnull=False).delete()
def test_populate_monthly_cost_node_supplementary_cost(self): """Test that the monthly supplementary cost row for nodes in the summary table is populated.""" self.cluster_id = self.ocp_provider.authentication.provider_resource_name node_rate = random.randrange(1, 100) dh = DateHelper() start_date = dh.this_month_start end_date = dh.this_month_end first_month, _ = month_date_range_tuple(start_date) cluster_alias = "test_cluster_alias" self.accessor.populate_monthly_cost( "Node", "Supplementary", node_rate, start_date, end_date, self.cluster_id, cluster_alias ) monthly_cost_rows = ( self.accessor._get_db_obj_query(OCPUsageLineItemDailySummary) .filter(usage_start=first_month, supplementary_monthly_cost__isnull=False) .all() ) with schema_context(self.schema): expected_count = ( OCPUsageLineItemDailySummary.objects.filter( report_period__provider_id=self.ocp_provider.uuid, usage_start__gte=start_date ) .values("node") .distinct() .count() ) self.assertEquals(monthly_cost_rows.count(), expected_count) for monthly_cost_row in monthly_cost_rows: self.assertEquals(monthly_cost_row.supplementary_monthly_cost, node_rate)
def test_remove_monthly_cost(self): """Test that the monthly cost row in the summary table is removed.""" report_table_name = OCP_REPORT_TABLE_MAP["report"] report_table = getattr(self.accessor.report_schema, report_table_name) node_cost = random.randrange(1, 100) for _ in range(5): self.creator.create_ocp_usage_line_item(self.reporting_period, self.report) with schema_context(self.schema): report_entry = report_table.objects.all().aggregate( Min("interval_start"), Max("interval_start")) start_date = report_entry["interval_start__min"] end_date = report_entry["interval_start__max"] self.accessor.populate_line_item_daily_table(start_date, end_date, self.cluster_id) self.accessor.populate_line_item_daily_summary_table( start_date, end_date, self.cluster_id) cluster_alias = "test_cluster_alias" self.accessor.populate_monthly_cost(node_cost, start_date, end_date, self.cluster_id, cluster_alias) first_month, _ = month_date_range_tuple(start_date) monthly_cost = self.accessor._get_db_obj_query( OCPUsageLineItemDailySummary).filter(usage_start=first_month, monthly_cost__isnull=False) self.assertTrue(monthly_cost.exists()) self.accessor.remove_monthly_cost() self.assertFalse(monthly_cost.exists())
def test_populate_monthly_cost(self): """Test that the monthly cost row in the summary table is populated.""" report_table_name = OCP_REPORT_TABLE_MAP['report'] report_table = getattr(self.accessor.report_schema, report_table_name) node_cost = random.randrange(1, 100) for _ in range(5): self.creator.create_ocp_usage_line_item(self.reporting_period, self.report) with schema_context(self.schema): report_entry = report_table.objects.all().aggregate( Min('interval_start'), Max('interval_start') ) start_date = report_entry['interval_start__min'] end_date = report_entry['interval_start__max'] start_date = start_date.replace(hour=0, minute=0, second=0, microsecond=0) end_date = end_date.replace(hour=0, minute=0, second=0, microsecond=0) first_month, _ = month_date_range_tuple(start_date) self.accessor.populate_line_item_daily_table(start_date, end_date, self.cluster_id) self.accessor.populate_line_item_daily_summary_table( start_date, end_date, self.cluster_id ) self.accessor.populate_monthly_cost(node_cost, start_date, end_date) monthly_cost_row = self.accessor._get_db_obj_query(OCPUsageLineItemDailySummary).filter( usage_start=first_month, monthly_cost__isnull=False ).first() self.assertEquals(monthly_cost_row.monthly_cost, 6 * node_cost)
def populate_monthly_cost(self, node_cost, start_date=None, end_date=None): """ Populate the monthly cost of a customer. Right now this is just the node/month cost. Calculated from node_cost * number_unique_nodes. args: node_cost (Decimal): The node cost per month start_date (datetime, str): The start_date to calculate monthly_cost. end_date (datetime, str): The end_date to calculate monthly_cost. """ if isinstance(start_date, str): start_date = parse(start_date) if isinstance(end_date, str): end_date = parse(end_date) if not start_date: # If start_date is not provided, recalculate from the first month start_date = OCPUsageLineItemDailySummary.objects.aggregate( Min('usage_start') )['usage_start__min'] if not end_date: # If end_date is not provided, recalculate till the latest month end_date = OCPUsageLineItemDailySummary.objects.aggregate( Max('usage_end') )['usage_end__max'] LOG.info('Populating Monthly cost from %s to %s.', start_date, end_date) first_month = start_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0) with schema_context(self.schema): # Calculate monthly cost for every month for curr_month in rrule(freq=MONTHLY, until=end_date, dtstart=first_month): first_curr_month, first_next_month = month_date_range_tuple(curr_month) unique_nodes = OCPUsageLineItemDailySummary.objects.\ filter(usage_start__gte=first_curr_month, usage_start__lt=first_next_month, node__isnull=False ).values_list('node').distinct().count() total_cost = node_cost * unique_nodes LOG.info('Total Cost is %s for %s nodes.', total_cost, unique_nodes) # Remove existing monthly costs OCPUsageLineItemDailySummary.objects.filter( usage_start=first_curr_month, monthly_cost__isnull=False ).delete() # Create new monthly cost OCPUsageLineItemDailySummary.objects.create( usage_start=first_curr_month, usage_end=first_curr_month, monthly_cost=total_cost )
def test_month_date_range_tuple(self): """Test month_date_range_tuple returns first of the month and first of next month.""" test_date = datetime(year=2018, month=12, day=15) expected_start_month = datetime(year=2018, month=12, day=1) expected_start_next_month = datetime(year=2019, month=1, day=1) start_month, first_next_month = common_utils.month_date_range_tuple(test_date) self.assertEquals(start_month, expected_start_month) self.assertEquals(first_next_month, expected_start_next_month)
def populate_monthly_cost(self, cost_type, rate_type, rate, start_date, end_date, cluster_id, cluster_alias): """ Populate the monthly cost of a customer. Right now this is just the node/month cost. Calculated from node_cost * number_unique_nodes. args: node_cost (Decimal): The node cost per month start_date (datetime, str): The start_date to calculate monthly_cost. end_date (datetime, str): The end_date to calculate monthly_cost. """ if isinstance(start_date, str): start_date = parse(start_date).date() if isinstance(end_date, str): end_date = parse(end_date).date() # usage_start, usage_end are date types first_month = datetime.datetime(*start_date.replace( day=1).timetuple()[:3]).replace(tzinfo=pytz.UTC) end_date = datetime.datetime(*end_date.timetuple()[:3]).replace( hour=23, minute=59, second=59, tzinfo=pytz.UTC) # Calculate monthly cost for each month from start date to end date for curr_month in rrule(freq=MONTHLY, until=end_date, dtstart=first_month): first_curr_month, first_next_month = month_date_range_tuple( curr_month) LOG.info("Populating monthly cost from %s to %s.", first_curr_month, first_next_month) if cost_type == "Node": if rate is None: self.remove_monthly_cost(first_curr_month, first_next_month, cluster_id, cost_type) else: self.upsert_monthly_node_cost_line_item( first_curr_month, first_next_month, cluster_id, cluster_alias, rate_type, rate) elif cost_type == "Cluster": if rate is None: self.remove_monthly_cost(first_curr_month, first_next_month, cluster_id, cost_type) else: self.upsert_monthly_cluster_cost_line_item( first_curr_month, first_next_month, cluster_id, cluster_alias, rate_type, rate)
def populate_monthly_cost(self, node_cost, start_date, end_date, cluster_id, cluster_alias): """ Populate the monthly cost of a customer. Right now this is just the node/month cost. Calculated from node_cost * number_unique_nodes. args: node_cost (Decimal): The node cost per month start_date (datetime, str): The start_date to calculate monthly_cost. end_date (datetime, str): The end_date to calculate monthly_cost. """ if isinstance(start_date, str): start_date = parse(start_date) if isinstance(end_date, str): end_date = parse(end_date) if not start_date: # If start_date is not provided, recalculate from the first month start_date = OCPUsageLineItemDailySummary.objects.aggregate( Min("usage_start"))["usage_start__min"] if not end_date: # If end_date is not provided, recalculate till the latest month end_date = OCPUsageLineItemDailySummary.objects.aggregate( Max("usage_end"))["usage_end__max"] first_month = start_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0) with schema_context(self.schema): # Calculate monthly cost for every month for curr_month in rrule(freq=MONTHLY, until=end_date, dtstart=first_month): first_curr_month, first_next_month = month_date_range_tuple( curr_month) LOG.info("Populating Monthly node cost from %s to %s.", first_curr_month, first_next_month) unique_nodes = (OCPUsageLineItemDailySummary.objects.filter( usage_start__gte=first_curr_month, usage_start__lt=first_next_month, cluster_id=cluster_id, node__isnull=False, ).values_list("node").distinct()) report_period = self.get_usage_period_by_dates_and_cluster( first_curr_month, first_next_month, cluster_id) for node in unique_nodes: LOG.info("Node (%s) has a monthly cost of %s.", node[0], node_cost) # delete node cost per month OCPUsageLineItemDailySummary.objects.filter( usage_start=first_curr_month, usage_end=first_curr_month, monthly_cost=node_cost, report_period=report_period, cluster_id=cluster_id, cluster_alias=cluster_alias, monthly_cost__isnull=False, node=node[0], ).delete() # add node cost per month OCPUsageLineItemDailySummary.objects.create( usage_start=first_curr_month, usage_end=first_curr_month, monthly_cost=node_cost, report_period=report_period, cluster_id=cluster_id, cluster_alias=cluster_alias, node=node[0], )