Repository: softlayer/softlayer-python (python)

Issue:
Object Storage Account Listing
Provide a manager and CLI commands for listing/detailing object storage accounts. This should give enough information to be able to use other Object Storage tooling.

Pull request description:
Adds Object Storage account/endpoint listing manager/cli
Resolves #657.

Patch:
diff --git a/SoftLayer/CLI/core.py b/SoftLayer/CLI/core.py
index e8545aaf..e28525b3 100644
--- a/SoftLayer/CLI/core.py
+++ b/SoftLayer/CLI/core.py
@@ -63,7 +63,7 @@ def get_command(self, ctx, name):
         new_path.append(name)
         module = env.get_command(*new_path)
         if isinstance(module, types.ModuleType):
-            return CommandLoader(*new_path, help=module.__doc__)
+            return CommandLoader(*new_path, help=module.__doc__ or '')
         else:
             return module
 
diff --git a/SoftLayer/CLI/object_storage/__init__.py b/SoftLayer/CLI/object_storage/__init__.py
new file mode 100644
index 00000000..cb5e85af
--- /dev/null
+++ b/SoftLayer/CLI/object_storage/__init__.py
@@ -0,0 +1,1 @@
+"""Object Storage."""
diff --git a/SoftLayer/CLI/object_storage/list_accounts.py b/SoftLayer/CLI/object_storage/list_accounts.py
new file mode 100644
index 00000000..c86ca933
--- /dev/null
+++ b/SoftLayer/CLI/object_storage/list_accounts.py
@@ -0,0 +1,26 @@
+"""List Object Storage accounts."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+
+@click.command()
+@environment.pass_env
+def cli(env):
+    """List object storage accounts."""
+
+    mgr = SoftLayer.ObjectStorageManager(env.client)
+    accounts = mgr.list_accounts()
+    table = formatting.Table(['id', 'name'])
+    table.sortby = 'id'
+    for account in accounts:
+        table.add_row([
+            account['id'],
+            account['username'],
+        ])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/object_storage/list_endpoints.py b/SoftLayer/CLI/object_storage/list_endpoints.py
new file mode 100644
index 00000000..212f882c
--- /dev/null
+++ b/SoftLayer/CLI/object_storage/list_endpoints.py
@@ -0,0 +1,27 @@
+"""List Object Storage endpoints."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import formatting
+
+
+@click.command()
+@environment.pass_env
+def cli(env):
+    """List object storage endpoints."""
+
+    mgr = SoftLayer.ObjectStorageManager(env.client)
+    endpoints = mgr.list_endpoints()
+
+    table = formatting.Table(['datacenter', 'public', 'private'])
+    for endpoint in endpoints:
+        table.add_row([
+            endpoint['datacenter']['name'],
+            endpoint['public'],
+            endpoint['private'],
+        ])
+
+    env.fout(table)
diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py
index e75f5d2a..63e1fa42 100644
--- a/SoftLayer/CLI/routes.py
+++ b/SoftLayer/CLI/routes.py
@@ -128,6 +128,12 @@
     ('nas:list', 'SoftLayer.CLI.nas.list:cli'),
     ('nas:credentials', 'SoftLayer.CLI.nas.credentials:cli'),
 
+    ('object-storage', 'SoftLayer.CLI.object_storage'),
+    ('object-storage:accounts',
+     'SoftLayer.CLI.object_storage.list_accounts:cli'),
+    ('object-storage:endpoints',
+     'SoftLayer.CLI.object_storage.list_endpoints:cli'),
+
     ('rwhois', 'SoftLayer.CLI.rwhois'),
     ('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),
     ('rwhois:show', 'SoftLayer.CLI.rwhois.show:cli'),
diff --git a/SoftLayer/fixtures/SoftLayer_Account.py b/SoftLayer/fixtures/SoftLayer_Account.py
index 9e1a43da..19938777 100644
--- a/SoftLayer/fixtures/SoftLayer_Account.py
+++ b/SoftLayer/fixtures/SoftLayer_Account.py
@@ -494,3 +494,6 @@
 getBalance = 40
 
 getNextInvoiceTotalAmount = 2
+
+getHubNetworkStorage = [{'id': 12345, 'username': 'SLOS12345-1'},
+                        {'id': 12346, 'username': 'SLOS12345-2'}]
diff --git a/SoftLayer/managers/__init__.py b/SoftLayer/managers/__init__.py
index 7a81ccf0..ff8b040f 100644
--- a/SoftLayer/managers/__init__.py
+++ b/SoftLayer/managers/__init__.py
@@ -7,22 +7,22 @@
 
     :license: MIT, see LICENSE for more details.
 """
-# pylint: disable=w0401
-from SoftLayer.managers.cdn import CDNManager  # NOQA
-from SoftLayer.managers.dns import DNSManager  # NOQA
-from SoftLayer.managers.firewall import FirewallManager  # NOQA
-from SoftLayer.managers.hardware import HardwareManager  # NOQA
-from SoftLayer.managers.image import ImageManager  # NOQA
-from SoftLayer.managers.iscsi import ISCSIManager  # NOQA
-from SoftLayer.managers.load_balancer import LoadBalancerManager  # NOQA
-from SoftLayer.managers.messaging import MessagingManager  # NOQA
-from SoftLayer.managers.metadata import MetadataManager  # NOQA
-from SoftLayer.managers.network import NetworkManager  # NOQA
-from SoftLayer.managers.ordering import OrderingManager  # NOQA
-from SoftLayer.managers.sshkey import SshKeyManager  # NOQA
-from SoftLayer.managers.ssl import SSLManager  # NOQA
-from SoftLayer.managers.ticket import TicketManager  # NOQA
-from SoftLayer.managers.vs import VSManager  # NOQA
+from SoftLayer.managers.cdn import CDNManager
+from SoftLayer.managers.dns import DNSManager
+from SoftLayer.managers.firewall import FirewallManager
+from SoftLayer.managers.hardware import HardwareManager
+from SoftLayer.managers.image import ImageManager
+from SoftLayer.managers.iscsi import ISCSIManager
+from SoftLayer.managers.load_balancer import LoadBalancerManager
+from SoftLayer.managers.messaging import MessagingManager
+from SoftLayer.managers.metadata import MetadataManager
+from SoftLayer.managers.network import NetworkManager
+from SoftLayer.managers.object_storage import ObjectStorageManager
+from SoftLayer.managers.ordering import OrderingManager
+from SoftLayer.managers.sshkey import SshKeyManager
+from SoftLayer.managers.ssl import SSLManager
+from SoftLayer.managers.ticket import TicketManager
+from SoftLayer.managers.vs import VSManager
 
 __all__ = [
     'CDNManager',
@@ -35,6 +35,7 @@
     'MessagingManager',
     'MetadataManager',
     'NetworkManager',
+    'ObjectStorageManager',
     'OrderingManager',
     'SshKeyManager',
     'SSLManager',
diff --git a/SoftLayer/managers/object_storage.py b/SoftLayer/managers/object_storage.py
new file mode 100644
index 00000000..71da8d22
--- /dev/null
+++ b/SoftLayer/managers/object_storage.py
@@ -0,0 +1,49 @@
+"""
+    SoftLayer.object_storage
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+    Object Storage Manager/helpers
+
+    :license: MIT, see LICENSE for more details.
+"""
+
+LIST_ACCOUNTS_MASK = '''mask(SoftLayer_Network_Storage_Hub_Swift)[
+    id,username,notes
+]'''
+
+ENDPOINT_MASK = '''mask(SoftLayer_Network_Storage_Hub_Swift)[
+    id,storageNodes[id,backendIpAddress,frontendIpAddress,datacenter]
+]'''
+
+
+class ObjectStorageManager(object):
+    """Manager for Object Storage."""
+
+    def __init__(self, client):
+        self.client = client
+
+    def list_accounts(self):
+        """Lists your object storage accounts."""
+        _filter = {
+            'hubNetworkStorage': {'vendorName': {'operation': 'Swift'}},
+        }
+        return self.client.call('Account', 'getHubNetworkStorage',
+                                mask=LIST_ACCOUNTS_MASK,
+                                filter=_filter)
+
+    def list_endpoints(self):
+        """Lists the known object storage endpoints."""
+        _filter = {
+            'hubNetworkStorage': {'vendorName': {'operation': 'Swift'}},
+        }
+        endpoints = []
+        for node in self.client.call('Account', 'getHubNetworkStorage',
+                                     mask=ENDPOINT_MASK,
+                                     limit=1,
+                                     filter=_filter)['storageNodes']:
+            endpoints.append({
+                'datacenter': node['datacenter'],
+                'public': node['frontendIpAddress'],
+                'private': node['backendIpAddress'],
+            })
+
+        return endpoints


Test patch:
diff --git a/tests/CLI/modules/object_storage_tests.py b/tests/CLI/modules/object_storage_tests.py
new file mode 100644
index 00000000..0cc9eeb7
--- /dev/null
+++ b/tests/CLI/modules/object_storage_tests.py
@@ -0,0 +1,38 @@
+"""
+    SoftLayer.tests.CLI.modules.object_storage_tests
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    :license: MIT, see LICENSE for more details.
+"""
+import json
+
+from SoftLayer import testing
+
+
+class ObjectStorageTests(testing.TestCase):
+
+    def test_list_accounts(self):
+        result = self.run_command(['object-storage', 'accounts'])
+
+        self.assertEqual(result.exit_code, 0)
+        self.assertEqual(json.loads(result.output),
+                         [{'id': 12345, 'name': 'SLOS12345-1'},
+                          {'id': 12346, 'name': 'SLOS12345-2'}])
+
+    def test_list_endpoints(self):
+        accounts = self.set_mock('SoftLayer_Account', 'getHubNetworkStorage')
+        accounts.return_value = {
+            'storageNodes': [{
+                'datacenter': {'name': 'dal05'},
+                'frontendIpAddress': 'https://dal05/auth/v1.0/',
+                'backendIpAddress': 'https://dal05/auth/v1.0/'}
+            ],
+        }
+
+        result = self.run_command(['object-storage', 'endpoints'])
+
+        self.assertEqual(result.exit_code, 0)
+        self.assertEqual(json.loads(result.output),
+                         [{'datacenter': 'dal05',
+                           'private': 'https://dal05/auth/v1.0/',
+                           'public': 'https://dal05/auth/v1.0/'}])
diff --git a/tests/managers/object_storage_tests.py b/tests/managers/object_storage_tests.py
new file mode 100644
index 00000000..232c5772
--- /dev/null
+++ b/tests/managers/object_storage_tests.py
@@ -0,0 +1,35 @@
+"""
+    SoftLayer.tests.managers.object_storage_tests
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    :license: MIT, see LICENSE for more details.
+"""
+import SoftLayer
+from SoftLayer import fixtures
+from SoftLayer import testing
+
+
+class ObjectStorageTests(testing.TestCase):
+
+    def set_up(self):
+        self.object_storage = SoftLayer.ObjectStorageManager(self.client)
+
+    def test_list_accounts(self):
+        accounts = self.object_storage.list_accounts()
+        self.assertEquals(accounts,
+                          fixtures.SoftLayer_Account.getHubNetworkStorage)
+
+    def test_list_endpoints(self):
+        accounts = self.set_mock('SoftLayer_Account', 'getHubNetworkStorage')
+        accounts.return_value = {
+            'storageNodes': [{
+                'datacenter': {'name': 'dal05'},
+                'frontendIpAddress': 'https://dal05/auth/v1.0/',
+                'backendIpAddress': 'https://dal05/auth/v1.0/'}
+            ],
+        }
+        endpoints = self.object_storage.list_endpoints()
+        self.assertEquals(endpoints,
+                          [{'datacenter': {'name': 'dal05'},
+                            'private': 'https://dal05/auth/v1.0/',
+                            'public': 'https://dal05/auth/v1.0/'}])