Blob Blame History Raw
From d4e96fe0294bd3d6e84a1d0a7e754662b23f8d13 Mon Sep 17 00:00:00 2001
From: Josh Durgin <josh.durgin@dreamhost.com>
Date: Wed, 4 Apr 2012 00:38:59 -0700
Subject: [PATCH] Allow unprivileged RADOS users to access rbd volumes.

This makes it possible to access rbd volumes with RADOS users with
restricted privileges. Previously, the admin user was always used.

This requires libvirt 0.9.8 or higher.

This is a backport of commit 01f24caba86c987b0109f743979a4e99e8afed11
from master.

Fixes bug 975335.

Change-Id: I3fbb2c03e5f63940c3a42f2d4f8d03ee16b30f7e
---
 .mailmap                    |    1 +
 Authors                     |    2 +-
 nova/tests/test_libvirt.py  |   51 +++++++++++++++++++++++++++++++++++++++++++
 nova/virt/libvirt/volume.py |   24 ++++++++++++++++----
 nova/volume/driver.py       |   15 +++++++++++-
 5 files changed, 85 insertions(+), 8 deletions(-)

diff --git a/.mailmap b/.mailmap
index 4f9e4e6..7fd6cb6 100644
diff --git a/Authors b/Authors
index e1a947c..a229313 100644
--- a/Authors
+++ b/Authors
@@ -98,7 +98,7 @@ Jonathan Bryce <jbryce@jbryce.com>
 Jordan Rinke <jordan@openstack.org>
 Joseph Suh <jsuh@isi.edu>
 Joseph W. Breu <breu@breu.org>
-Josh Durgin <joshd@hq.newdream.net>
+Josh Durgin <josh.durgin@dreamhost.com>
 Josh Kearney <josh@jk0.org>
 Josh Kleinpeter <josh@kleinpeter.org>
 Joshua Harlow <harlowja@yahoo-inc.com>
diff --git a/nova/tests/test_libvirt.py b/nova/tests/test_libvirt.py
index 4ce91cb..ad4bb06 100644
--- a/nova/tests/test_libvirt.py
+++ b/nova/tests/test_libvirt.py
@@ -240,6 +240,57 @@ class LibvirtVolumeTestCase(test.TestCase):
         self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
         rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
         self.assertEqual(tree.find('./source').get('name'), rbd_name)
+        self.assertEqual(tree.find('./source/auth'), None)
+        libvirt_driver.disconnect_volume(connection_info, mount_device)
+        connection_info = vol_driver.terminate_connection(vol, self.connr)
+
+    def test_libvirt_rbd_driver_auth_enabled(self):
+        vol_driver = volume_driver.RBDDriver()
+        libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
+        name = 'volume-00000001'
+        vol = {'id': 1, 'name': name}
+        connection_info = vol_driver.initialize_connection(vol, self.connr)
+        uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
+        user = 'foo'
+        secret_type = 'ceph'
+        connection_info['data']['auth_enabled'] = True
+        connection_info['data']['auth_username'] = user
+        connection_info['data']['secret_type'] = secret_type
+        connection_info['data']['secret_uuid'] = uuid
+        mount_device = "vde"
+        xml = libvirt_driver.connect_volume(connection_info, mount_device)
+        tree = ElementTree.fromstring(xml)
+        self.assertEqual(tree.get('type'), 'network')
+        self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
+        rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
+        self.assertEqual(tree.find('./source').get('name'), rbd_name)
+        self.assertEqual(tree.find('./auth').get('username'), user)
+        self.assertEqual(tree.find('./auth/secret').get('type'), secret_type)
+        self.assertEqual(tree.find('./auth/secret').get('uuid'), uuid)
+        libvirt_driver.disconnect_volume(connection_info, mount_device)
+        connection_info = vol_driver.terminate_connection(vol, self.connr)
+
+    def test_libvirt_rbd_driver_auth_disabled(self):
+        vol_driver = volume_driver.RBDDriver()
+        libvirt_driver = volume.LibvirtNetVolumeDriver(self.fake_conn)
+        name = 'volume-00000001'
+        vol = {'id': 1, 'name': name}
+        connection_info = vol_driver.initialize_connection(vol, self.connr)
+        uuid = '875a8070-d0b9-4949-8b31-104d125c9a64'
+        user = 'foo'
+        secret_type = 'ceph'
+        connection_info['data']['auth_enabled'] = False
+        connection_info['data']['auth_username'] = user
+        connection_info['data']['secret_type'] = secret_type
+        connection_info['data']['secret_uuid'] = uuid
+        mount_device = "vde"
+        xml = libvirt_driver.connect_volume(connection_info, mount_device)
+        tree = ElementTree.fromstring(xml)
+        self.assertEqual(tree.get('type'), 'network')
+        self.assertEqual(tree.find('./source').get('protocol'), 'rbd')
+        rbd_name = '%s/%s' % (FLAGS.rbd_pool, name)
+        self.assertEqual(tree.find('./source').get('name'), rbd_name)
+        self.assertEqual(tree.find('./auth'), None)
         libvirt_driver.disconnect_volume(connection_info, mount_device)
         connection_info = vol_driver.terminate_connection(vol, self.connr)
 
diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py
index 784867e..10338c2 100644
--- a/nova/virt/libvirt/volume.py
+++ b/nova/virt/libvirt/volume.py
@@ -76,11 +76,25 @@ class LibvirtNetVolumeDriver(LibvirtVolumeDriver):
         driver = self._pick_volume_driver()
         protocol = connection_info['driver_volume_type']
         name = connection_info['data']['name']
-        xml = """<disk type='network'>
-                     <driver name='%s' type='raw' cache='none'/>
-                     <source protocol='%s' name='%s'/>
-                     <target dev='%s' bus='virtio'/>
-                 </disk>""" % (driver, protocol, name, mount_device)
+        if connection_info['data'].get('auth_enabled'):
+            username = connection_info['data']['auth_username']
+            secret_type = connection_info['data']['secret_type']
+            secret_uuid = connection_info['data']['secret_uuid']
+            xml = """<disk type='network'>
+                         <driver name='%s' type='raw' cache='none'/>
+                         <source protocol='%s' name='%s'/>
+                         <auth username='%s'>
+                             <secret type='%s' uuid='%s'/>
+                         </auth>
+                         <target dev='%s' bus='virtio'/>
+                     </disk>""" % (driver, protocol, name, username,
+                                   secret_type, secret_uuid, mount_device)
+        else:
+            xml = """<disk type='network'>
+                         <driver name='%s' type='raw' cache='none'/>
+                         <source protocol='%s' name='%s'/>
+                         <target dev='%s' bus='virtio'/>
+                     </disk>""" % (driver, protocol, name, mount_device)
         return xml
 
 
diff --git a/nova/volume/driver.py b/nova/volume/driver.py
index ffdd1f5..8b316be 100644
--- a/nova/volume/driver.py
+++ b/nova/volume/driver.py
@@ -56,7 +56,14 @@ volume_opts = [
                help='The port that the iSCSI daemon is listening on'),
     cfg.StrOpt('rbd_pool',
                default='rbd',
-               help='the rbd pool in which volumes are stored'),
+               help='the RADOS pool in which rbd volumes are stored'),
+    cfg.StrOpt('rbd_user',
+               default=None,
+               help='the RADOS client name for accessing rbd volumes'),
+    cfg.StrOpt('rbd_secret_uuid',
+               default=None,
+               help='the libvirt uuid of the secret for the rbd_user'
+                    'volumes'),
     ]
 
 FLAGS = flags.FLAGS
@@ -546,7 +553,11 @@ class RBDDriver(VolumeDriver):
         return {
             'driver_volume_type': 'rbd',
             'data': {
-                'name': '%s/%s' % (FLAGS.rbd_pool, volume['name'])
+                'name': '%s/%s' % (FLAGS.rbd_pool, volume['name']),
+                'auth_enabled': FLAGS.rbd_secret_uuid is not None,
+                'auth_username': FLAGS.rbd_user,
+                'secret_type': 'ceph',
+                'secret_uuid': FLAGS.rbd_secret_uuid,
             }
         }