Skip to content

Commit e16cdae

Browse files
authored
Merge branch 'main' into esebesto/pef_subs_resources
2 parents e926afd + 02b12f0 commit e16cdae

File tree

6 files changed

+128
-21
lines changed

6 files changed

+128
-21
lines changed

Diff for: example_aws_static_data.yml

100644100755
+14-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
generators:
33
- EC2Generator:
4-
start_date: 2020-03-01
4+
start_date: today
55
processor_arch: 32-bit
66
resource_id: 55555555
77
product_sku: VEAJHRNKTJZQ
@@ -52,6 +52,19 @@
5252
family: 'Memory Optimized'
5353
cost: 1.000
5454
rate: 0.500
55+
- EBSGenerator:
56+
start_date: today
57+
product_sku: VEAJHRNBBBBD
58+
resource_id: 12345674
59+
amount: 8
60+
rate: 0.1
61+
tags:
62+
resourceTags/user:storageclass: gamma
63+
resourceTags/user:Mapping: d1
64+
resourceTags/user:Map: d2
65+
cost_category:
66+
costCategory/env: ephemeral
67+
5568

5669

5770
accounts:

Diff for: nise/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
__version__ = "4.6.5"
1+
__version__ = "4.6.9"
2+
23

34
VERSION = __version__.split(".")

Diff for: nise/generators/aws/data_transfer_generator.py

+20-3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(self, start_date, end_date, currency, payer_account, usage_accounts
4545
self._rate = float(self.attributes.get("rate", 0)) or None
4646
self._resource_id = f"i-{self.attributes.get('resource_id', self.fake.ean8())}"
4747
self._saving = float(self.attributes.get("saving", 0)) or None
48+
self._negation = self.attributes.get("negation") or False
4849
self._tags = self.attributes.get("tags", self._tags)
4950

5051
@property
@@ -81,7 +82,8 @@ def _update_data(self, row, start, end, **kwargs):
8182

8283
resource_id = self._resource_id if self._resource_id else self.fake.ean8()
8384
rate = self._rate if self._rate else round(uniform(0.12, 0.19), 3)
84-
saving = self._saving if self._saving else round(uniform(0.12, 0.19), 3)
85+
saving = self._saving
86+
negation = self._negation
8587
amount = self._amount if self._amount else uniform(0.000002, 0.09)
8688
cost = amount * rate
8789
trans_desc, operation, description, location1, location2, trans_type, aws_region = self._get_data_transfer(
@@ -114,12 +116,27 @@ def _update_data(self, row, start, end, **kwargs):
114116
row["pricing/term"] = "OnDemand"
115117
row["pricing/unit"] = "GB"
116118
row["savingsPlan/SavingsPlanEffectiveCost"] = str(saving)
119+
row["savingsPlan/SavingsPlanRate"] = str(saving)
117120

118121
# Overwrite lineItem/LineItemType for items with applied Savings plan
119122
if saving is not None:
120123
row["lineItem/LineItemType"] = "SavingsPlanCoveredUsage"
121-
self._add_tag_data(row)
122-
self._add_category_data(row)
124+
125+
if negation:
126+
row["lineItem/LineItemType"] = "SavingsPlanNegation"
127+
row["lineItem/UnblendedCost"] = -abs(cost)
128+
row["lineItem/UnblendedRate"] = -abs(rate)
129+
row["lineItem/BlendedCost"] = -abs(cost)
130+
row["lineItem/BlendedRate"] = -abs(rate)
131+
row[
132+
"lineItem/LineItemDescription"
133+
] = f"SavingsPlanNegation used by AccountId : {self.payer_account} and UsageSku : {self._product_sku}"
134+
row["lineItem/ResourceId"] = None
135+
row["savingsPlan/SavingsPlanEffectiveCost"] = None
136+
row["savingsPlan/SavingsPlanRate"] = None
137+
else:
138+
self._add_tag_data(row)
139+
self._add_category_data(row)
123140
return row
124141

125142
def generate_data(self, report_type=None):

Diff for: nise/generators/aws/ebs_generator.py

+17-11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
# along with this program. If not, see <https://www.gnu.org/licenses/>.
1616
#
1717
"""Module for ebs data generation."""
18+
import calendar
1819
from random import choice
1920
from random import uniform
2021

@@ -33,45 +34,50 @@ def __init__(self, start_date, end_date, currency, payer_account, usage_accounts
3334
"""Initialize the EBS generator."""
3435
super().__init__(start_date, end_date, currency, payer_account, usage_accounts, attributes, tag_cols)
3536
self._resource_id = "vol-{}".format(self.fake.ean8())
36-
self._amount = uniform(0.2, 300.99)
37+
self._disk_size = choice([5, 10, 15, 20, 25])
3738
self._rate = round(uniform(0.02, 0.16), 3)
3839
self._product_sku = self.fake.pystr(min_chars=12, max_chars=12).upper()
3940

4041
if self.attributes:
4142
if self.attributes.get("resource_id"):
4243
self._resource_id = "vol-{}".format(self.attributes.get("resource_id"))
43-
if self.attributes.get("amount"):
44-
self._amount = float(self.attributes.get("amount"))
4544
if self.attributes.get("rate"):
4645
self._rate = float(self.attributes.get("rate"))
4746
if self.attributes.get("product_sku"):
4847
self._product_sku = self.attributes.get("product_sku")
4948
if self.attributes.get("tags"):
5049
self._tags = self.attributes.get("tags")
50+
if _disk_size := self.attributes.get("disk_size"):
51+
self._disk_size = int(_disk_size)
5152

5253
def _get_storage(self):
5354
"""Get storage data."""
5455
return choice(self.STORAGE)
5556

57+
def _calculate_hourly_rate(self, start):
58+
"""Calculates the houly rate based of the provided monthly rate."""
59+
num_days_in_month = calendar.monthrange(start.year, start.month)[1]
60+
hours_in_month = num_days_in_month * 24
61+
return self._rate / hours_in_month
62+
5663
def _update_data(self, row, start, end, **kwargs):
5764
"""Update data with generator specific data."""
5865
row = self._add_common_usage_info(row, start, end)
59-
60-
rate = self._rate
61-
amount = self._amount
62-
cost = amount * rate
66+
hourly_rate = self._calculate_hourly_rate(start)
67+
cost = round(self._disk_size * hourly_rate, 10)
68+
amount = round(cost / self._rate, 10)
6369
location, aws_region, _, storage_region = self._get_location()
64-
description = f"${rate} per GB-Month of snapshot data stored - {location}"
70+
description = f"${self._rate} per GB-Month of snapshot data stored - {location}"
6571
burst, max_iops, max_thru, max_vol_size, vol_backed, vol_type = self._get_storage()
6672

6773
row["lineItem/ProductCode"] = "AmazonEC2"
6874
row["lineItem/UsageType"] = f"{storage_region}:VolumeUsage"
6975
row["lineItem/Operation"] = "CreateVolume"
7076
row["lineItem/ResourceId"] = self._resource_id
7177
row["lineItem/UsageAmount"] = str(amount)
72-
row["lineItem/UnblendedRate"] = str(rate)
78+
row["lineItem/UnblendedRate"] = str(self._rate)
7379
row["lineItem/UnblendedCost"] = str(cost)
74-
row["lineItem/BlendedRate"] = str(rate)
80+
row["lineItem/BlendedRate"] = str(self._rate)
7581
row["lineItem/BlendedCost"] = str(cost)
7682
row["lineItem/LineItemDescription"] = description
7783
row["product/ProductName"] = "Amazon Elastic Compute Cloud"
@@ -89,7 +95,7 @@ def _update_data(self, row, start, end, **kwargs):
8995
row["product/usagetype"] = f"{storage_region}:VolumeUsage"
9096
row["product/volumeType"] = vol_type
9197
row["pricing/publicOnDemandCost"] = str(cost)
92-
row["pricing/publicOnDemandRate"] = str(rate)
98+
row["pricing/publicOnDemandRate"] = str(self._rate)
9399
row["pricing/term"] = "OnDemand"
94100
row["pricing/unit"] = "GB-Mo"
95101
self._add_tag_data(row)

Diff for: nise/generators/aws/ec2_generator.py

+43-4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class EC2Generator(AWSGenerator):
3636
"0.096",
3737
"0.096",
3838
"0.045",
39+
1,
40+
False,
3941
"${cost} per On Demand Linux {inst_type} Instance Hour",
4042
),
4143
(
@@ -48,6 +50,8 @@ class EC2Generator(AWSGenerator):
4850
"0.34",
4951
"0.34",
5052
"0.17",
53+
1,
54+
False,
5155
"${cost} per On Demand Linux {inst_type} Instance Hour",
5256
),
5357
(
@@ -60,6 +64,8 @@ class EC2Generator(AWSGenerator):
6064
"0.199",
6165
"0.199",
6266
"0.099",
67+
1,
68+
False,
6369
"${cost} per On Demand Linux {inst_type} Instance Hour",
6470
),
6571
(
@@ -72,6 +78,8 @@ class EC2Generator(AWSGenerator):
7278
"0.133",
7379
"0.133",
7480
"0.067",
81+
1,
82+
False,
7583
"${cost} per On Demand Linux {inst_type} Instance Hour",
7684
),
7785
)
@@ -115,12 +123,27 @@ def __init__(self, start_date, end_date, currency, payer_account, usage_accounts
115123
instance_type.get("cost"),
116124
instance_type.get("rate"),
117125
instance_type.get("saving"),
126+
instance_type.get("amount", "1"),
127+
instance_type.get("negation", False),
118128
"${cost} per On Demand Linux {inst_type} Instance Hour",
119129
)
120130

121131
def _update_data(self, row, start, end, **kwargs):
122132
"""Update data with generator specific data."""
123-
inst_type, physical_cores, vcpu, memory, storage, family, cost, rate, saving, description = self._instance_type
133+
(
134+
inst_type,
135+
physical_cores,
136+
vcpu,
137+
memory,
138+
storage,
139+
family,
140+
cost,
141+
rate,
142+
saving,
143+
amount,
144+
negation,
145+
description,
146+
) = self._instance_type
124147

125148
inst_description = description.format(cost=cost, inst_type=inst_type)
126149
product_name = "Amazon Elastic Compute Cloud"
@@ -137,7 +160,7 @@ def _update_data(self, row, start, end, **kwargs):
137160
row["lineItem/Operation"] = "RunInstances"
138161
row["lineItem/AvailabilityZone"] = avail_zone
139162
row["lineItem/ResourceId"] = self._resource_id
140-
row["lineItem/UsageAmount"] = "1"
163+
row["lineItem/UsageAmount"] = amount
141164
row["lineItem/UnblendedRate"] = rate
142165
row["lineItem/UnblendedCost"] = cost
143166
row["lineItem/BlendedRate"] = rate
@@ -175,13 +198,29 @@ def _update_data(self, row, start, end, **kwargs):
175198
row["pricing/term"] = "OnDemand"
176199
row["pricing/unit"] = "Hrs"
177200
row["savingsPlan/SavingsPlanEffectiveCost"] = saving
201+
row["savingsPlan/SavingsPlanRate"] = saving
178202

179203
# Overwrite lineItem/LineItemType for items with applied Savings plan
180204
if saving is not None:
181205
row["lineItem/LineItemType"] = "SavingsPlanCoveredUsage"
182206

183-
self._add_tag_data(row)
184-
self._add_category_data(row)
207+
if negation:
208+
row["lineItem/LineItemType"] = "SavingsPlanNegation"
209+
row["lineItem/UnblendedCost"] = -abs(cost)
210+
row["lineItem/UnblendedRate"] = -abs(rate)
211+
row["lineItem/BlendedCost"] = -abs(cost)
212+
row["lineItem/BlendedRate"] = -abs(rate)
213+
row[
214+
"lineItem/LineItemDescription"
215+
] = f"SavingsPlanNegation used by AccountId : {self.payer_account} and UsageSku : {self._product_sku}"
216+
row["lineItem/ResourceId"] = None
217+
row["savingsPlan/SavingsPlanEffectiveCost"] = None
218+
row["savingsPlan/SavingsPlanRate"] = None
219+
220+
else:
221+
self._add_tag_data(row)
222+
self._add_category_data(row)
223+
185224
return row
186225

187226
def generate_data(self, report_type=None):

Diff for: tests/test_aws_generator.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ def setUp(self):
209209
self.amount = 1
210210
self.rate = 0.1
211211
self.saving = 0.1
212+
self.disk_size = 10
212213
self.currency = "USD"
213214
self.legal_entity = "Red Hat"
214215
self.attributes = {
@@ -219,6 +220,7 @@ def setUp(self):
219220
"product_name": self.product_name,
220221
"resource_id": self.resource_id,
221222
"amount": self.amount,
223+
"disk_size": self.disk_size,
222224
"rate": self.rate,
223225
"saving": self.saving,
224226
"product_family": self.product_family,
@@ -327,6 +329,21 @@ def test_update_data(self):
327329
self.assertEqual(row["product/productFamily"], "Data Transfer")
328330
self.assertEqual(row[self.cost_category_key], self.cost_category_value)
329331

332+
def test_update_data_transfer_negation(self):
333+
"""Test DataTransfer specific update data with negation costs."""
334+
self.attributes = {
335+
"rate": 20,
336+
"amount": 1,
337+
"negation": True,
338+
}
339+
generator = DataTransferGenerator(
340+
self.two_hours_ago, self.now, self.currency, self.payer_account, self.usage_accounts, self.attributes
341+
)
342+
start_row = {}
343+
row = generator._update_data(start_row, self.two_hours_ago, self.now)
344+
345+
self.assertEqual(row["lineItem/LineItemType"], "SavingsPlanNegation")
346+
330347

331348
class TestEBSGenerator(AWSGeneratorTestCase):
332349
"""Tests for the EBS Generator type."""
@@ -339,7 +356,7 @@ def test_init_with_attributes(self):
339356
self.assertEqual(generator._product_sku, self.product_sku)
340357
self.assertEqual(generator._tags, self.tags)
341358
self.assertEqual(generator._resource_id, "vol-" + self.resource_id)
342-
self.assertEqual(generator._amount, self.amount)
359+
self.assertEqual(generator._disk_size, self.disk_size)
343360
self.assertEqual(generator._rate, self.rate)
344361

345362
def test_update_data(self):
@@ -377,6 +394,8 @@ def test_init_with_attributes(self):
377394
"cost": "1",
378395
"rate": "1",
379396
"saving": "1",
397+
"amount": 1,
398+
"negation": False,
380399
}
381400
self.attributes["instance_type"] = self.instance_type
382401

@@ -388,6 +407,18 @@ def test_init_with_attributes(self):
388407
self.assertEqual(generator._resource_id, "i-" + self.resource_id)
389408
self.assertEqual(generator._instance_type[:-1], tuple(self.instance_type.values()))
390409

410+
def test_update_data_ec2_negation(self):
411+
"""Test EC2 specific update data with negation costs."""
412+
self.instance_type = {"negation": True, "cost": 10, "rate": 1}
413+
self.attributes["instance_type"] = self.instance_type
414+
generator = EC2Generator(
415+
self.two_hours_ago, self.now, self.currency, self.payer_account, self.usage_accounts, self.attributes
416+
)
417+
start_row = {}
418+
row = generator._update_data(start_row, self.two_hours_ago, self.now)
419+
420+
self.assertEqual(row["lineItem/LineItemType"], "SavingsPlanNegation")
421+
391422
def test_update_data(self):
392423
"""Test EBS specific update data method."""
393424
generator = EC2Generator(

0 commit comments

Comments
 (0)