diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py index 81ba46672..6736b233b 100644 --- a/SoftLayer/CLI/routes.py +++ b/SoftLayer/CLI/routes.py @@ -36,6 +36,7 @@ ('virtual:reboot', 'SoftLayer.CLI.virt.power:reboot'), ('virtual:reload', 'SoftLayer.CLI.virt.reload:cli'), ('virtual:upgrade', 'SoftLayer.CLI.virt.upgrade:cli'), + ('virtual:usage', 'SoftLayer.CLI.virt.usage:cli'), ('virtual:credentials', 'SoftLayer.CLI.virt.credentials:cli'), ('virtual:capacity', 'SoftLayer.CLI.virt.capacity:cli'), ('virtual:placementgroup', 'SoftLayer.CLI.virt.placementgroup:cli'), diff --git a/SoftLayer/CLI/virt/usage.py b/SoftLayer/CLI/virt/usage.py new file mode 100644 index 000000000..ec9702216 --- /dev/null +++ b/SoftLayer/CLI/virt/usage.py @@ -0,0 +1,59 @@ +"""Usage information of a virtual server.""" +# :license: MIT, see LICENSE for more details. + +import click + +import SoftLayer +from SoftLayer.CLI import environment +from SoftLayer.CLI import exceptions +from SoftLayer.CLI import formatting +from SoftLayer.CLI import helpers +from SoftLayer.utils import clean_time + + +@click.command() +@click.argument('identifier') +@click.option('--start_date', '-s', type=click.STRING, required=True, help="Start Date e.g. 2019-3-4 (yyyy-MM-dd)") +@click.option('--end_date', '-e', type=click.STRING, required=True, help="End Date e.g. 2019-4-2 (yyyy-MM-dd)") +@click.option('--valid_type', '-t', type=click.STRING, required=True, + help="Metric_Data_Type keyName e.g. CPU0, CPU1, MEMORY_USAGE, etc.") +@click.option('--summary_period', '-p', type=click.INT, default=1800, + help="300, 600, 1800, 3600, 43200 or 86400 seconds") +@environment.pass_env +def cli(env, identifier, start_date, end_date, valid_type, summary_period): + """Usage information of a virtual server.""" + + vsi = SoftLayer.VSManager(env.client) + table = formatting.Table(['counter', 'dateTime', 'type']) + table_average = formatting.Table(['Average']) + + vs_id = helpers.resolve_id(vsi.resolve_ids, identifier, 'VS') + + result = vsi.get_summary_data_usage(vs_id, start_date=start_date, end_date=end_date, + valid_type=valid_type, summary_period=summary_period) + + if len(result) == 0: + raise exceptions.CLIAbort('No metric data for this range of dates provided') + + count = 0 + counter = 0.00 + for data in result: + if valid_type == "MEMORY_USAGE": + usage_counter = data['counter'] / 2 ** 30 + else: + usage_counter = data['counter'] + + table.add_row([ + round(usage_counter, 2), + clean_time(data['dateTime']), + data['type'], + ]) + counter = counter + usage_counter + count = count + 1 + + average = counter / count + + env.fout(table_average.add_row([round(average, 2)])) + + env.fout(table_average) + env.fout(table) diff --git a/SoftLayer/fixtures/SoftLayer_Metric_Tracking_Object.py b/SoftLayer/fixtures/SoftLayer_Metric_Tracking_Object.py new file mode 100644 index 000000000..6a0a031a2 --- /dev/null +++ b/SoftLayer/fixtures/SoftLayer_Metric_Tracking_Object.py @@ -0,0 +1,12 @@ +getSummaryData = [ + { + "counter": 1.44, + "dateTime": "2019-03-04T00:00:00-06:00", + "type": "cpu0" + }, + { + "counter": 1.53, + "dateTime": "2019-03-04T00:05:00-06:00", + "type": "cpu0" + }, +] diff --git a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py index c01fd17a8..49433b01f 100644 --- a/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py +++ b/SoftLayer/fixtures/SoftLayer_Virtual_Guest.py @@ -626,3 +626,5 @@ } }, ] + +getMetricTrackingObjectId = 1000 diff --git a/SoftLayer/managers/vs.py b/SoftLayer/managers/vs.py index 00b738d0c..073b8aeab 100644 --- a/SoftLayer/managers/vs.py +++ b/SoftLayer/managers/vs.py @@ -1002,6 +1002,27 @@ def _get_price_id_for_upgrade_option(self, upgrade_prices, option, value, public else: return price.get('id') + def get_summary_data_usage(self, instance_id, start_date=None, end_date=None, valid_type=None, summary_period=None): + """Retrieve the usage information of a virtual server. + + :param string instance_id: a string identifier used to resolve ids + :param string start_date: the start data to retrieve the vs usage information + :param string end_date: the start data to retrieve the vs usage information + :param string string valid_type: the Metric_Data_Type keyName. + :param int summary_period: summary period. + """ + valid_types = [ + { + "keyName": valid_type, + "summaryType": "max" + } + ] + + metric_tracking_id = self.guest.getMetricTrackingObjectId(id=instance_id) + + return self.client.call('Metric_Tracking_Object', 'getSummaryData', start_date, end_date, valid_types, + summary_period, id=metric_tracking_id, iter=True) + # pylint: disable=inconsistent-return-statements def _get_price_id_for_upgrade(self, package_items, option, value, public=True): """Find the price id for the option and value to upgrade. diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py index ce1bb9d73..7b03bb084 100644 --- a/tests/CLI/modules/vs/vs_tests.py +++ b/tests/CLI/modules/vs/vs_tests.py @@ -660,3 +660,39 @@ def test_vs_capture(self): result = self.run_command(['vs', 'capture', '100', '--name', 'TestName']) self.assert_no_fail(result) self.assert_called_with('SoftLayer_Virtual_Guest', 'createArchiveTransaction', identifier=100) + + @mock.patch('SoftLayer.CLI.formatting.no_going_back') + def test_usage_no_confirm(self, confirm_mock): + confirm_mock.return_value = False + + result = self.run_command(['vs', 'usage', '100']) + self.assertEqual(result.exit_code, 2) + + def test_usage_vs(self): + result = self.run_command( + ['vs', 'usage', '100']) + self.assertEqual(result.exit_code, 2) + + def test_usage_vs_cpu(self): + result = self.run_command( + ['vs', 'usage', '100', '--start_date=2019-3-4', '--end_date=2019-4-2', '--valid_type=CPU0', + '--summary_period=300']) + + self.assert_no_fail(result) + + def test_usage_vs_memory(self): + result = self.run_command( + ['vs', 'usage', '100', '--start_date=2019-3-4', '--end_date=2019-4-2', '--valid_type=MEMORY_USAGE', + '--summary_period=300']) + + self.assert_no_fail(result) + + def test_usage_metric_data_empty(self): + usage_vs = self.set_mock('SoftLayer_Metric_Tracking_Object', 'getSummaryData') + test_usage = [] + usage_vs.return_value = test_usage + result = self.run_command( + ['vs', 'usage', '100', '--start_date=2019-3-4', '--end_date=2019-4-2', '--valid_type=CPU0', + '--summary_period=300']) + self.assertEqual(result.exit_code, 2) + self.assertIsInstance(result.exception, exceptions.CLIAbort) diff --git a/tests/managers/vs/vs_tests.py b/tests/managers/vs/vs_tests.py index f13c3e7b9..47674345f 100644 --- a/tests/managers/vs/vs_tests.py +++ b/tests/managers/vs/vs_tests.py @@ -830,3 +830,31 @@ def test_capture_additional_disks(self): 'createArchiveTransaction', args=args, identifier=1) + + def test_usage_vs_cpu(self): + result = self.vs.get_summary_data_usage('100', + start_date='2019-3-4', + end_date='2019-4-2', + valid_type='CPU0', + summary_period=300) + + expected = fixtures.SoftLayer_Metric_Tracking_Object.getSummaryData + self.assertEqual(result, expected) + + args = ('2019-3-4', '2019-4-2', [{"keyName": "CPU0", "summaryType": "max"}], 300) + + self.assert_called_with('SoftLayer_Metric_Tracking_Object', 'getSummaryData', args=args, identifier=1000) + + def test_usage_vs_memory(self): + result = self.vs.get_summary_data_usage('100', + start_date='2019-3-4', + end_date='2019-4-2', + valid_type='MEMORY_USAGE', + summary_period=300) + + expected = fixtures.SoftLayer_Metric_Tracking_Object.getSummaryData + self.assertEqual(result, expected) + + args = ('2019-3-4', '2019-4-2', [{"keyName": "MEMORY_USAGE", "summaryType": "max"}], 300) + + self.assert_called_with('SoftLayer_Metric_Tracking_Object', 'getSummaryData', args=args, identifier=1000)