Repository: softlayer/softlayer-python
Pull request #742 (2016-07-23 19:10:59)

Block storage host auth
Pulled forward the 4.1.0 branch from @iodine53 and cleaned up a few things. Adds ability to give and revoke access to block volumes, per https://github.com/softlayer/softlayer-python/issues/731

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7133039/badge)](https://coveralls.io/builds/7133039)

Coverage decreased (-0.3%) to 79.541% when pulling **f0032e9105e2ce55e3f04078303a8eed97b9cf5d on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7133081/badge)](https://coveralls.io/builds/7133081)

Coverage decreased (-0.3%) to 79.544% when pulling **003765cf5855581c488db0452cc6685b7f781322 on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7133239/badge)](https://coveralls.io/builds/7133239)

Coverage decreased (-0.3%) to 79.544% when pulling **c9588b728a24eeda7b65deba0387cd04db37ab7a on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7174314/badge)](https://coveralls.io/builds/7174314)

Coverage decreased (-0.3%) to 79.544% when pulling **df0c12f92f3e6288947f3bbda2039ee9526f49a0 on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

vmtyler: Ok got those fixes in. Fixed the dashes in the authorize CLI as well a the revoke CLI.
coveralls: 
[![Coverage Status](https://coveralls.io/builds/7174380/badge)](https://coveralls.io/builds/7174380)

Coverage decreased (-0.3%) to 79.544% when pulling **b85640448a1dfd7ff078bb830b3652b93fe12dd5 on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7174422/badge)](https://coveralls.io/builds/7174422)

Coverage decreased (-0.3%) to 79.544% when pulling **b85640448a1dfd7ff078bb830b3652b93fe12dd5 on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7174514/badge)](https://coveralls.io/builds/7174514)

Coverage decreased (-0.3%) to 79.544% when pulling **3fac2abd35e268c4cf483c5a8a5296b5f9f99e64 on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/7174689/badge)](https://coveralls.io/builds/7174689)

Coverage decreased (-0.3%) to 79.544% when pulling **c195477006eba7c0eccaa0af9a2fa847628915fa on vmtyler:block-storage-host-auth** into **4be0789d219066c25ec75d78a1db8dc908ffe23c on softlayer:master**.


Patch:
diff --git a/SoftLayer/CLI/block/access/__init__.py b/SoftLayer/CLI/block/access/__init__.py
new file mode 100644
index 00000000..050b3938
--- /dev/null
+++ b/SoftLayer/CLI/block/access/__init__.py
@@ -0,0 +1,1 @@
+"""Block Storage Access Control."""
diff --git a/SoftLayer/CLI/block/access/authorize.py b/SoftLayer/CLI/block/access/authorize.py
new file mode 100644
index 00000000..4e9dc20f
--- /dev/null
+++ b/SoftLayer/CLI/block/access/authorize.py
@@ -0,0 +1,42 @@
+"""Create a block storage snapshot."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+from SoftLayer.CLI import exceptions
+
+
+@click.command()
+@click.argument('volume_id')
+@click.option('--hardware-id', '-h', multiple=True,
+              help='The id of one SoftLayer_Hardware to authorize')
+@click.option('--virtual-id', '-v', multiple=True,
+              help='The id of one SoftLayer_Virtual_Guest to authorize')
+@click.option('--ip-address-id', '-i', multiple=True,
+              help='The id of one SoftLayer_Network_Subnet_IpAddress'
+              ' to authorize')
+@click.option('--ip-address', multiple=True,
+              help='An IP address to authorize')
+@environment.pass_env
+def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address):
+    """Authorizes hosts to access a given volume"""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    ip_address_id_list = list(ip_address_id)
+
+    # Convert actual IP Addresses to their SoftLayer ids
+    if ip_address is not None:
+        network_manager = SoftLayer.NetworkManager(env.client)
+        for ip_address_value in ip_address:
+            ip_address_object = network_manager.ip_lookup(ip_address_value)
+            if ip_address_object == "":
+                click.echo("IP Address not found on your account.  " +
+                           "Please confirm IP and try again.")
+                raise exceptions.ArgumentError('Incorrect IP Address')
+            else:
+                ip_address_id_list.append(ip_address_object['id'])
+
+    block_manager.authorize_host_to_volume(volume_id,
+                                           hardware_id,
+                                           virtual_id,
+                                           ip_address_id_list)
diff --git a/SoftLayer/CLI/block/access/revoke.py b/SoftLayer/CLI/block/access/revoke.py
new file mode 100644
index 00000000..1b0c93a4
--- /dev/null
+++ b/SoftLayer/CLI/block/access/revoke.py
@@ -0,0 +1,38 @@
+"""Create a block storage snapshot."""
+# :license: MIT, see LICENSE for more details.
+
+import click
+import SoftLayer
+from SoftLayer.CLI import environment
+
+
+@click.command()
+@click.argument('volume_id')
+@click.option('--hardware-id', '-h', multiple=True,
+              help='The id of one SoftLayer_Hardware'
+              ' to revoke authorization')
+@click.option('--virtual-id', '-v', multiple=True,
+              help='The id of one SoftLayer_Virtual_Guest'
+              ' to revoke authorization')
+@click.option('--ip_address-id', '-i', multiple=True,
+              help='The id of one SoftLayer_Network_Subnet_IpAddress'
+              ' to revoke authorization')
+@click.option('--ip-address', multiple=True,
+              help='An IP address to revoke authorization')
+@environment.pass_env
+def cli(env, volume_id, hardware_id, virtual_id, ip_address_id, ip_address):
+    """Revokes authorization for hosts accessing a given volume"""
+    block_manager = SoftLayer.BlockStorageManager(env.client)
+    ip_address_id_list = list(ip_address_id)
+
+    # Convert actual IP Addresses to their SoftLayer ids
+    if ip_address is not None:
+        network_manager = SoftLayer.NetworkManager(env.client)
+        for ip_address_value in ip_address:
+            ip_address_object = network_manager.ip_lookup(ip_address_value)
+            ip_address_id_list.append(ip_address_object['id'])
+
+    block_manager.deauthorize_host_to_volume(volume_id,
+                                             hardware_id,
+                                             virtual_id,
+                                             ip_address_id_list)
diff --git a/SoftLayer/CLI/routes.py b/SoftLayer/CLI/routes.py
index a9aec3c9..3446ef12 100644
--- a/SoftLayer/CLI/routes.py
+++ b/SoftLayer/CLI/routes.py
@@ -61,9 +61,13 @@
     ('block:volume-detail', 'SoftLayer.CLI.block.detail:cli'),
     ('block:volume-cancel', 'SoftLayer.CLI.block.cancel:cli'),
     ('block:volume-order', 'SoftLayer.CLI.block.order:cli'),
+
     ('block:snapshot-list', 'SoftLayer.CLI.block.snapshot_list:cli'),
     ('block:snapshot-delete', 'SoftLayer.CLI.block.snapshot_delete:cli'),
+
     ('block:access-list', 'SoftLayer.CLI.block.access_list:cli'),
+    ('block:access-authorize', 'SoftLayer.CLI.block.access.authorize:cli'),
+    ('block:access-revoke', 'SoftLayer.CLI.block.access.revoke:cli'),
 
     ('firewall', 'SoftLayer.CLI.firewall'),
     ('firewall:add', 'SoftLayer.CLI.firewall.add:cli'),
diff --git a/SoftLayer/fixtures/SoftLayer_Network_Storage.py b/SoftLayer/fixtures/SoftLayer_Network_Storage.py
index 0257b167..5a45f14f 100644
--- a/SoftLayer/fixtures/SoftLayer_Network_Storage.py
+++ b/SoftLayer/fixtures/SoftLayer_Network_Storage.py
@@ -63,3 +63,5 @@
 }
 getSnapshots = []
 deleteObject = True
+allowAccessFromHostList = True
+removeAccessFromHostList = True
diff --git a/SoftLayer/managers/block.py b/SoftLayer/managers/block.py
index 906496ee..26040321 100644
--- a/SoftLayer/managers/block.py
+++ b/SoftLayer/managers/block.py
@@ -135,6 +135,80 @@ def get_block_volume_snapshot_list(self, volume_id, **kwargs):
         return self.client.call('Network_Storage', 'getSnapshots',
                                 id=volume_id, **kwargs)
 
+    def authorize_host_to_volume(self, volume_id,
+                                 hardware_ids=None,
+                                 virtual_guest_ids=None,
+                                 ip_address_ids=None):
+        """Authorizes hosts to Block Storage Volumes
+
+        :param volume_id: The Volume to authorize hosts to
+        :param hardware_ids: A List of SoftLayer_Hardware ids
+        :param virtual_guest_ids: A List of SoftLayer_Virtual_Guest ids
+        :param ip_address_ids: A List of SoftLayer_Network_Subnet_IpAddress ids
+        """
+        host_templates = []
+
+        if hardware_ids is not None:
+            for hardware_id in hardware_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Hardware',
+                    'id': hardware_id
+                })
+
+        if virtual_guest_ids is not None:
+            for virtual_guest_id in virtual_guest_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Virtual_Guest',
+                    'id': virtual_guest_id
+                })
+
+        if ip_address_ids is not None:
+            for ip_address_id in ip_address_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Network_Subnet_IpAddress',
+                    'id': ip_address_id
+                })
+
+        return self.client.call('Network_Storage', 'allowAccessFromHostList',
+                                host_templates, id=volume_id)
+
+    def deauthorize_host_to_volume(self, volume_id,
+                                   hardware_ids=None,
+                                   virtual_guest_ids=None,
+                                   ip_address_ids=None):
+        """Revokes authorization of hosts to Block Storage Volumes
+
+        :param volume_id: The Volume to deauthorize hosts to
+        :param hardware_ids: A List of SoftLayer_Hardware ids
+        :param virtual_guest_ids: A List of SoftLayer_Virtual_Guest ids
+        :param ip_address_ids: A List of SoftLayer_Network_Subnet_IpAddress ids
+        """
+        host_templates = []
+
+        if hardware_ids is not None:
+            for hardware_id in hardware_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Hardware',
+                    'id': hardware_id
+                })
+
+        if virtual_guest_ids is not None:
+            for virtual_guest_id in virtual_guest_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Virtual_Guest',
+                    'id': virtual_guest_id
+                })
+
+        if ip_address_ids is not None:
+            for ip_address_id in ip_address_ids:
+                host_templates.append({
+                    'objectType': 'SoftLayer_Network_Subnet_IpAddress',
+                    'id': ip_address_id
+                })
+
+        return self.client.call('Network_Storage', 'removeAccessFromHostList',
+                                host_templates, id=volume_id)
+
     def delete_snapshot(self, snapshot_id):
         """Deletes the specified snapshot object.
 


Test patch:
diff --git a/tests/managers/block_tests.py b/tests/managers/block_tests.py
index a6b6f866..e278cf32 100644
--- a/tests/managers/block_tests.py
+++ b/tests/managers/block_tests.py
@@ -210,3 +210,19 @@ def test_order_block_volume_endurance(self):
                     'setupFee': '1'}],
                 },
             )
+
+    def test_authorize_host_to_volume(self):
+        result = self.block.authorize_host_to_volume(50,
+                                                     hardware_ids=[100],
+                                                     virtual_guest_ids=[200],
+                                                     ip_address_ids=[300])
+        self.assertEqual(fixtures.SoftLayer_Network_Storage.
+                         allowAccessFromHostList, result)
+
+    def test_deauthorize_host_to_volume(self):
+        result = self.block.authorize_host_to_volume(50,
+                                                     hardware_ids=[100],
+                                                     virtual_guest_ids=[200],
+                                                     ip_address_ids=[300])
+        self.assertEqual(fixtures.SoftLayer_Network_Storage.
+                         removeAccessFromHostList, result)