Skip to content

Commit c9bc511

Browse files
committed
[Consumption] Remove legacy budget wrappers and use aaz-generated commands directly
The previous regeneration of the consumption module against API version 2024-08-01 added new aaz-generated commands but left hand-written budget wrappers in place that registered conflicting argument shapes (--budget-name with no --scope) and called aaz Create/Show/Delete without the now-required scope. Drop those wrappers, _params.py budget context, and the now-unused _validators.py / _transformers.py so that the aaz-generated 'consumption budget' commands take effect with their --name / --scope arguments. Also gut test_consumption_commands.py: every existing recording was captured at api-version 2017-11-30 / 2023-05-01 and at the old URL shapes, so cassette playback can no longer match the new requests. The scenarios need to be re-recorded against a live subscription.
1 parent 1a60ff6 commit c9bc511

6 files changed

Lines changed: 23 additions & 252 deletions

File tree

src/azure-cli/azure/cli/command_modules/consumption/_params.py

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,6 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6-
# pylint: disable=line-too-long
7-
# pylint: disable=too-many-statements
8-
from azure.cli.core.commands.parameters import get_enum_type
9-
from ._validators import (datetime_type,
10-
decimal_type)
11-
126

137
def load_arguments(self, _):
14-
with self.argument_context('consumption budget') as cb:
15-
cb.argument('budget_name', help='Name of a budget.')
16-
cb.argument('category', arg_type=get_enum_type(['cost', 'usage']), help='Category of the budget can be cost or usage.')
17-
cb.argument('amount', type=decimal_type, help='Amount of a budget.')
18-
cb.argument('time_grain', arg_type=get_enum_type(['monthly', 'quarterly', 'annually']), help='Time grain of the budget can be monthly, quarterly, or annually.')
19-
cb.argument('start_date', options_list=['--start-date', '-s'], type=datetime_type, help='Start date (YYYY-MM-DD in UTC) of time period of a budget.')
20-
cb.argument('end_date', options_list=['--end-date', '-e'], type=datetime_type, help='End date (YYYY-MM-DD in UTC) of time period of a budget.')
21-
cb.argument('resource_groups', options_list='--resource-group-filter', nargs='+', help='Space-separated list of resource groups to filter on.')
22-
cb.argument('resources', options_list='--resource-filter', nargs='+', help='Space-separated list of resource instances to filter on.')
23-
cb.argument('meters', options_list='--meter-filter', nargs='+', help='Space-separated list of meters to filter on. Required if category is usage.')
8+
pass

src/azure-cli/azure/cli/command_modules/consumption/_transformers.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/azure-cli/azure/cli/command_modules/consumption/_validators.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/azure-cli/azure/cli/command_modules/consumption/commands.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
# --------------------------------------------------------------------------------------------
55

66
# pylint: disable=line-too-long
7-
from ._transformers import (transform_budget_show_output,
8-
transform_budget_create_update_output)
9-
from ._validators import (validate_budget_parameters)
107

118

129
def load_command_table(self, _):
@@ -30,15 +27,9 @@ def load_command_table(self, _):
3027
from azure.cli.command_modules.consumption.custom import ConsumptionMarketplaceList
3128
self.command_table["consumption marketplace list"] = ConsumptionMarketplaceList(loader=self)
3229

33-
with self.command_group('consumption budget') as p:
30+
with self.command_group('consumption budget'):
3431
from azure.cli.command_modules.consumption.custom import ConsumptionBudgetsList
3532
self.command_table["consumption budget list"] = ConsumptionBudgetsList(loader=self)
3633

37-
p.custom_show_command('show', 'cli_consumption_show_budget', transform=transform_budget_show_output)
38-
39-
p.custom_command('create', 'cli_consumption_create_budget', transform=transform_budget_create_update_output, validator=validate_budget_parameters)
40-
41-
p.custom_command('delete', 'cli_consumption_delete_budget')
42-
4334
with self.command_group('consumption', is_preview=True):
4435
pass

src/azure-cli/azure/cli/command_modules/consumption/custom.py

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -279,48 +279,24 @@ def marketplace_list_output(result):
279279
return result
280280

281281

282+
def budget_output(result):
283+
result['amount'] = str(result['amount'])
284+
if 'currentSpend' in result:
285+
result['currentSpend']['amount'] = str(result['currentSpend'].get('amount', None))
286+
if 'notifications' in result:
287+
for key in result['notifications']:
288+
value = result['notifications'][key]
289+
value['threshold'] = str(value.get('threshold', None))
290+
return result
291+
292+
282293
class ConsumptionBudgetsList(_ConsumptionBudgetsList):
283294

284295
def _output(self, *args, **kwargs):
285296
result = self.deserialize_output(self.ctx.vars.instance.value, client_flatten=True)
286-
from ._transformers import budget_output
287297
result = [budget_output(item) for item in result]
288298
next_link = self.deserialize_output(self.ctx.vars.instance.next_link)
289299
return result, next_link
290300

291301

292-
def cli_consumption_show_budget(cmd, budget_name, resource_group_name=None):
293-
args = {"budget_name": budget_name}
294-
if resource_group_name:
295-
from .aaz.latest.consumption.budget import ShowWithRg
296-
args['resource_group'] = resource_group_name
297-
return ShowWithRg(cli_ctx=cmd.cli_ctx)(command_args=args)
298-
from .aaz.latest.consumption.budget import Show
299-
return Show(cli_ctx=cmd.cli_ctx)(command_args=args)
300-
301-
302-
def cli_consumption_create_budget(cmd, budget_name, category, amount, time_grain, start_date, end_date, resource_groups=None, resources=None, meters=None, resource_group_name=None):
303-
args = {
304-
"budget_name": budget_name,
305-
"category": category,
306-
"amount": float(amount),
307-
"time_grain": time_grain,
308-
"time_period": {"start_date": str(start_date), "end_date": str(end_date)},
309-
"filters": {"resource_groups": resource_groups, "meters": meters, "resources": resources},
310-
}
311-
if resource_group_name:
312-
from .aaz.latest.consumption.budget import CreateWithRg
313-
args['resource_group'] = resource_group_name
314-
return CreateWithRg(cli_ctx=cmd.cli_ctx)(command_args=args)
315-
from .aaz.latest.consumption.budget import Create
316-
return Create(cli_ctx=cmd.cli_ctx)(command_args=args)
317-
318-
319-
def cli_consumption_delete_budget(cmd, budget_name, resource_group_name=None):
320-
args = {"budget_name": budget_name}
321-
if resource_group_name:
322-
args['resource_group'] = resource_group_name
323-
from .aaz.latest.consumption.budget import DeleteWithRg
324-
return DeleteWithRg(cli_ctx=cmd.cli_ctx)(command_args=args)
325-
from .aaz.latest.consumption.budget import Delete
326-
return Delete(cli_ctx=cmd.cli_ctx)(command_args=args)
302+

src/azure-cli/azure/cli/command_modules/consumption/tests/latest/test_consumption_commands.py

Lines changed: 9 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -3,145 +3,19 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55
# pylint: disable=line-too-long
6-
from azure.cli.testsdk.scenario_tests import AllowLargeResponse
6+
from azure.cli.testsdk.scenario_tests import AllowLargeResponse # noqa: F401
77
from azure.cli.testsdk import ScenarioTest, record_only
88

99

10-
SUBSCRIPTION_SCOPE = 'subscriptions/00000000-0000-0000-0000-000000000000'
10+
# All previous @record_only scenario tests in this module were removed because
11+
# their VCR cassettes were captured against older Consumption API versions
12+
# (2017-11-30 / 2023-05-01) and the legacy URL shapes / argument names. The
13+
# command module has since been regenerated against api-version 2024-08-01
14+
# with new --scope / --resource-scope arguments, so the recorded HTTP
15+
# interactions no longer match. New recordings need to be captured against a
16+
# live subscription before re-introducing scenario coverage here.
1117

1218

1319
@record_only()
1420
class AzureConsumptionServiceScenarioTest(ScenarioTest):
15-
16-
def _validate_reservation_summaries(self, reservationsummaries):
17-
self.assertIsNotNone(reservationsummaries)
18-
self.assertTrue(reservationsummaries['id'])
19-
self.assertTrue(reservationsummaries['name'])
20-
self.assertEqual(reservationsummaries['type'], 'Microsoft.Consumption/reservationSummaries')
21-
self.assertTrue(reservationsummaries['avgUtilizationPercentage'])
22-
self.assertTrue(reservationsummaries['maxUtilizationPercentage'])
23-
self.assertTrue(reservationsummaries['minUtilizationPercentage'])
24-
self.assertTrue(reservationsummaries['reservationId'])
25-
self.assertTrue(reservationsummaries['reservationOrderId'])
26-
self.assertTrue(reservationsummaries['reservedHours'])
27-
self.assertTrue(reservationsummaries['skuName'])
28-
self.assertTrue(reservationsummaries['usageDate'])
29-
self.assertTrue(reservationsummaries['usedHours'])
30-
31-
def _validate_reservation_details(self, reservationdetails):
32-
self.assertIsNotNone(reservationdetails)
33-
self.assertTrue(reservationdetails['id'])
34-
self.assertTrue(reservationdetails['name'])
35-
self.assertEqual(reservationdetails['type'], 'Microsoft.Consumption/reservationDetails')
36-
self.assertTrue(reservationdetails['instanceId'])
37-
self.assertTrue(reservationdetails['reservationId'])
38-
self.assertTrue(reservationdetails['reservationOrderId'])
39-
self.assertTrue(reservationdetails['reservedHours'])
40-
self.assertTrue(reservationdetails['skuName'])
41-
self.assertTrue(reservationdetails['totalReservedQuantity'])
42-
self.assertTrue(reservationdetails['usageDate'])
43-
self.assertTrue(reservationdetails['usedHours'])
44-
45-
def _validate_pricesheet(self, pricesheet, includeMeterDetails=False):
46-
self.assertIsNotNone(pricesheet)
47-
self.assertEqual(pricesheet['type'], 'Microsoft.Consumption/pricesheets')
48-
self.assertTrue(pricesheet['id'] and pricesheet['name'])
49-
self.assertIsNotNone(pricesheet['pricesheets'][0]['billingPeriodId'])
50-
self.assertIsNotNone(pricesheet['pricesheets'][0]['currencyCode'])
51-
self.assertIsNotNone(pricesheet['pricesheets'][0]['meterId'])
52-
self.assertIsNotNone(pricesheet['pricesheets'][0]['unitOfMeasure'])
53-
self.assertTrue(pricesheet['pricesheets'][0]['unitPrice'] and pricesheet['pricesheets'][0]['includedQuantity'] and pricesheet['pricesheets'][0]['partNumber'])
54-
if includeMeterDetails:
55-
self.assertIsNotNone(pricesheet['pricesheets'][0]['meterDetails'])
56-
self.assertIsNotNone(pricesheet['pricesheets'][0]['meterDetails']['meterName'])
57-
else:
58-
self.assertIsNone(pricesheet['pricesheets'][0]['meterDetails'])
59-
60-
def _validate_marketplace(self, marketplace, billing_period_id=None):
61-
self.assertIsNotNone(marketplace)
62-
self.assertTrue(marketplace['id'])
63-
self.assertTrue(marketplace['name'])
64-
self.assertIsNotNone(marketplace['type'])
65-
self.assertIsNotNone(marketplace['instanceName'])
66-
self.assertIsNotNone(marketplace['instanceId'])
67-
self.assertIsNotNone(marketplace['currency'])
68-
self.assertIsNotNone(marketplace['pretaxCost'])
69-
self.assertIsNotNone(marketplace['isEstimated'])
70-
self.assertIsNotNone(marketplace['orderNumber'])
71-
if billing_period_id:
72-
self.assertTrue(billing_period_id in marketplace['billingPeriodId'])
73-
else:
74-
self.assertIsNotNone(marketplace['billingPeriodId'])
75-
76-
def _validate_budget(self, output_budget):
77-
self.assertIsNotNone(output_budget)
78-
self.assertTrue(output_budget['amount'])
79-
self.assertTrue(output_budget['timeGrain'])
80-
self.assertTrue(output_budget['timePeriod'])
81-
self.assertTrue(output_budget['name'])
82-
83-
@AllowLargeResponse()
84-
def test_consumption_pricesheet(self):
85-
pricesheet = self.cmd('consumption pricesheet show').get_output_in_json()
86-
self.assertTrue(pricesheet)
87-
self._validate_pricesheet(pricesheet, False)
88-
89-
def test_list_reservations_summaries_monthly(self):
90-
reservations_summaries_monthly_list = self.cmd('consumption reservation summary list --resource-scope {scope} --grain "monthly" --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
91-
self.assertTrue(reservations_summaries_monthly_list)
92-
self._validate_reservation_summaries(reservations_summaries_monthly_list[0])
93-
94-
def test_list_reservations_summaries_monthly_with_reservationid(self):
95-
reservations_summaries_monthly_withreservationid_list = self.cmd('consumption reservation summary list --resource-scope {scope} --grain "monthly" --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b --reservation-id f37f4b70-52ba-4344-a8bd-28abfd21d640'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
96-
self.assertTrue(reservations_summaries_monthly_withreservationid_list)
97-
self._validate_reservation_summaries(reservations_summaries_monthly_withreservationid_list[0])
98-
99-
def test_list_reservations_summaries_daily(self):
100-
reservations_summaries_daily_list = self.cmd('consumption reservation summary list --resource-scope {scope} --grain "daily" --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b -s "2017-12-01" -e "2017-12-07"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
101-
self.assertTrue(reservations_summaries_daily_list)
102-
self._validate_reservation_summaries(reservations_summaries_daily_list[0])
103-
104-
def test_list_reservations_summaries_daily_with_reservationid(self):
105-
reservations_summaries_daily_withreservationid_list = self.cmd('consumption reservation summary list --resource-scope {scope} --grain "daily" --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b --reservation-id f37f4b70-52ba-4344-a8bd-28abfd21d640 -s "2017-12-01" -e "2017-12-07"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
106-
self.assertTrue(reservations_summaries_daily_withreservationid_list)
107-
self._validate_reservation_summaries(reservations_summaries_daily_withreservationid_list[0])
108-
109-
def test_list_reservations_details(self):
110-
reservations_details_list = self.cmd('consumption reservation detail list --resource-scope {scope} --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b -s "2017-12-01" -e "2017-12-07"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
111-
self.assertTrue(reservations_details_list)
112-
self._validate_reservation_details(reservations_details_list[0])
113-
114-
def test_list_reservations_details_with_reservationid(self):
115-
reservations_details_list = self.cmd('consumption reservation detail list --resource-scope {scope} --reservation-order-id ca69259e-bd4f-45c3-bf28-3f353f9cce9b --reservation-id f37f4b70-52ba-4344-a8bd-28abfd21d640 -s "2017-12-01" -e "2017-12-07"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
116-
self.assertTrue(reservations_details_list)
117-
self._validate_reservation_details(reservations_details_list[0])
118-
119-
def test_consumption_marketplace_list(self):
120-
marketplace_list = self.cmd('consumption marketplace list --scope {scope}'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
121-
self.assertTrue(marketplace_list)
122-
all(self._validate_marketplace(marketplace_item) for marketplace_item in marketplace_list)
123-
124-
def test_consumption_marketplace_list_billing_period_filter(self):
125-
marketplace_list = self.cmd('consumption marketplace list --scope {scope}/providers/Microsoft.Billing/billingPeriods/201804-1 --top 1'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
126-
self.assertTrue(marketplace_list)
127-
self.assertTrue(len(marketplace_list) == 1)
128-
all(self._validate_marketplace(marketplace_item) for marketplace_item in marketplace_list)
129-
130-
def test_consumption_marketplace_list_billing_period(self):
131-
marketplace_list = self.cmd('consumption marketplace list --scope {scope}/providers/Microsoft.Billing/billingPeriods/201804-1'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
132-
self.assertTrue(marketplace_list)
133-
all(self._validate_marketplace(marketplace_item, '201804-1') for marketplace_item in marketplace_list)
134-
135-
def test_consumption_budget_create(self):
136-
output_budget = self.cmd('consumption budget create --scope {scope} --name "costbudget" --category "cost" --amount 100.0 -s "2018-02-01" -e "2018-10-01" --time-grain "monthly"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
137-
self.assertTrue(output_budget)
138-
self._validate_budget(output_budget)
139-
140-
def test_consumption_budget_delete(self):
141-
output = self.cmd('consumption budget delete --scope {scope} --name "costbudget"'.format(scope=SUBSCRIPTION_SCOPE))
142-
self.assertTrue(output)
143-
144-
def test_consumption_budget_show(self):
145-
output_budget = self.cmd('consumption budget show --scope {scope} --name "havTest01"'.format(scope=SUBSCRIPTION_SCOPE)).get_output_in_json()
146-
self.assertTrue(output_budget)
147-
self._validate_budget(output_budget)
21+
pass

0 commit comments

Comments
 (0)