Repository: softlayer/softlayer-python
Pull request #1137 (2019-04-23 22:09:38)

Feature usage vs information
Feature usage vs information https://github.com/softlayer/softlayer-python/issues/1113.

**slcli virtual usage --help**
```
Options:
  -s, --start_date TEXT   Start Date e.g. 2019-3-4 (yyyy-MM-dd) [required]
  -e, --end_date TEXT     End Date e.g. 2019-4-2 (yyyy-MM-dd) [required]
  -t, --valid_typeTEXT   Metric_Data_Type keyName e.g. CPU0, CPU1, MEMORY_USAGE, etc. [required]
  -p, --summary_period   INTEGER  300, 600, 1800, 3600, 43200 or 86400 seconds
  -h, --help             Show this message and exit.
```
**slcli virtual usage -s 2019-04-04 -e 2019-04-23 -t CPU0 -p 1800 11111**
```
:....................:
:      Average       :
:....................:
: 0.6315241228070173 :
:....................:
:.........:..................:......:
: counter :     dateTime     : type :
:.........:..................:......:
:   0.37  : 2019-04-03 23:00 : cpu0 :
:   0.29  : 2019-04-03 23:30 : cpu0 :
:   0.28  : 2019-04-04 00:00 : cpu0 :
:   0.34  : 2019-04-04 00:30 : cpu0 :
:   0.36  : 2019-04-04 01:00 : cpu0 :
:   0.25  : 2019-04-04 01:30 : cpu0 :
:   0.44  : 2019-04-04 02:00 : cpu0 :
:   0.28  : 2019-04-04 02:30 : cpu0 :
:   0.34  : 2019-04-04 03:00 : cpu0 :
:   0.27  : 2019-04-04 03:30 : cpu0 :
:   0.31  : 2019-04-04 04:00 : cpu0 :
:   9.84  : 2019-04-04 04:30 : cpu0 :
:   0.27  : 2019-04-04 05:00 : cpu0 :
:   0.35  : 2019-04-04 05:30 : cpu0 :

```


Patch:
diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py
index 81ba4667..6736b233 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 00000000..ec970221
--- /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 00000000..6a0a031a
--- /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 c01fd17a..49433b01 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 00b738d0..073b8aea 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.


Test patch:
diff --git a/tests/CLI/modules/vs/vs_tests.py b/tests/CLI/modules/vs/vs_tests.py
index ce1bb9d7..7b03bb08 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 f13c3e7b..47674345 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)