From cbe7c98a3927e9b598ad51dcf64680aaad40718d Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Tue, 31 Mar 2020 20:09:33 -0400 Subject: [PATCH 1/6] implement the new feature hw billing and vs billing --- SoftLayer/CLI/hardware/billing.py | 38 +++++++++++++++++++++ SoftLayer/CLI/virt/billing.py | 38 +++++++++++++++++++++ tests/CLI/modules/server_tests.py | 55 +++++++++++++++++++++---------- tests/CLI/modules/vs/vs_tests.py | 52 +++++++++++++++++++---------- 4 files changed, 147 insertions(+), 36 deletions(-) create mode 100644 SoftLayer/CLI/hardware/billing.py create mode 100644 SoftLayer/CLI/virt/billing.py diff --git a/SoftLayer/CLI/hardware/billing.py b/SoftLayer/CLI/hardware/billing.py new file mode 100644 index 000000000..2131f999c --- /dev/null +++ b/SoftLayer/CLI/hardware/billing.py @@ -0,0 +1,38 @@ +"""Get billing for a hardware device.""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import formatting +from SoftLayer.CLI import helpers +from SoftLayer import utils + + +@click.command() +@click.argument('identifier') +@environment.pass_env +def cli(env, identifier): + """Get billing for a hardware device.""" + hardware = SoftLayer.HardwareManager(env.client) + + hardware_id = helpers.resolve_id(hardware.resolve_ids, identifier, 'hardware') + result = hardware.get_hardware(hardware_id) + table = formatting.KeyValueTable(['name', 'value']) + table.align['name'] = 'r' + table.align['value'] = 'l' + + table.add_row(['hardwareId', identifier]) + + table.add_row(['BillingIttem', utils.lookup(result, 'billingItem', 'id')]) + table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) + table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) + table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) + + price_table = formatting.Table(['Item', 'Recurring Price']) + for item in utils.lookup(result, 'billingItem', 'children') or []: + price_table.add_row([item['description'], item['nextInvoiceTotalRecurringAmount']]) + + table.add_row(['prices', price_table]) + env.fout(table) diff --git a/SoftLayer/CLI/virt/billing.py b/SoftLayer/CLI/virt/billing.py new file mode 100644 index 000000000..500692d26 --- /dev/null +++ b/SoftLayer/CLI/virt/billing.py @@ -0,0 +1,38 @@ +"""Get billing for a virtual device.""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import formatting +from SoftLayer.CLI import helpers +from SoftLayer import utils + + +@click.command() +@click.argument('identifier') +@environment.pass_env +def cli(env, identifier): + """Get billing for a virtual device.""" + virtual = SoftLayer.VSManager(env.client) + + virtual_id = helpers.resolve_id(virtual.resolve_ids, identifier, 'virtual') + result = virtual.get_instance(virtual_id) + table = formatting.KeyValueTable(['name', 'value']) + table.align['name'] = 'r' + table.align['value'] = 'l' + + table.add_row(['VirtuallId', identifier]) + + table.add_row(['BillingIttem', utils.lookup(result, 'billingItem', 'id')]) + table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) + table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) + table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) + + price_table = formatting.Table(['Recurring Price']) + for item in utils.lookup(result, 'billingItem', 'children') or []: + price_table.add_row([item['nextInvoiceTotalRecurringAmount']]) + + table.add_row(['prices', price_table]) + env.fout(table) diff --git a/tests/CLI/modules/server_tests.py b/tests/CLI/modules/server_tests.py index 14f8e9201..16af3a235 100644 --- a/tests/CLI/modules/server_tests.py +++ b/tests/CLI/modules/server_tests.py @@ -659,19 +659,19 @@ def test_dns_sync_both(self, confirm_mock): 'getResourceRecords') getResourceRecords.return_value = [] createAargs = ({ - 'type': 'a', - 'host': 'hardware-test1', - 'domainId': 12345, # from SoftLayer_Account::getDomains - 'data': '172.16.1.100', - 'ttl': 7200 - },) + 'type': 'a', + 'host': 'hardware-test1', + 'domainId': 12345, # from SoftLayer_Account::getDomains + 'data': '172.16.1.100', + 'ttl': 7200 + },) createPTRargs = ({ - 'type': 'ptr', - 'host': '100', - 'domainId': 123456, - 'data': 'hardware-test1.test.sftlyr.ws', - 'ttl': 7200 - },) + 'type': 'ptr', + 'host': '100', + 'domainId': 123456, + 'data': 'hardware-test1.test.sftlyr.ws', + 'ttl': 7200 + },) result = self.run_command(['hw', 'dns-sync', '1000']) @@ -714,12 +714,12 @@ def test_dns_sync_v6(self, confirm_mock): } } createV6args = ({ - 'type': 'aaaa', - 'host': 'hardware-test1', - 'domainId': 12345, # from SoftLayer_Account::getDomains - 'data': '2607:f0d0:1b01:0023:0000:0000:0000:0004', - 'ttl': 7200 - },) + 'type': 'aaaa', + 'host': 'hardware-test1', + 'domainId': 12345, # from SoftLayer_Account::getDomains + 'data': '2607:f0d0:1b01:0023:0000:0000:0000:0004', + 'ttl': 7200 + },) server.return_value = test_server result = self.run_command(['hw', 'dns-sync', '--aaaa-record', '1000']) self.assert_no_fail(result) @@ -826,3 +826,22 @@ def test_dns_sync_misc_exception(self, confirm_mock): result = self.run_command(['hw', 'dns-sync', '-a', '1000']) self.assertEqual(result.exit_code, 2) self.assertIsInstance(result.exception, exceptions.CLIAbort) + + def test_billing(self): + result = self.run_command(['hw', 'billing', '123456']) + billing_json = { + "hardwareId": "123456", + "BillingIttem": 6327, + "recurringFee": 1.54, + "Total": 16.08, + "provisionDate": None, + "prices": [ + { + "Item": "test", + "Recurring Price": 1 + } + ] + } + + self.assert_no_fail(result) + self.assertEqual(json.loads(result.output), billing_json) diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py index 2c79f42bf..e82bf4e87 100644 --- a/tests/CLI/modules/vs/vs_tests.py +++ b/tests/CLI/modules/vs/vs_tests.py @@ -320,19 +320,19 @@ def test_dns_sync_both(self, confirm_mock): 'getResourceRecords') getResourceRecords.return_value = [] createAargs = ({ - 'type': 'a', - 'host': 'vs-test1', - 'domainId': 12345, # from SoftLayer_Account::getDomains - 'data': '172.16.240.2', - 'ttl': 7200 - },) + 'type': 'a', + 'host': 'vs-test1', + 'domainId': 12345, # from SoftLayer_Account::getDomains + 'data': '172.16.240.2', + 'ttl': 7200 + },) createPTRargs = ({ - 'type': 'ptr', - 'host': '2', - 'domainId': 123456, - 'data': 'vs-test1.test.sftlyr.ws', - 'ttl': 7200 - },) + 'type': 'ptr', + 'host': '2', + 'domainId': 123456, + 'data': 'vs-test1.test.sftlyr.ws', + 'ttl': 7200 + },) result = self.run_command(['vs', 'dns-sync', '100']) @@ -375,12 +375,12 @@ def test_dns_sync_v6(self, confirm_mock): } } createV6args = ({ - 'type': 'aaaa', - 'host': 'vs-test1', - 'domainId': 12345, - 'data': '2607:f0d0:1b01:0023:0000:0000:0000:0004', - 'ttl': 7200 - },) + 'type': 'aaaa', + 'host': 'vs-test1', + 'domainId': 12345, + 'data': '2607:f0d0:1b01:0023:0000:0000:0000:0004', + 'ttl': 7200 + },) guest.return_value = test_guest result = self.run_command(['vs', 'dns-sync', '--aaaa-record', '100']) self.assert_no_fail(result) @@ -740,3 +740,19 @@ def test_bandwidth_vs_quite(self): self.assertEqual(output_summary[1]['Max Date'], date) self.assertEqual(output_summary[2]['Max GB'], 0.1172) self.assertEqual(output_summary[3]['Sum GB'], 0.0009) + + def test_billing(self): + result = self.run_command(['vs', 'billing', '123456']) + vir_billing = { + "BillingIttem": 6327, + "Total": 1.54, + "VirtuallId": "123456", + "prices": [{"Recurring Price": 1}, + {"Recurring Price": 1}, + {"Recurring Price": 1}, + {"Recurring Price": 1}, + {"Recurring Price": 1}], + "provisionDate": None, + "recurringFee": None} + self.assert_no_fail(result) + self.assertEqual(json.loads(result.output), vir_billing) From 0d69281a756f257935ad187f977e28d3ec9ec911 Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Wed, 1 Apr 2020 08:34:03 -0400 Subject: [PATCH 2/6] add the routes file --- SoftLayer/CLI/routes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index f6edee475..b68fd8e4a 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -20,6 +20,7 @@ ('virtual', 'SoftLayer.CLI.virt'), ('virtual:bandwidth', 'SoftLayer.CLI.virt.bandwidth:cli'), + ('virtual:billing', 'SoftLayer.CLI.virt.billing:cli'), ('virtual:cancel', 'SoftLayer.CLI.virt.cancel:cli'), ('virtual:capture', 'SoftLayer.CLI.virt.capture:cli'), ('virtual:create', 'SoftLayer.CLI.virt.create:cli'), @@ -163,7 +164,6 @@ ('image:list', 'SoftLayer.CLI.image.list:cli'), ('image:import', 'SoftLayer.CLI.image.import:cli'), ('image:export', 'SoftLayer.CLI.image.export:cli'), - ('image:datacenter', 'SoftLayer.CLI.image.datacenter:cli'), ('ipsec', 'SoftLayer.CLI.vpn.ipsec'), ('ipsec:configure', 'SoftLayer.CLI.vpn.ipsec.configure:cli'), @@ -231,6 +231,7 @@ ('hardware:create', 'SoftLayer.CLI.hardware.create:cli'), ('hardware:create-options', 'SoftLayer.CLI.hardware.create_options:cli'), ('hardware:detail', 'SoftLayer.CLI.hardware.detail:cli'), + ('hardware:billing', 'SoftLayer.CLI.hardware.billing:cli'), ('hardware:edit', 'SoftLayer.CLI.hardware.edit:cli'), ('hardware:list', 'SoftLayer.CLI.hardware.list:cli'), ('hardware:power-cycle', 'SoftLayer.CLI.hardware.power:power_cycle'), From 845760df58f39ca10232bd85902b83db8d1ed158 Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Thu, 2 Apr 2020 15:40:29 -0400 Subject: [PATCH 3/6] fix Christopher code review --- SoftLayer/CLI/hardware/billing.py | 4 ++-- SoftLayer/CLI/routes.py | 1 + SoftLayer/CLI/virt/billing.py | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/SoftLayer/CLI/hardware/billing.py b/SoftLayer/CLI/hardware/billing.py index 2131f999c..f1b1a8501 100644 --- a/SoftLayer/CLI/hardware/billing.py +++ b/SoftLayer/CLI/hardware/billing.py @@ -23,9 +23,9 @@ def cli(env, identifier): table.align['name'] = 'r' table.align['value'] = 'l' - table.add_row(['hardwareId', identifier]) + table.add_row(['Id', identifier]) - table.add_row(['BillingIttem', utils.lookup(result, 'billingItem', 'id')]) + table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')]) table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index b68fd8e4a..d7e6334c8 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -164,6 +164,7 @@ ('image:list', 'SoftLayer.CLI.image.list:cli'), ('image:import', 'SoftLayer.CLI.image.import:cli'), ('image:export', 'SoftLayer.CLI.image.export:cli'), + ('image:datacenter', 'SoftLayer.CLI.image.datacenter:cli'), ('ipsec', 'SoftLayer.CLI.vpn.ipsec'), ('ipsec:configure', 'SoftLayer.CLI.vpn.ipsec.configure:cli'), diff --git a/SoftLayer/CLI/virt/billing.py b/SoftLayer/CLI/virt/billing.py index 500692d26..872f708a0 100644 --- a/SoftLayer/CLI/virt/billing.py +++ b/SoftLayer/CLI/virt/billing.py @@ -23,9 +23,9 @@ def cli(env, identifier): table.align['name'] = 'r' table.align['value'] = 'l' - table.add_row(['VirtuallId', identifier]) + table.add_row(['Id', identifier]) - table.add_row(['BillingIttem', utils.lookup(result, 'billingItem', 'id')]) + table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')]) table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) From ff42108a6a8841353c0839da51ea5c9bab1c376c Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Thu, 2 Apr 2020 16:12:12 -0400 Subject: [PATCH 4/6] fix Christopher code review --- SoftLayer/CLI/hardware/billing.py | 6 +++--- SoftLayer/CLI/virt/billing.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SoftLayer/CLI/hardware/billing.py b/SoftLayer/CLI/hardware/billing.py index f1b1a8501..03b32e7f6 100644 --- a/SoftLayer/CLI/hardware/billing.py +++ b/SoftLayer/CLI/hardware/billing.py @@ -26,13 +26,13 @@ def cli(env, identifier): table.add_row(['Id', identifier]) table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')]) - table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) + table.add_row(['Recurring Fee', utils.lookup(result, 'billingItem', 'recurringFee')]) table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) - table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) + table.add_row(['Provision Date', utils.lookup(result, 'billingItem', 'provisionDate')]) price_table = formatting.Table(['Item', 'Recurring Price']) for item in utils.lookup(result, 'billingItem', 'children') or []: - price_table.add_row([item['description'], item['nextInvoiceTotalRecurringAmount']]) + price_table.add_row([item['Description'], item['NextInvoiceTotalRecurringAmount']]) table.add_row(['prices', price_table]) env.fout(table) diff --git a/SoftLayer/CLI/virt/billing.py b/SoftLayer/CLI/virt/billing.py index 872f708a0..7312de8d8 100644 --- a/SoftLayer/CLI/virt/billing.py +++ b/SoftLayer/CLI/virt/billing.py @@ -26,9 +26,9 @@ def cli(env, identifier): table.add_row(['Id', identifier]) table.add_row(['Billing Item Id', utils.lookup(result, 'billingItem', 'id')]) - table.add_row(['recurringFee', utils.lookup(result, 'billingItem', 'recurringFee')]) + table.add_row(['Recurring Fee', utils.lookup(result, 'billingItem', 'recurringFee')]) table.add_row(['Total', utils.lookup(result, 'billingItem', 'nextInvoiceTotalRecurringAmount')]) - table.add_row(['provisionDate', utils.lookup(result, 'billingItem', 'provisionDate')]) + table.add_row(['Provision Date', utils.lookup(result, 'billingItem', 'provisionDate')]) price_table = formatting.Table(['Recurring Price']) for item in utils.lookup(result, 'billingItem', 'children') or []: From 2b0ffd9101f4aa771aba88b187ac5a8512a28739 Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Tue, 7 Apr 2020 16:26:08 -0400 Subject: [PATCH 5/6] add command docs/cli --- docs/cli/hardware.rst | 4 ++++ docs/cli/vs.rst | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/docs/cli/hardware.rst b/docs/cli/hardware.rst index 3cd899d4a..4fd245e22 100644 --- a/docs/cli/hardware.rst +++ b/docs/cli/hardware.rst @@ -36,6 +36,10 @@ Provides some basic functionality to order a server. `slcli order` has a more fu :prog: hw detail :show-nested: +.. click:: SoftLayer.CLI.hardware.billing:cli + :prog: hw billing + :show-nested: + .. click:: SoftLayer.CLI.hardware.edit:cli :prog: hw edit diff --git a/docs/cli/vs.rst b/docs/cli/vs.rst index afa0f8b2d..75db769a8 100644 --- a/docs/cli/vs.rst +++ b/docs/cli/vs.rst @@ -245,6 +245,10 @@ If no timezone is specified, IMS local time (CST) will be assumed, which might n :prog: vs usage :show-nested: +.. click:: SoftLayer.CLI.virt.billing:cli + :prog: vs billing + :show-nested: + From 16ad4e0972a7c5cc25778d4ee19366dd5a112bee Mon Sep 17 00:00:00 2001 From: Daniel Cabero Barrios Date: Wed, 8 Apr 2020 16:15:44 -0400 Subject: [PATCH 6/6] fix the problems with tox --- SoftLayer/CLI/hardware/billing.py | 2 +- tests/CLI/modules/server_tests.py | 21 +++++++++------------ tests/CLI/modules/vs/vs_tests.py | 23 +++++++++++++---------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/SoftLayer/CLI/hardware/billing.py b/SoftLayer/CLI/hardware/billing.py index 03b32e7f6..55c68c485 100644 --- a/SoftLayer/CLI/hardware/billing.py +++ b/SoftLayer/CLI/hardware/billing.py @@ -32,7 +32,7 @@ def cli(env, identifier): price_table = formatting.Table(['Item', 'Recurring Price']) for item in utils.lookup(result, 'billingItem', 'children') or []: - price_table.add_row([item['Description'], item['NextInvoiceTotalRecurringAmount']]) + price_table.add_row([item['description'], item['nextInvoiceTotalRecurringAmount']]) table.add_row(['prices', price_table]) env.fout(table) diff --git a/tests/CLI/modules/server_tests.py b/tests/CLI/modules/server_tests.py index 16af3a235..588ed4d1e 100644 --- a/tests/CLI/modules/server_tests.py +++ b/tests/CLI/modules/server_tests.py @@ -830,18 +830,15 @@ def test_dns_sync_misc_exception(self, confirm_mock): def test_billing(self): result = self.run_command(['hw', 'billing', '123456']) billing_json = { - "hardwareId": "123456", - "BillingIttem": 6327, - "recurringFee": 1.54, - "Total": 16.08, - "provisionDate": None, - "prices": [ - { - "Item": "test", - "Recurring Price": 1 - } - ] + 'Billing Item Id': 6327, + 'Id': '123456', + 'Provision Date': None, + 'Recurring Fee': 1.54, + 'Total': 16.08, + 'prices': [{ + 'Item': 'test', + 'Recurring Price': 1 + }] } - self.assert_no_fail(result) self.assertEqual(json.loads(result.output), billing_json) diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py index e82bf4e87..9fbe699c2 100644 --- a/tests/CLI/modules/vs/vs_tests.py +++ b/tests/CLI/modules/vs/vs_tests.py @@ -744,15 +744,18 @@ def test_bandwidth_vs_quite(self): def test_billing(self): result = self.run_command(['vs', 'billing', '123456']) vir_billing = { - "BillingIttem": 6327, - "Total": 1.54, - "VirtuallId": "123456", - "prices": [{"Recurring Price": 1}, - {"Recurring Price": 1}, - {"Recurring Price": 1}, - {"Recurring Price": 1}, - {"Recurring Price": 1}], - "provisionDate": None, - "recurringFee": None} + 'Billing Item Id': 6327, + 'Id': '123456', + 'Provision Date': None, + 'Recurring Fee': None, + 'Total': 1.54, + 'prices': [ + {'Recurring Price': 1}, + {'Recurring Price': 1}, + {'Recurring Price': 1}, + {'Recurring Price': 1}, + {'Recurring Price': 1} + ] + } self.assert_no_fail(result) self.assertEqual(json.loads(result.output), vir_billing)