-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add new command budget to consumption #6024
Changes from 10 commits
32dada6
7ec8e0c
d473a14
8f476d6
3237ae9
ee09a4d
ee51703
89c6bb8
f90fc2d
2d892eb
85d4dc4
5869ff5
3b282ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,33 +4,47 @@ | |
# -------------------------------------------------------------------------------------------- | ||
|
||
# pylint: disable=line-too-long | ||
from ._validators import get_datetime_type | ||
# pylint: disable=too-many-statements | ||
from azure.cli.core.commands.parameters import get_enum_type | ||
from ._validators import (datetime_type, | ||
decimal_type) | ||
|
||
|
||
def load_arguments(self, _): | ||
with self.argument_context('consumption usage') as c: | ||
c.argument('top', options_list=['--top', '-t'], type=int, help='Maximum number of items to return. Value range: 1-1000.') | ||
c.argument('include_additional_properties', options_list=['--include-additional-properties', '-a'], action='store_true', help='Include additional properties in the usages.') | ||
c.argument('include_meter_details', options_list=['--include-meter-details', '-m'], action='store_true', help='Include meter details in the usages.') | ||
c.argument('start_date', options_list=['--start-date', '-s'], type=get_datetime_type(), help='Start date (YYYY-MM-DD in UTC). If specified, also requires --end-date.') | ||
c.argument('end_date', options_list=['--end-date', '-e'], type=get_datetime_type(), help='End date (YYYY-MM-DD in UTC). If specified, also requires --start-date.') | ||
c.argument('start_date', options_list=['--start-date', '-s'], type=datetime_type, help='Start date (YYYY-MM-DD in UTC). If specified, also requires --end-date.') | ||
c.argument('end_date', options_list=['--end-date', '-e'], type=datetime_type, help='End date (YYYY-MM-DD in UTC). If specified, also requires --start-date.') | ||
c.argument('billing_period_name', options_list=['--billing-period-name', '-p'], help='Name of the billing period to get the usage details that associate with.') | ||
|
||
with self.argument_context('consumption reservation') as rs: | ||
rs.argument('reservation_order_id', options_list='--reservation-order-id', help='Reservation order id.') | ||
rs.argument('start_date', options_list=['--start-date', '-s'], type=get_datetime_type(), help='Start date (YYYY-MM-DD in UTC). Only needed for daily grain and if specified, also requires --end-date.') | ||
rs.argument('end_date', options_list=['--end-date', '-e'], type=get_datetime_type(), help='End date (YYYY-MM-DD in UTC). Only needed for daily grain and if specified, also requires --start-date.') | ||
rs.argument('reservation_id', options_list='--reservation-id', help='Reservation id.') | ||
rs.argument('reservation_order_id', help='Reservation order id.') | ||
rs.argument('start_date', options_list=['--start-date', '-s'], type=datetime_type, help='Start date (YYYY-MM-DD in UTC). Only needed for daily grain and if specified, also requires --end-date.') | ||
rs.argument('end_date', options_list=['--end-date', '-e'], type=datetime_type, help='End date (YYYY-MM-DD in UTC). Only needed for daily grain and if specified, also requires --start-date.') | ||
rs.argument('reservation_id', help='Reservation id.') | ||
|
||
with self.argument_context('consumption reservation summary list') as rs: | ||
rs.argument('grain', options_list='--grain', type=str, help='Reservation summary grain. Possible values are daily or monthly.') | ||
rs.argument('grain', help='Reservation summary grain. Possible values are daily or monthly.') | ||
|
||
with self.argument_context('consumption pricesheet show') as cps: | ||
cps.argument('include_meter_details', options_list='--include-meter-details', action='store_true', help='Include meter details in the price sheet.') | ||
cps.argument('include_meter_details', action='store_true', help='Include meter details in the price sheet.') | ||
cps.argument('billing_period_name', options_list=['--billing-period-name', '-p'], help='Name of the billing period to get the price sheet.') | ||
|
||
with self.argument_context('consumption marketplace list') as cmp: | ||
cmp.argument('billing_period_name', options_list=['--billing-period-name', '-p'], help='Name of the billing period to get the marketplace.') | ||
cmp.argument('top', options_list=['--top', '-t'], type=int, help='Maximum number of items to return. Value range: 1-1000.') | ||
cmp.argument('start_date', options_list=['--start-date', '-s'], type=get_datetime_type(), help='Start date (YYYY-MM-DD in UTC). If specified, also requires --end-date.') | ||
cmp.argument('end_date', options_list=['--end-date', '-e'], type=get_datetime_type(), help='End date (YYYY-MM-DD in UTC). If specified, also requires --start-date.') | ||
cmp.argument('start_date', options_list=['--start-date', '-s'], type=datetime_type, help='Start date (YYYY-MM-DD in UTC). If specified, also requires --end-date.') | ||
cmp.argument('end_date', options_list=['--end-date', '-e'], type=datetime_type, help='End date (YYYY-MM-DD in UTC). If specified, also requires --start-date.') | ||
|
||
with self.argument_context('consumption budget') as cb: | ||
cb.argument('budget_name', help='Name of a budget.') | ||
cb.argument('category', arg_type=get_enum_type(['cost', 'usage']), help='Category of the budget can be cost or usage.') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are these enums not in your SDK? |
||
cb.argument('amount', type=decimal_type, help='Amount of a budget.') | ||
cb.argument('time_grain', arg_type=get_enum_type(['monthly', 'quarterly', 'annually']), help='Time grain of the budget can be monthly, quarterly, or annually.') | ||
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.') | ||
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.') | ||
cb.argument('resource_groups', options_list='--resource-group-filter', nargs='+', help='Space-separated list of resource groups to filter on.') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is fine, but you should still add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
cb.argument('resources', options_list='--resource-filter', nargs='+', help='Space-separated list of resource instances to filter on.') | ||
cb.argument('meters', options_list='--meter-filter', nargs='+', help='Space-separated list of meters to filter on. Required if category is usage.') |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,24 +4,27 @@ | |
# -------------------------------------------------------------------------------------------- | ||
|
||
from datetime import datetime | ||
from decimal import Decimal | ||
from azure.cli.core.util import CLIError | ||
|
||
|
||
def get_datetime_type(): | ||
def datetime_type(string): | ||
""" Validates UTC datetime. Examples of accepted forms: | ||
2017-12-31T01:11:59Z,2017-12-31T01:11Z or 2017-12-31T01Z or 2017-12-31 """ | ||
def datetime_type(string): | ||
""" Validates UTC datetime. Examples of accepted forms: | ||
2017-12-31T01:11:59Z,2017-12-31T01:11Z or 2017-12-31T01Z or 2017-12-31 """ | ||
accepted_date_formats = ['%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%dT%H:%MZ', | ||
'%Y-%m-%dT%HZ', '%Y-%m-%d'] | ||
for form in accepted_date_formats: | ||
try: | ||
return datetime.strptime(string, form) | ||
except ValueError: | ||
continue | ||
raise ValueError("Input '{}' not valid. Valid example: 2017-02-11T23:59:59Z".format(string)) | ||
return datetime_type | ||
accepted_date_formats = ['%Y-%m-%dT%H:%M:%SZ', '%Y-%m-%dT%H:%MZ', '%Y-%m-%dT%HZ', '%Y-%m-%d'] | ||
for form in accepted_date_formats: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Try the version and core. If you feel it doesn't support you scenarios, let me know so I can improve it. |
||
try: | ||
return datetime.strptime(string, form) | ||
except ValueError: | ||
continue | ||
raise ValueError("Input '{}' not valid. Valid example: 2017-02-11T23:59:59Z".format(string)) | ||
|
||
|
||
def decimal_type(string): | ||
try: | ||
return Decimal(string) | ||
except ValueError: | ||
raise ValueError("the value passed cannot be converted to decimal") | ||
|
||
|
||
def validate_both_start_end_dates(namespace): | ||
|
@@ -37,3 +40,15 @@ def validate_reservation_summary(namespace): | |
raise CLIError("usage error: --grain can be either daily or monthly.") | ||
if data_grain == 'daily' and (not namespace.start_date or not namespace.end_date): | ||
raise CLIError("usage error: Both --start-date and --end-date need to be supplied for daily grain.") | ||
|
||
|
||
def validate_budget_parameters(namespace): | ||
"""lowercase the time grain for comparison""" | ||
budgetcategory = namespace.category.lower() | ||
if budgetcategory != 'cost' and budgetcategory != 'usage': | ||
raise CLIError("usage error: --category must be set to either cost or usage") | ||
time_grain = namespace.time_grain.lower().strip() | ||
if time_grain != 'annually' and time_grain != 'quarterly' and time_grain != 'monthly': | ||
raise CLIError("usage error: --time_grain can be 'Annually', 'Quarterly', or 'Monthly'.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These enums should not be validated in code at all. That's why you register them as enums. The CLI handles all of that. Validating the amount is fine though. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removed validation on category and time grain |
||
if namespace.amount < 0: | ||
raise CLIError("usage error: --amount must be greater than 0") |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
interactions: | ||
- request: | ||
body: '{"properties": {"category": "cost", "amount": 100.0, "timeGrain": "monthly", | ||
"timePeriod": {"startDate": "2018-02-01T00:00:00.000Z", "endDate": "2018-10-01T00:00:00.000Z"}}}' | ||
headers: | ||
Accept: [application/json] | ||
Accept-Encoding: ['gzip, deflate'] | ||
CommandName: [consumption budget create] | ||
Connection: [keep-alive] | ||
Content-Length: ['173'] | ||
Content-Type: [application/json; charset=utf-8] | ||
User-Agent: [python/3.6.4 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.26 | ||
msrest_azure/0.4.21 azure-mgmt-consumption/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.28] | ||
accept-language: [en-US] | ||
method: PUT | ||
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/costbudget?api-version=2018-01-31 | ||
response: | ||
body: {string: '{"id":"subscriptions/0f88eb23-845d-48b9-b363-efd011b05586/providers/Microsoft.Consumption/budgets/costbudget","name":"costbudget","type":"Microsoft.Consumption/budgets","eTag":"\"1d3ab6019183d09\"","properties":{"timePeriod":{"startDate":"2018-02-01T00:00:00Z","endDate":"2018-10-01T00:00:00Z"},"timeGrain":"Monthly","amount":100.0,"currentSpend":null,"category":"Cost","notifications":{},"filters":{"resourceGroups":[],"resources":[],"meters":[]}}}'} | ||
headers: | ||
cache-control: [no-cache] | ||
content-length: ['449'] | ||
content-type: [application/json; charset=utf-8] | ||
date: ['Wed, 21 Feb 2018 22:05:32 GMT'] | ||
expires: ['-1'] | ||
location: ['https://consumption.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/costbudget?api-version=2018-01-31'] | ||
pragma: [no-cache] | ||
server: [Microsoft-IIS/8.5] | ||
session-id: [5215920e-8606-48f6-b900-5b2a5d59794a] | ||
strict-transport-security: [max-age=31536000; includeSubDomains] | ||
x-content-type-options: [nosniff] | ||
x-ms-ratelimit-remaining-subscription-writes: ['1199'] | ||
x-powered-by: [ASP.NET] | ||
status: {code: 201, message: Created} | ||
version: 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
interactions: | ||
- request: | ||
body: null | ||
headers: | ||
Accept: [application/json] | ||
Accept-Encoding: ['gzip, deflate'] | ||
CommandName: [consumption budget delete] | ||
Connection: [keep-alive] | ||
Content-Length: ['0'] | ||
Content-Type: [application/json; charset=utf-8] | ||
User-Agent: [python/3.6.4 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.26 | ||
msrest_azure/0.4.21 azure-mgmt-consumption/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.28] | ||
accept-language: [en-US] | ||
method: DELETE | ||
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/costbudget?api-version=2018-01-31 | ||
response: | ||
body: {string: ''} | ||
headers: | ||
cache-control: [no-cache] | ||
content-length: ['0'] | ||
date: ['Thu, 22 Feb 2018 00:11:03 GMT'] | ||
expires: ['-1'] | ||
pragma: [no-cache] | ||
server: [Microsoft-IIS/8.5] | ||
session-id: [2fb4175b-6646-45a5-8595-b324cd07818a] | ||
strict-transport-security: [max-age=31536000; includeSubDomains] | ||
x-content-type-options: [nosniff] | ||
x-ms-ratelimit-remaining-subscription-writes: ['1199'] | ||
x-powered-by: [ASP.NET] | ||
status: {code: 200, message: OK} | ||
version: 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
interactions: | ||
- request: | ||
body: '{"properties": {"category": "usage", "amount": 20.0, "timeGrain": "annually", | ||
"timePeriod": {"startDate": "2018-02-01T00:00:00.000Z", "endDate": "2018-10-01T00:00:00.000Z"}, | ||
"filters": {"meters": ["0dfadad2-6e4f-4078-85e1-90c230d4d482"]}}}' | ||
headers: | ||
Accept: [application/json] | ||
Accept-Encoding: ['gzip, deflate'] | ||
CommandName: [consumption budget create] | ||
Connection: [keep-alive] | ||
Content-Length: ['239'] | ||
Content-Type: [application/json; charset=utf-8] | ||
User-Agent: [python/3.6.4 (Windows-10-10.0.16299-SP0) requests/2.18.4 msrest/0.4.26 | ||
msrest_azure/0.4.21 azure-mgmt-consumption/2.0.0 Azure-SDK-For-Python AZURECLI/2.0.28] | ||
accept-language: [en-US] | ||
method: PUT | ||
uri: https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/usagetypebudget1?api-version=2018-01-31 | ||
response: | ||
body: {string: '{"id":"subscriptions/0f88eb23-845d-48b9-b363-efd011b05586/providers/Microsoft.Consumption/budgets/usagetypebudget1","name":"usagetypebudget1","type":"Microsoft.Consumption/budgets","eTag":"\"1d3ab875141ad02\"","properties":{"timePeriod":{"startDate":"2018-02-01T00:00:00Z","endDate":"2018-10-01T00:00:00Z"},"timeGrain":"Annually","amount":20.0,"currentSpend":null,"category":"Usage","notifications":{},"filters":{"resourceGroups":[],"resources":[],"meters":["0dfadad2-6e4f-4078-85e1-90c230d4d482"]}}}'} | ||
headers: | ||
cache-control: [no-cache] | ||
content-length: ['500'] | ||
content-type: [application/json; charset=utf-8] | ||
date: ['Thu, 22 Feb 2018 02:46:20 GMT'] | ||
expires: ['-1'] | ||
location: ['https://consumption.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Consumption/budgets/usagetypebudget1?api-version=2018-01-31'] | ||
pragma: [no-cache] | ||
server: [Microsoft-IIS/8.5] | ||
session-id: [3268b230-5476-48b4-9e87-07f73dee71d7] | ||
strict-transport-security: [max-age=31536000; includeSubDomains] | ||
x-content-type-options: [nosniff] | ||
x-ms-ratelimit-remaining-subscription-writes: ['1199'] | ||
x-powered-by: [ASP.NET] | ||
status: {code: 201, message: Created} | ||
version: 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using the
get_datetime_type
method fromazure.cli.core.commands.parameters
. They are methods because you have to parameterize, but the intention will be to standardize date handling using these configurable methods. Try it on one command and let me know whether it fits your scenario.