From: Jean-Baptiste RANSY Date: Thu, 21 Mar 2013 13:19:54 +0000 (+0100) Subject: CoraidDriver: support users that are not admin X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=0a0251e695ed600ea586233b9654aedf4dab79e6;p=openstack-build%2Fcinder-build.git CoraidDriver: support users that are not admin Add support to the CoraidDriver to specify a subgroup (with admin privileges). Coraid storage orchestration allows you to allocate portions of your SAN to specific users/groups. The driver should support this and not assume logging in as "admin" (equiv to "root"). Will add another parameter to cinder.conf, "coraid_group", and if present, the driver will authenticate using the specified group as well as the already available coraid_user parameter. Fixes bug 1157354 Change-Id: I0d165955126adabce788ebdacd3a14a08edc8d8f --- diff --git a/cinder/tests/test_coraid.py b/cinder/tests/test_coraid.py index 847d651d1..52297d746 100644 --- a/cinder/tests/test_coraid.py +++ b/cinder/tests/test_coraid.py @@ -23,6 +23,7 @@ from cinder import test from cinder.volume import configuration as conf from cinder.volume.drivers import coraid from cinder.volume.drivers.coraid import CoraidDriver +from cinder.volume.drivers.coraid import CoraidESMException from cinder.volume.drivers.coraid import CoraidRESTClient import cookielib @@ -32,7 +33,8 @@ LOG = logging.getLogger(__name__) fake_esm_ipaddress = "192.168.0.1" -fake_esm_username = "admin" +fake_esm_username = "darmok" +fake_esm_group = "tanagra" fake_esm_password = "12345678" fake_volume_name = "volume-12345678-1234-1234-1234-1234567890ab" @@ -87,6 +89,24 @@ fake_esm_success = {"category": "provider", "metaCROp": "noAction", "message": None} +fake_group_fullpath = "admin group:%s" % (fake_esm_group) +fake_group_id = 4 +fake_login_reply = {"values": [ + {"fullPath": fake_group_fullpath, + "groupId": fake_group_id}], + "message": "", + "state": "adminSucceed", + "metaCROp": "noAction"} + +fake_group_fail_fullpath = "fail group:%s" % (fake_esm_group) +fake_group_fail_id = 5 +fake_login_reply_group_fail = {"values": [ + {"fullPath": fake_group_fail_fullpath, + "groupId": fake_group_fail_id}], + "message": "", + "state": "adminSucceed", + "metaCROp": "noAction"} + class TestCoraidDriver(test.TestCase): def setUp(self): @@ -98,6 +118,7 @@ class TestCoraidDriver(test.TestCase): configuration.append_config_values(mox.IgnoreArg()) configuration.coraid_esm_address = fake_esm_ipaddress configuration.coraid_user = fake_esm_username + configuration.coraid_group = fake_esm_group configuration.coraid_password = fake_esm_password self.drv = CoraidDriver(configuration=configuration) @@ -149,8 +170,32 @@ class TestCoraidRESTClient(test.TestCase): lambda *_, **__: self.rest_mock) self.drv = CoraidRESTClient(fake_esm_ipaddress, fake_esm_username, + fake_esm_group, fake_esm_password) + def test__get_group_id(self): + setattr(self.rest_mock, '_get_group_id', + lambda *_: True) + self.assertEquals(self.drv._get_group_id(fake_esm_group, + fake_login_reply), + fake_group_id) + + def test__set_group(self): + setattr(self.rest_mock, '_set_group', + lambda *_: fake_group_id) + self.stubs.Set(CoraidRESTClient, '_esm', + lambda *_: fake_login_reply) + self.drv._set_group(fake_login_reply) + + def test__set_group_fails_no_group(self): + setattr(self.rest_mock, '_set_group', + lambda *_: False) + self.stubs.Set(CoraidRESTClient, '_esm', + lambda *_: fake_login_reply_group_fail) + self.assertRaises(CoraidESMException, + self.drv._set_group, + fake_login_reply_group_fail) + def test__configure(self): setattr(self.rest_mock, '_configure', lambda *_: True) diff --git a/cinder/volume/drivers/coraid.py b/cinder/volume/drivers/coraid.py index 260a48aea..6d3a2109a 100644 --- a/cinder/volume/drivers/coraid.py +++ b/cinder/volume/drivers/coraid.py @@ -18,6 +18,7 @@ Desc : Driver to store volumes on Coraid Appliances. Require : Coraid EtherCloud ESM, Coraid VSX and Coraid SRX. Author : Jean-Baptiste RANSY +Contrib : Larry Matter """ import cookielib @@ -45,6 +46,9 @@ coraid_opts = [ cfg.StrOpt('coraid_user', default='admin', help='User name to connect to Coraid ESM'), + cfg.StrOpt('coraid_group', + default=False, + help='Group name of coraid_user (must have admin privilege)'), cfg.StrOpt('coraid_password', default='password', help='Password to connect to Coraid ESM'), @@ -74,9 +78,10 @@ class CoraidESMException(CoraidException): class CoraidRESTClient(object): """Executes volume driver commands on Coraid ESM EtherCloud Appliance.""" - def __init__(self, ipaddress, user, password): + def __init__(self, ipaddress, user, group, password): self.url = "https://%s:8443/" % ipaddress self.user = user + self.group = group self.password = password self.session = False self.cookiejar = cookielib.CookieJar() @@ -96,6 +101,7 @@ class CoraidRESTClient(object): self.session = time.time() + 1100 msg = _('Update session cookie %(session)s') LOG.debug(msg % dict(session=self.session)) + self._set_group(reply) return True else: errmsg = response.get('message', '') @@ -103,6 +109,37 @@ class CoraidRESTClient(object): raise CoraidESMException(msg % dict(message=errmsg)) return True + def _set_group(self, reply): + """Set effective group.""" + if self.group: + group = self.group + groupId = self._get_group_id(group, reply) + if groupId: + url = ('admin?op=setRbacGroup&groupId=%s' % (groupId)) + data = 'Group' + reply = self._esm(url, data) + if reply.get('state') == 'adminSucceed': + return True + else: + errmsg = reply.get('message', '') + msg = _('Error while trying to set group: %(message)s') + raise CoraidRESTException(msg % dict(message=errmsg)) + else: + msg = _('Unable to find group: %(group)s') + raise CoraidESMException(msg % dict(group=group)) + return True + + def _get_group_id(self, groupName, loginResult): + """Map group name to group ID.""" + # NOTE(lmatter): All other groups are under the admin group + fullName = "admin group:%s" % groupName + groupId = False + for kid in loginResult['values']: + fullPath = kid['fullPath'] + if fullPath == fullName: + return kid['groupId'] + return False + def _esm(self, url=False, data=None): """ _esm represent the entry point to send requests to ESM Appliance. @@ -240,6 +277,7 @@ class CoraidDriver(driver.VolumeDriver): """Initialize the volume driver.""" self.esm = CoraidRESTClient(self.configuration.coraid_esm_address, self.configuration.coraid_user, + self.configuration.coraid_group, self.configuration.coraid_password) def check_for_setup_error(self):