]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add support for Purity Protection Groups to PureISCSIDriver
authorPatrick East <patrick.east@purestorage.com>
Fri, 5 Dec 2014 18:18:46 +0000 (10:18 -0800)
committerPatrick East <patrick.east@purestorage.com>
Wed, 17 Dec 2014 19:00:45 +0000 (11:00 -0800)
We will be needing access to the Protection Group features of Purity to
enable features like Replication and Consistency Groups. To do this we
need to add new helpers for the FlashArray object for the required REST
API methods.

DocImpact: To bring in pgroup support we will need to bump up the
required REST API version to 1.2+ and remove support for 1.0 and 1.1

Implements: blueprint pure-iscsi-add-pgroup-support
Change-Id: Ia446615e0c03b91fc1da75489855e77c29639efa

cinder/tests/test_pure.py
cinder/volume/drivers/pure.py

index b0bae9a59092689357d2001ed6b64869e8d29bfe..fdc03afacc13bff82eb8ad817c1d6310f7070e3c 100644 (file)
@@ -614,16 +614,16 @@ class FlashArrayHttpRequestTestCase(FlashArrayBaseTestCase):
     # Test with _http_requests rather than rest calls to ensure
     # root_url change happens properly
     def test_choose_rest_version(self):
-        response_string = '{"version": ["0.1", "1.3", "1.1", "1.0"]}'
+        response_string = '{"version": ["0.1", "1.4", "1.3", "1.0"]}'
         self.response.read.return_value = response_string
         self.array._opener.open.return_value = self.response
         result = self.array._choose_rest_version()
-        self.assertEqual(result, "1.1")
+        self.assertEqual(result, "1.3")
         self.array._opener.open.assert_called_with(FakeRequest(
             "GET", "https://%s/api/api_version" % TARGET,
             headers=self.headers), "null")
         self.array._opener.open.reset_mock()
-        self.response.read.return_value = '{"version": ["0.1", "1.3"]}'
+        self.response.read.return_value = '{"version": ["0.1", "1.4"]}'
         self.assertRaises(exception.PureDriverException,
                           self.array._choose_rest_version)
 
@@ -765,6 +765,68 @@ class FlashArrayRESTTestCase(FlashArrayBaseTestCase):
         self.assert_error_propagates([mock_req], self.array.list_volume_hosts,
                                      "vol-name")
 
+    def test_create_pgroup(self, mock_req):
+        mock_req.return_value = self.result
+        pgroup_name = "cgroup_id"
+        result = self.array.create_pgroup(pgroup_name)
+        self.assertEqual(self.result, result)
+        req_url = "pgroup/" + pgroup_name
+        mock_req.assert_called_with(self.array, "POST", req_url)
+        self.assert_error_propagates([mock_req], self.array.create_pgroup,
+                                     pgroup_name)
+
+    def test_delete_pgroup(self, mock_req):
+        mock_req.return_value = self.result
+        pgroup_name = "cgroup_id"
+        result = self.array.delete_pgroup(pgroup_name)
+        self.assertEqual(self.result, result)
+        req_url = "pgroup/" + pgroup_name
+        mock_req.assert_called_with(self.array, "DELETE", req_url)
+        self.assert_error_propagates([mock_req], self.array.delete_pgroup,
+                                     pgroup_name)
+
+    def test_create_pgroup_snapshot(self, mock_req):
+        mock_req.return_value = self.result
+        pgroup_name = "cgroup_id"
+        snap_suffix = "snap_suffix"
+        result = self.array.create_pgroup_snapshot(pgroup_name, snap_suffix)
+        self.assertEqual(self.result, result)
+        expected_params = {
+            "snap": True,
+            "suffix": snap_suffix,
+            "source": [pgroup_name]
+        }
+        mock_req.assert_called_with(self.array, "POST", "pgroup",
+                                    expected_params)
+        self.assert_error_propagates([mock_req],
+                                     self.array.create_pgroup_snapshot,
+                                     pgroup_name, snap_suffix)
+
+    def test_delete_pgroup_snapshot(self, mock_req):
+        mock_req.return_value = self.result
+        snapshot_name = "snap1"
+        result = self.array.delete_pgroup_snapshot(snapshot_name)
+        self.assertEqual(self.result, result)
+        req_url = "pgroup/" + snapshot_name
+        mock_req.assert_called_with(self.array, "DELETE", req_url)
+        self.assert_error_propagates([mock_req],
+                                     self.array.delete_pgroup_snapshot,
+                                     snapshot_name)
+
+    def test_add_volume_to_pgroup(self, mock_req):
+        mock_req.return_value = self.result
+        pgroup_name = "cgroup_id"
+        volume_name = "myvol-1"
+        expected_params = {"addvollist": [volume_name]}
+        result = self.array.add_volume_to_pgroup(pgroup_name, volume_name)
+        self.assertEqual(self.result, result)
+        req_url = "pgroup/" + pgroup_name
+        mock_req.assert_called_with(self.array, "PUT", req_url,
+                                    expected_params)
+        self.assert_error_propagates([mock_req],
+                                     self.array.add_volume_to_pgroup,
+                                     pgroup_name, volume_name)
+
 
 class FakeFlashArray(pure.FlashArray):
 
index 12c7362b2fadc9615661fb369a20174099bec1e7..e5335b592956bdea8b6453d6093a3501e15d21a1 100644 (file)
@@ -71,7 +71,7 @@ def _generate_purity_host_name(name):
 class PureISCSIDriver(san.SanISCSIDriver):
     """Performs volume management on Pure Storage FlashArray."""
 
-    VERSION = "1.0.0"
+    VERSION = "2.0.0"
 
     def __init__(self, *args, **kwargs):
         execute = kwargs.pop("execute", utils.execute)
@@ -323,7 +323,7 @@ class PureISCSIDriver(san.SanISCSIDriver):
 
 class FlashArray(object):
     """Wrapper for Pure Storage REST API."""
-    SUPPORTED_REST_API_VERSIONS = ["1.2", "1.1", "1.0"]
+    SUPPORTED_REST_API_VERSIONS = ["1.3", "1.2"]
 
     def __init__(self, target, api_token):
         cookie_handler = urllib2.HTTPCookieProcessor(cookielib.CookieJar())
@@ -463,3 +463,24 @@ class FlashArray(object):
     def list_volume_hosts(self, volume):
         """Return a list of dictionaries describing connected hosts."""
         return self._http_request("GET", "volume/%s/host" % volume)
+
+    def create_pgroup(self, name):
+        return self._http_request("POST", "pgroup/%s" % name)
+
+    def delete_pgroup(self, name):
+        return self._http_request("DELETE", "pgroup/%s" % name)
+
+    def create_pgroup_snapshot(self, pgroup_name, pgsnapshot_suffix):
+        params = {
+            "snap": True,
+            "suffix": pgsnapshot_suffix,
+            "source": [pgroup_name]
+        }
+        return self._http_request("POST", "pgroup", params)
+
+    def delete_pgroup_snapshot(self, name):
+        return self._http_request("DELETE", "pgroup/%s" % name)
+
+    def add_volume_to_pgroup(self, pgroup_name, volume_name):
+        return self._http_request("PUT", "pgroup/%s" % pgroup_name,
+                                  {"addvollist": [volume_name]})