Change in vdsm[ovirt-3.5-gluster]: gluster: volume snapshot config list and set verbs.

dnarayan at redhat.com dnarayan at redhat.com
Thu Apr 16 10:14:09 UTC 2015


Hello Piotr Kliczewski, Dan Kenigsberg,

I'd like you to do a code review.  Please visit

    https://gerrit.ovirt.org/39921

to review the following change.

Change subject: gluster: volume snapshot config list and set verbs.
......................................................................

gluster: volume snapshot config list and set verbs.

This patch adds new verbs to list and set the
configuration of gluster volume snapshots.

*glusterSnapshotConfigList: get the snapshot configuration.
This verb gives the snapshot configuration for the cluster
and for all the volumes present in it.
Returns:
{'system':{'snap-max-hard-limit': 'hardlimit',
           'snap-max-soft-limit': 'softLimit',
           'auto-delete': 'enable/disable'},
 'volume':{'name' :
            {'snap-max-hard-limit: 'hardlimit',
             'effective-hard-limit: 'EffectiveHardlimit',
             'snap-max-soft-limit': 'softLimit'}
          }...
}

*glusterVolumeSnapshotConfigList: Get the snapshot
configuration for a volume. Volume name should be provided
as an argument, configuration for that volume along with
cluster snapshot configuration is listed.
Returns:
{'system':{'snap-max-hard-limit': 'hardlimit',
           'snap-max-soft-limit': 'softLimit',
           'auto-delete': 'enable/disable'},
 'volume':{'name' :
            {'snap-max-hard-limit: 'hardlimit',
             'effective-hard-limit: 'EffectiveHardlimit',
             'snap-max-soft-limit': 'softLimit'}
          }
}

*glusterSnapshotConfigSet: Set snapshot configuration
at cluster leval. The possible configurations that can
be set are:
snap-max-hard-limit, snap-max-soft-limit and auto-delete

*glusterVolumeSnapshotConfigSet: Set snapshot configuration
at volume leval. Volume name has to be provided as argument.
And the configurable parameter is snap-max-hard-limit.

Change-Id: Iee32a95cf028cda33f25776c08820c5ed80f1033
Signed-off-by: Darshan N <dnarayan at redhat.com>
Reviewed-on: https://gerrit.ovirt.org/34741
Reviewed-by: Piotr Kliczewski <piotr.kliczewski at gmail.com>
Reviewed-by: Dan Kenigsberg <danken at redhat.com>
---
M client/vdsClientGluster.py
M tests/Makefile.am
A tests/glusterSnapshotConfig.xml
M tests/glusterTestData.py
M tests/gluster_cli_tests.py
M vdsm.spec.in
M vdsm/gluster/api.py
M vdsm/gluster/apiwrapper.py
M vdsm/gluster/cli.py
M vdsm/gluster/exception.py
M vdsm/rpc/vdsmapi-gluster-schema.json
11 files changed, 354 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/21/39921/1

diff --git a/client/vdsClientGluster.py b/client/vdsClientGluster.py
index d86d16d..652526d 100644
--- a/client/vdsClientGluster.py
+++ b/client/vdsClientGluster.py
@@ -613,6 +613,41 @@
         pp.pprint(status)
         return status['status']['code'], status['status']['message']
 
+    def do_glusterVolumeSnapshotConfigList(self, args):
+        params = self._eqSplit(args)
+        volumeName = params.get('volumeName', '')
+
+        status = self.s.glusterVolumeSnapshotConfigList(volumeName)
+
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterSnapshotConfigList(self, args):
+        status = self.s.glusterSnapshotConfigList()
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterVolumeSnapshotConfigSet(self, args):
+        params = self._eqSplit(args)
+        volumeName = params.get('volumeName', '')
+        optionName = params.get('optionName', '')
+        optionValue = params.get('optionValue', '')
+
+        status = self.s.glusterVolumeSnapshotConfigSet(volumeName,
+                                                       optionName,
+                                                       optionValue)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
+    def do_glusterSnapshotConfigSet(self, args):
+        params = self._eqSplit(args)
+        optionName = params.get('optionName', '')
+        optionValue = params.get('optionValue', '')
+
+        status = self.s.glusterSnapshotConfigSet(optionName, optionValue)
+        pp.pprint(status)
+        return status['status']['code'], status['status']['message']
+
 
 def getGlusterCmdDict(serv):
     return \
@@ -1021,6 +1056,18 @@
              ('volumeName=<volume name>',
               'delete all snapshots for given volume'
               )),
+         'glusterVolumeSnapshotConfigList': (
+             serv.do_glusterVolumeSnapshotConfigList,
+             ('volumeName=<volume_name>',
+              'get gluster volume snapshot configuration'
+              )),
+         'glusterVolumeSnapshotConfigSet': (
+             serv.do_glusterVolumeSnapshotConfigSet,
+             ('volumeName=<volume_name>'
+              'optionName=<option_name>'
+              'optionValue=<option_value>',
+              'Set gluster snapshot configuration at volume leval'
+              )),
          'glusterSnapshotDelete': (
              serv.do_glusterSnapshotDelete,
              ('snapName=<snap_name>',
@@ -1041,5 +1088,16 @@
              serv.do_glusterSnapshotRestore,
              ('snapName=snap_name',
               'restore snapshot'
+              )),
+         'glusterSnapshotConfigList': (
+             serv.do_glusterSnapshotConfigList,
+             ('',
+              'get gluster volume snapshot configuration'
+              )),
+         'glusterSnapshotConfigSet': (
+             serv.do_glusterSnapshotConfigSet,
+             ('optionName=<option_name>'
+              'optionValue=<option_value>',
+              'Set gluster snapshot configuration at cluster leval'
               ))
          }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0395058..69feaf2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -114,6 +114,7 @@
 	caps_numactl_4_nodes.out \
 	glob_1c60971a-8647-44ac-ae33-6520887f8843.out \
 	glusterGeoRepStatus.xml \
+	glusterSnapshotConfig.xml \
 	glusterSnapshotRestore.xml \
 	glusterVolumeGeoRepConfigList.xml \
 	glusterVolumeProfileInfo.xml \
diff --git a/tests/glusterSnapshotConfig.xml b/tests/glusterSnapshotConfig.xml
new file mode 100644
index 0000000..d167fdc
--- /dev/null
+++ b/tests/glusterSnapshotConfig.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<cliOutput>
+  <opRet>0</opRet>
+  <opErrno>0</opErrno>
+  <opErrstr/>
+  <snapConfig>
+    <systemConfig>
+      <hardLimit>255</hardLimit>
+      <softLimit>91%</softLimit>
+      <autoDelete>disable</autoDelete>
+    </systemConfig>
+    <volumeConfig>
+      <volume>
+        <name>snap-vol</name>
+        <hardLimit>256</hardLimit>
+        <effectiveHardLimit>255</effectiveHardLimit>
+        <softLimit>232</softLimit>
+      </volume>
+      <volume>
+        <name>snap-vol2</name>
+        <hardLimit>254</hardLimit>
+        <effectiveHardLimit>254</effectiveHardLimit>
+        <softLimit>231</softLimit>
+      </volume>
+    </volumeConfig>
+  </snapConfig>
+</cliOutput>
diff --git a/tests/glusterTestData.py b/tests/glusterTestData.py
index 165c1c3..ff2b1f0 100644
--- a/tests/glusterTestData.py
+++ b/tests/glusterTestData.py
@@ -1128,3 +1128,23 @@
     'volumeName': 'snap-vol2',
     'volumeUuid': '8558c40f-1581-414e-89d6-46854376ae3d'
 }
+
+GLUSTER_SNAPSHOT_CONFIG_LIST = {
+    'volume': {
+        'snap-vol': {
+            'snap-max-hard-limit': '256',
+            'snap-max-soft-limit': '232',
+            'effective-hard-limit': '255'
+        },
+        'snap-vol2': {
+            'snap-max-hard-limit': '254',
+            'snap-max-soft-limit': '231',
+            'effective-hard-limit': '254'
+        }
+    },
+    'system': {
+        'snap-max-hard-limit': '255',
+        'auto-delete': 'disable',
+        'snap-max-soft-limit': '91%'
+    }
+}
diff --git a/tests/gluster_cli_tests.py b/tests/gluster_cli_tests.py
index eeb00d9..b08e67b 100644
--- a/tests/gluster_cli_tests.py
+++ b/tests/gluster_cli_tests.py
@@ -1152,3 +1152,10 @@
         tree = etree.fromstring(out)
         status = gcli._parseRestoredSnapshot(tree)
         self.assertEquals(status, glusterTestData.GLUSTER_SNAPSHOT_RESTORE)
+
+    def test_parseSnapshotConfigList(self):
+        with open("glusterSnapshotConfig.xml") as f:
+            out = f.read()
+        tree = etree.fromstring(out)
+        status = gcli._parseSnapshotConfigList(tree)
+        self.assertEquals(status, glusterTestData.GLUSTER_SNAPSHOT_CONFIG_LIST)
diff --git a/vdsm.spec.in b/vdsm.spec.in
index c1737a7..98384e0 100644
--- a/vdsm.spec.in
+++ b/vdsm.spec.in
@@ -1300,6 +1300,7 @@
 %{_datadir}/%{vdsm_name}/tests/glusterGeoRepStatus.xml
 %{_datadir}/%{vdsm_name}/tests/glusterVolumeGeoRepConfigList.xml
 %{_datadir}/%{vdsm_name}/tests/glusterVolumeProfileInfo.xml
+%{_datadir}/%{vdsm_name}/tests/glusterSnapshotConfig.xml
 %{_datadir}/%{vdsm_name}/tests/glusterVolumeProfileInfoNfs.xml
 %{_datadir}/%{vdsm_name}/tests/glusterVolumeRebalanceStatus.xml
 %{_datadir}/%{vdsm_name}/tests/glusterVolumeRemoveBricksStatus.xml
diff --git a/vdsm/gluster/api.py b/vdsm/gluster/api.py
index 6d7e139..648b2bc 100644
--- a/vdsm/gluster/api.py
+++ b/vdsm/gluster/api.py
@@ -445,6 +445,45 @@
         status = self.svdsmProxy.glusterSnapshotRestore(snapName)
         return {'snapRestore': status}
 
+    @exportAsVerb
+    def snapshotConfigList(self, options=None):
+        try:
+            status = self.svdsmProxy.glusterSnapshotConfig()
+        except ge.GlusterSnapshotConfigFailedException as e:
+            raise ge.GlusterSnapshotConfigGetFailedException(rc=e.rc,
+                                                             err=e.err)
+        return {'snapshotConfig': status}
+
+    @exportAsVerb
+    def volumeSnapshotConfigList(self, volumeName, options=None):
+        try:
+            status = self.svdsmProxy.glusterSnapshotConfig(
+                volumeName=volumeName)
+        except ge.GlusterSnapshotConfigFailedException as e:
+            raise ge.GlusterSnapshotConfigGetFailedException(rc=e.rc,
+                                                             err=e.err)
+        return {'snapshotConfig': status}
+
+    @exportAsVerb
+    def volumeSnapshotConfigSet(self, volumeName, optionName, optionValue,
+                                options=None):
+        try:
+            self.svdsmProxy.glusterSnapshotConfig(volumeName=volumeName,
+                                                  optionName=optionName,
+                                                  optionValue=optionValue)
+        except ge.GlusterSnapshotConfigFailedException as e:
+            raise ge.GlusterSnapshotConfigSetFailedException(rc=e.rc,
+                                                             err=e.err)
+
+    @exportAsVerb
+    def snapshotConfigSet(self, optionName, optionValue, options=None):
+        try:
+            self.svdsmProxy.glusterSnapshotConfig(optionName=optionName,
+                                                  optionValue=optionValue)
+        except ge.GlusterSnapshotConfigFailedException as e:
+            raise ge.GlusterSnapshotConfigSetFailedException(rc=e.rc,
+                                                             err=e.err)
+
 
 def getGlusterMethods(gluster):
     l = []
diff --git a/vdsm/gluster/apiwrapper.py b/vdsm/gluster/apiwrapper.py
index f4177cd..0cdb795 100644
--- a/vdsm/gluster/apiwrapper.py
+++ b/vdsm/gluster/apiwrapper.py
@@ -248,6 +248,13 @@
     def snapshotDeleteAll(self, volumeName):
         return self._gluster.volumeSnapshotDeleteAll(volumeName)
 
+    def snapshotConfigSet(self, volumeName, optionName, optionValue):
+        return self._gluster.volumeSnapshotConfigSet(volumeName, optionName,
+                                                     optionValue)
+
+    def snapshotConfigList(self, volumeName):
+        return self._gluster.volumeSnapshotConfigList(volumeName)
+
 
 class GlusterSnapshot(GlusterApiBase):
     def __init__(self):
@@ -264,3 +271,9 @@
 
     def restore(self, snapName):
         return self._gluster.snapshotRestore(snapName)
+
+    def configList(self):
+        return self._gluster.snapshotConfigList()
+
+    def configSet(self, optionName, optionValue):
+        return self._gluster.snapshotConfigSet(optionName, optionValue)
diff --git a/vdsm/gluster/cli.py b/vdsm/gluster/cli.py
index e60da27..c605fd8 100644
--- a/vdsm/gluster/cli.py
+++ b/vdsm/gluster/cli.py
@@ -1335,3 +1335,55 @@
         return _parseRestoredSnapshot(xmltree)
     except _etreeExceptions:
         raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
+
+
+def _parseSnapshotConfigList(tree):
+    """
+    returns {'system':{'snap-max-hard-limit': 'hardlimit',
+                       'snap-max-soft-limit': 'softLimit',
+                       'auto-delete': 'enable/disable'},
+             'volume':{'name' :
+                          {'snap-max-hard-limit: 'hardlimit',
+                           'effective-hard-limit: 'EffectiveHardlimit',
+                           'snap-max-soft-limit': 'softLimit'}
+                      }
+            }
+    """
+    systemConfig = {}
+    systemConfig['snap-max-hard-limit'] = tree.find(
+        'snapConfig/systemConfig/hardLimit').text
+    systemConfig['snap-max-soft-limit'] = tree.find(
+        'snapConfig/systemConfig/softLimit').text
+    systemConfig['auto-delete'] = tree.find(
+        'snapConfig/systemConfig/autoDelete').text
+
+    volumeConfig = {}
+    for el in tree.findall('snapConfig/volumeConfig/volume'):
+        config = {}
+        volumeName = el.find('name').text
+        config['snap-max-hard-limit'] = el.find('hardLimit').text
+        config['effective-hard-limit'] = el.find('effectiveHardLimit').text
+        config['snap-max-soft-limit'] = el.find('softLimit').text
+        volumeConfig[volumeName] = config
+
+    return {'system': systemConfig, 'volume': volumeConfig}
+
+
+ at makePublic
+def snapshotConfig(volumeName=None, optionName=None, optionValue=None):
+    command = _getGlusterSnapshotCmd() + ["config"]
+    if volumeName:
+        command.append(volumeName)
+    if optionName and optionValue:
+        command += [optionName, optionValue]
+
+    try:
+        xmltree = _execGlusterXml(command)
+        if optionName and optionValue:
+            return
+    except ge.GlusterCmdFailedException as e:
+        raise ge.GlusterSnapshotConfigFailedException(rc=e.rc, err=e.err)
+    try:
+        return _parseSnapshotConfigList(xmltree)
+    except _etreeExceptions:
+        raise ge.GlusterXmlErrorException(err=[etree.tostring(xmltree)])
diff --git a/vdsm/gluster/exception.py b/vdsm/gluster/exception.py
index e7e4533..00727d9 100644
--- a/vdsm/gluster/exception.py
+++ b/vdsm/gluster/exception.py
@@ -575,3 +575,21 @@
 class GlusterSnapshotRestoreFailedException(GlusterSnapshotException):
     code = 4705
     message = "Snapshot restore failed"
+
+
+class GlusterSnapshotConfigFailedException(
+        GlusterSnapshotException):
+    code = 4706
+    message = "Snapshot config failed"
+
+
+class GlusterSnapshotConfigSetFailedException(
+        GlusterSnapshotException):
+    code = 4707
+    message = "Snapshot config set failed"
+
+
+class GlusterSnapshotConfigGetFailedException(
+        GlusterSnapshotException):
+    code = 4708
+    message = "Snapshot config get failed"
diff --git a/vdsm/rpc/vdsmapi-gluster-schema.json b/vdsm/rpc/vdsmapi-gluster-schema.json
index 5143f26..e4c0d14 100644
--- a/vdsm/rpc/vdsmapi-gluster-schema.json
+++ b/vdsm/rpc/vdsmapi-gluster-schema.json
@@ -1724,3 +1724,121 @@
 {'command': {'class': 'GlusterSnapshot', 'name': 'restore'},
  'data': {'snapName': 'str'},
  'returns': 'SnapRestoreDetail'}
+
+##
+#
+# @SystemSnapshotConfig:
+#
+# @snap-max-hard-limit: Snapshot max hard limit
+#
+# @snap-max-soft-limit: Soft limit percentage of snapshot max limit
+#
+# @auto-delete:         Auto delete enabled/disabled
+#
+# @Since: 4.17.0
+##
+{'type': 'SystemSnapshotConfig',
+ 'data': {'snap-max-hard-limit': 'str', 'snap-max-soft-limit': 'str',
+          'auto-delete': 'str'}}
+
+##
+#
+# @VolumeSnapConfig:
+#
+# @snap-max-hard-limit:  Snapshot max hard limit
+#
+# @effective-hard-limit: Effective snapshot Hard limit for that volume
+#
+# @snap-max-soft-limit:  Snapshot soft limit for that volume
+#
+# @Since: 4.17.0
+##
+{'type': 'VolumeSnapConfig',
+ 'data': {'snap-max-hard-limit': 'str', 'effective-hard-limit': 'str',
+          'snap-max-soft-limit': 'str'}}
+
+##
+#
+# @VolumeSnapshotConfigMap:
+#
+# A mapping of snapshot config indexed by volume name.
+#
+# @Since: 4.17.0
+##
+{'map': 'VolumeSnapshotConfigMap',
+ 'key': 'str', 'value': 'VolumeSnapConfig'}
+
+##
+# @SnapConfigDetail
+#
+# Snapshot configuration details
+#
+# @system: System level snapshot configuration
+#
+# @volume: Volume specific snapshot configuration
+#
+# Since: 4.17.0
+##
+{'type': 'SnapConfigDetail',
+ 'data': {'system': 'SystemSnapshotConfig',
+          'volume': 'VolumeSnapshotConfigMap'}}
+
+##
+# @GlusterSnapshot.configList:
+#
+# get the config values of snapshot
+#
+# Returns:
+# current configuration related to system and all volumes
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'GlusterSnapshot', 'name': 'configList'},
+ 'data': {},
+ 'returns': 'SnapConfigDetail'}
+
+##
+# @GlusterVolume.snapshotConfigList:
+#
+# get the config values of snapshot for a volume
+#
+# @volumeName: Gluster volume name
+#
+# Returns:
+# current configuration related a gluster volume
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'GlusterVolume', 'name': 'snapshotConfigList'},
+ 'data': {'volumeName': 'str'},
+ 'returns': 'SnapConfigDetail'}
+
+##
+# @GlusterSnapshot.configSet:
+#
+# set gluster volume snapshot config
+#
+# @optionName:   Option name to be set
+#
+# @optionValue:  Value of the configration option
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'GlusterSnapshot', 'name': 'configSet'},
+ 'data': {'optionName': 'str', 'optionValue': 'str'}}
+
+##
+# @GlusterVolume.snapshotConfigSet:
+#
+# set gluster volume snapshot config
+#
+# @volumeName:     Gluster volume name
+#
+# @optionName:     Option name to be set
+#
+# @optionValue:    Value of the configration option
+#
+# Since: 4.17.0
+##
+{'command': {'class': 'GlusterVolume', 'name': 'snapshotConfigSet'},
+ 'data': {'volumeName': 'str', 'optionName': 'str', 'optionValue': 'str'}}


-- 
To view, visit https://gerrit.ovirt.org/39921
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Iee32a95cf028cda33f25776c08820c5ed80f1033
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.5-gluster
Gerrit-Owner: Darshan N <dnarayan at redhat.com>
Gerrit-Reviewer: Dan Kenigsberg <danken at redhat.com>
Gerrit-Reviewer: Piotr Kliczewski <piotr.kliczewski at gmail.com>


More information about the vdsm-patches mailing list