From 234205bf538489dfc9c42858b104224170259278 Mon Sep 17 00:00:00 2001
From: Gaurav Gupta <gaurav@denali-systems.com>
Date: Thu, 29 Sep 2011 08:09:50 -0700
Subject: [PATCH 1/2] Added the following CLI commands to access nova volumes: 
    volume-attach       Attach a volume to a server.     volume-create      
 Add a new volume.     volume-delete       Remove a volume.     volume-detach 
      Detach a volume from a server.     volume-list         List all the
 volumes.     volume-show         Show details about a volume.

---
 README.rst                |  6 +++
 novaclient/v1_1/client.py |  2 +
 novaclient/v1_1/shell.py  | 88 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+)

diff --git a/README.rst b/README.rst
index 1916a79b8..7955d326a 100644
--- a/README.rst
+++ b/README.rst
@@ -106,6 +106,12 @@ You'll find complete documentation on the shell by running
         root-password       Change the root password for a server.
         show                Show details about the given server.
         unrescue            Unrescue a server.
+        volume-attach       Attach a volume to a server.
+        volume-create       Add a new volume.
+        volume-delete       Remove a volume.
+        volume-detach       Detach a volume from a server.
+        volume-list         List all the volumes.
+        volume-show         Show details about a volume.
         zone                Show or edit a Child Zone
         zone-add            Add a Child Zone.
         zone-boot           Boot a server, considering Zones.
diff --git a/novaclient/v1_1/client.py b/novaclient/v1_1/client.py
index 81118c6c6..a46d6bbb8 100644
--- a/novaclient/v1_1/client.py
+++ b/novaclient/v1_1/client.py
@@ -7,6 +7,7 @@ from novaclient.v1_1 import security_group_rules
 from novaclient.v1_1 import security_groups
 from novaclient.v1_1 import servers
 from novaclient.v1_1 import quotas
+from novaclient.v1_1 import volumes
 from novaclient.v1_1 import zones
 
 
@@ -36,6 +37,7 @@ class Client(object):
         self.servers = servers.ServerManager(self)
 
         # extensions
+        self.volumes = volumes.VolumeManager(self)
         self.keypairs = keypairs.KeypairManager(self)
         self.zones = zones.ZoneManager(self)
         self.quotas = quotas.QuotaSetManager(self)
diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py
index 6b83292e5..7575ac6fb 100644
--- a/novaclient/v1_1/shell.py
+++ b/novaclient/v1_1/shell.py
@@ -703,3 +703,91 @@ def do_remove_fixed_ip(cs, args):
     """Remove an IP address from a server."""
     server = _find_server(cs, args.server)
     server.remove_fixed_ip(args.address)
+
+
+def _find_volume(cs, volume):
+    """Get a volume by ID."""
+    return utils.find_resource(cs.volumes, volume)
+
+
+def _print_volume(cs, volume):
+    utils.print_dict(volume._info)
+
+
+def _translate_volume_keys(collection):
+    convert = [('displayName', 'display_name')]
+    for item in collection:
+        keys = item.__dict__.keys()
+        for from_key, to_key in convert:
+            if from_key in keys and to_key not in keys:
+                setattr(item, to_key, item._info[from_key])
+
+
+def do_volume_list(cs, args):
+    """List all the volumes."""
+    volumes = cs.volumes.list()
+    _translate_volume_keys(volumes)
+
+    # Create a list of servers to which the volume is attached
+    for vol in volumes:
+        servers = [server.get('serverId') for server in vol.attachments]
+        setattr(vol, 'attached_to', ','.join(map(str, servers)))
+    utils.print_list(volumes, ['ID', 'Status', 'Display Name',
+                        'Size', 'Attached to'])
+
+
+@utils.arg('volume', metavar='<volume>', help='ID of the volume.')
+def do_volume_show(cs, args):
+    """Show details about a volume."""
+    volume = _find_volume(cs, args.volume)
+    _print_volume(cs, volume)
+
+
+@utils.arg('size',
+    metavar='<size>',
+    type=int,
+    help='Size of volume in GB')
+@utils.arg('--display_name', metavar='<display_name>',
+            help='Optional volume name. (Default=None)',
+            default=None)
+@utils.arg('--display_description', metavar='<display_description>',
+            help='Optional volume description. (Default=None)',
+            default=None)
+def do_volume_create(cs, args):
+    """Add a new volume."""
+    cs.volumes.create(args.size, args.display_name, args.display_description)
+
+
+@utils.arg('volume', metavar='<volume>', help='ID of the volume to delete.')
+def do_volume_delete(cs, args):
+    """Remove a volume."""
+    volume = _find_volume(cs, args.volume)
+    volume.delete()
+
+
+@utils.arg('server',
+    metavar='<server>',
+    type=int,
+    help='Name or ID of server.')
+@utils.arg('volume',
+    metavar='<volume>',
+    type=int,
+    help='ID of the volume to attach.')
+@utils.arg('device', metavar='<device>',
+    help='Name of the device e.g. /dev/vdb.')
+def do_volume_attach(cs, args):
+    """Attach a volume to a server."""
+    cs.volumes.create_server_volume(args.server, args.volume, args.device)
+
+
+@utils.arg('server',
+    metavar='<server>',
+    type=int,
+    help='Name or ID of server.')
+@utils.arg('attachment_id',
+    metavar='<volume>',
+    type=int,
+    help='Attachment ID of the volume.')
+def do_volume_detach(cs, args):
+    """Detach a volume from a server."""
+    cs.volumes.delete_server_volume(args.server, args.attachment_id)

From cd9f3cb47e7fc02e843867cac7bd8c309ebb24f5 Mon Sep 17 00:00:00 2001
From: Gaurav Gupta <gaurav@denali-systems.com>
Date: Sun, 16 Oct 2011 15:21:53 -0700
Subject: [PATCH 2/2] Updated volume attach/detach commands to accept server
 name (in addition to server id).     Code review comments:    
 https://github.com/rackspace/python-novaclient/pull/125/files#r169829

---
 novaclient/v1_1/shell.py | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py
index 7575ac6fb..075a56ee6 100644
--- a/novaclient/v1_1/shell.py
+++ b/novaclient/v1_1/shell.py
@@ -767,7 +767,6 @@ def do_volume_delete(cs, args):
 
 @utils.arg('server',
     metavar='<server>',
-    type=int,
     help='Name or ID of server.')
 @utils.arg('volume',
     metavar='<volume>',
@@ -777,12 +776,13 @@ def do_volume_delete(cs, args):
     help='Name of the device e.g. /dev/vdb.')
 def do_volume_attach(cs, args):
     """Attach a volume to a server."""
-    cs.volumes.create_server_volume(args.server, args.volume, args.device)
+    cs.volumes.create_server_volume(_find_server(cs, args.server).id,
+                                        args.volume,
+                                        args.device)
 
 
 @utils.arg('server',
     metavar='<server>',
-    type=int,
     help='Name or ID of server.')
 @utils.arg('attachment_id',
     metavar='<volume>',
@@ -790,4 +790,5 @@ def do_volume_attach(cs, args):
     help='Attachment ID of the volume.')
 def do_volume_detach(cs, args):
     """Detach a volume from a server."""
-    cs.volumes.delete_server_volume(args.server, args.attachment_id)
+    cs.volumes.delete_server_volume(_find_server(cs, args.server).id,
+                                        args.attachment_id)