Dima Kuznetsov has uploaded a new change for review.

Change subject: client: Add warning prompt on dangerous commands
......................................................................

client: Add warning prompt on dangerous commands

Added a warning and confirmation prompt for the following commands:
 * deactivateStorageDomain
 * deleteImage
 * deleteVolume
 * deleteVolumeByDescr
 * destroyStoragePool
 * extendStorageDomain
 * extendVolume
 * forcedDetachStorageDomain
 * formatStorageDomain
 * mergeSnapshots
 * moveImage
 * moveMultiImage
 * reconstructMaster
 * releaseDomainLock
 * removeVG

Also added '--force' flag to bypass warnings and prompts (intended for
scripts).

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=1005923
Change-Id: Idea34ad7c3d5b66993bcb56b61e7edb0549ef9fb
Signed-off-by: Dima Kuznetsov <dkuzn...@redhat.com>
---
M client/vdsClient.py
M lib/vdsm/vdscli.py.in
M tests/vdsClientTests.py
3 files changed, 95 insertions(+), 17 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/74/28174/1

diff --git a/client/vdsClient.py b/client/vdsClient.py
index 0235837..0eb4aac 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -85,6 +85,7 @@
     print "-m\tList supported methods and their params (Short help)"
     print "-s [--truststore path]\tConnect to server with SSL."
     print "-o, --oneliner\tShow the key-val information in one line."
+    print "--force\tDo not prompt on dangerous commands (not recommended)."
     print "\tIf truststore path is not specified, use defaults."
     print "\nCommands"
     verbs = cmd.keys()
@@ -2070,11 +2071,12 @@
                       'Create a new VG from devices devlist (list of dev '
                       'GUIDs)'
                       )),
-        'removeVG': (serv.removeVG,
+        'removeVG': (vdscli.request_confirmation(serv.removeVG),
                      ('<vgUUID>',
                       'remove the VG identified by its UUID'
                       )),
-        'extendStorageDomain': (serv.extendStorageDomain,
+        'extendStorageDomain': (vdscli.request_confirmation(
+                                serv.extendStorageDomain),
                                 ('<sdUUID> <spUUID> <devlist>',
                                  'Extend the Storage Domain by adding devices'
                                  ' devlist (list of dev GUIDs)'
@@ -2132,7 +2134,8 @@
                               ('<spUUID> <sdUUID>',
                                'acquire storage domain lock'
                                )),
-        'releaseDomainLock': (serv.releaseDomainLock,
+        'releaseDomainLock': (vdscli.request_confirmation(
+                              serv.releaseDomainLock),
                               ('<spUUID> <sdUUID>',
                                'release storage domain lock'
                                )),
@@ -2154,7 +2157,8 @@
                      ('<spUUID> <vmUUID> [sdUUID]',
                       'Remove VM from pool or Backup domain'
                       )),
-        'reconstructMaster': (serv.reconstructMaster,
+        'reconstructMaster': (vdscli.request_confirmation(
+                              serv.reconstructMaster),
                               ('<spUUID> <poolName> <masterDom> '
                                '<domDict>({sdUUID1=status,sdUUID2=status,...})'
                                ' <masterVersion>, [<lockPolicy> '
@@ -2171,7 +2175,8 @@
                                'Create new storage pool with single/multiple '
                                'image data domain'
                                )),
-        'destroyStoragePool': (serv.destroyStoragePool,
+        'destroyStoragePool': (vdscli.request_confirmation(
+                               serv.destroyStoragePool),
                                ('<spUUID> <id> <scsi-key>',
                                 'Destroy storage pool',
                                 'Parameter scsi-key is ignored (maintained '
@@ -2227,7 +2232,8 @@
                                    'Activate a storage domain that is already '
                                    'a member in a storage pool.'
                                    )),
-        'deactivateStorageDomain': (serv.deactivateStorageDomain,
+        'deactivateStorageDomain': (vdscli.request_confirmation(
+                                    serv.deactivateStorageDomain),
                                     ('<domain UUID> <pool UUID> <new master '
                                      'domain UUID> <masterVer>',
                                      'Deactivate a storage domain. '
@@ -2241,12 +2247,14 @@
                                  ' UUID> <masterVer>',
                                  'Detach a storage domain from a storage pool.'
                                  )),
-        'forcedDetachStorageDomain': (serv.forcedDetachStorageDomain,
+        'forcedDetachStorageDomain': (vdscli.request_confirmation(
+                                      serv.forcedDetachStorageDomain),
                                       ('<domain UUID> <pool UUID>',
                                        'Forced detach a storage domain from a '
                                        'storage pool.'
                                        )),
-        'formatStorageDomain': (serv.formatStorageDomain,
+        'formatStorageDomain': (vdscli.request_confirmation(
+                                serv.formatStorageDomain),
                                 ('<domain UUID> [<autoDetach>]',
                                  'Format detached storage domain.'
                                  )),
@@ -2269,7 +2277,8 @@
                           '<srcImgUUID> <srcVolUUID>',
                           'Creates new volume or snapshot'
                           )),
-        'extendVolumeSize': (serv.extendVolumeSize, (
+        'extendVolumeSize': (vdscli.request_confirmation(
+                             serv.extendVolumeSize), (
             '<spUUID> <sdUUID> <imgUUID> <volUUID> <newSize>',
             'Extend the volume size (virtual disk size seen by the guest).',
         )),
@@ -2287,12 +2296,13 @@
                                '<Legality>',
                                'Set volume legality (ILLEGAL/LEGAL).'
                                )),
-        'deleteVolume': (serv.deleteVolume,
+        'deleteVolume': (vdscli.request_confirmation(serv.deleteVolume),
                          ('<sdUUID> <spUUID> <imgUUID> <volUUID>,...,<volUUID>'
                           ' <postZero> [<force>]',
                           'Deletes an volume if its a leaf. Else returns error'
                           )),
-        'deleteVolumeByDescr': (serv.deleteVolumeByDescr,
+        'deleteVolumeByDescr': (vdscli.request_confirmation(
+                                serv.deleteVolumeByDescr),
                                 ('<part of description> <sdUUID> <spUUID> '
                                  '<imgUUID>',
                                  'Deletes list of volumes(only leafs) '
@@ -2391,11 +2401,11 @@
                                   ' <enabled = true/false>',
                                   'Enable or disable Hosted Engine HA'
                                   ' maintenance')),
-        'deleteImage': (serv.deleteImage,
+        'deleteImage': (vdscli.request_confirmation(serv.deleteImage),
                         ('<sdUUID> <spUUID> <imgUUID> [<postZero>] [<force>]',
                          'Delete Image folder with all volumes.',
                          )),
-        'moveImage': (serv.moveImage,
+        'moveImage': (vdscli.request_confirmation(serv.moveImage),
                       ('<spUUID> <srcDomUUID> <dstDomUUID> <imgUUID> <vmUUID>'
                        ' <op = COPY_OP/MOVE_OP> [<postZero>] [ <force>]',
                        'Move/Copy image between storage domains within same '
@@ -2423,7 +2433,7 @@
             'Download an image from a remote endpoint using the specified',
             'methodArgs.'
         )),
-        'moveMultiImage': (serv.moveMultiImage,
+        'moveMultiImage': (vdscli.request_confirmation(serv.moveMultiImage),
                            ('<spUUID> <srcDomUUID> <dstDomUUID> '
                             '<imgList>({imgUUID=postzero,'
                             'imgUUID=postzero,...}) <vmUUID> [<force>]',
@@ -2439,7 +2449,7 @@
                        'Do it by collapse and copy the whole chain '
                        '(baseVolUUID->srcVolUUID)'
                        )),
-        'mergeSnapshots': (serv.mergeSnapshots,
+        'mergeSnapshots': (vdscli.request_confirmation(serv.mergeSnapshots),
                            ('<sdUUID> <spUUID> <vmUUID> <imgUUID> <Ancestor '
                             'Image uuid> <Successor Image uuid> [<postZero>]',
                             'Merge images from successor to ancestor.',
@@ -2574,8 +2584,8 @@
     try:
         opts, args = getopt.getopt(sys.argv[1:], "hmso", ["help", "methods",
                                                           "SSL", "truststore=",
-                                                          "oneliner"])
-
+                                                          "oneliner", "force"])
+        vdscli.REQUEST_CONFIRMATION = True
         for o, v in opts:
             if o == "-h" or o == "--help":
                 usage(commands)
@@ -2589,6 +2599,8 @@
                 serv.truststore = v
             if o == '-o' or o == '--oneliner':
                 serv.pretty = False
+            if o == '--force':
+                vdscli.REQUEST_CONFIRMATION = False
         if len(args) < 2:
             raise Exception("Need at least two arguments")
         server, command = args[0:2]
diff --git a/lib/vdsm/vdscli.py.in b/lib/vdsm/vdscli.py.in
index 5fa7528..2ac21b2 100644
--- a/lib/vdsm/vdscli.py.in
+++ b/lib/vdsm/vdscli.py.in
@@ -21,6 +21,7 @@
 
 import xmlrpclib
 import subprocess
+import functools
 import os
 import re
 import sys
@@ -165,3 +166,25 @@
                                                 d_useSSL, d_tsPath)
     server = connect()
     print server.getVdsCapabilities()
+
+
+USER_WARNING = """
+Please note that vdsClient is not a supported tool and should be used only with
+direct guidance from support representative.
+
+This operation might cause data corruption, would you like to proceed?
+[n][Y] """.lstrip()
+
+
+REQUEST_CONFIRMATION = False
+
+
+def request_confirmation(f):
+    @functools.wraps(f)
+    def wrapper(*args, **kwargs):
+        if REQUEST_CONFIRMATION:
+            resp = raw_input(USER_WARNING).decode('string_escape')
+            if resp != 'Y':
+                sys.exit(1)
+        return f(*args, **kwargs)
+    return wrapper
diff --git a/tests/vdsClientTests.py b/tests/vdsClientTests.py
index 41e93fc..8d9b943 100644
--- a/tests/vdsClientTests.py
+++ b/tests/vdsClientTests.py
@@ -22,12 +22,15 @@
 from tempfile import mkstemp
 from contextlib import contextmanager
 import subprocess
+import sys
+import StringIO
 
 from testrunner import VdsmTestCase as TestCaseBase
 from monkeypatch import MonkeyPatch
 
 import vdsClient
 from vdsm.vdscli import __getLocalVdsName as getLocalVdsName
+import vdsm.vdscli as vdscli
 
 
 @contextmanager
@@ -150,6 +153,7 @@
 
 
 class vdscliTests(TestCaseBase):
+
     @MonkeyPatch(subprocess, 'Popen', lambda *y, **x: _FakePopen(
         'subject= /O=VDSM Certificate/CN=myhost\n'))
     def test__getLocalVdsName1(self):
@@ -166,3 +170,42 @@
     def test__getLocalVdsName3(self):
         cn = getLocalVdsName('fake')
         self.assertEquals('0', cn)
+
+
+class ConfirmationTests(TestCaseBase):
+    def testDefaultOff(self):
+        @vdscli.request_confirmation
+        def foobar():
+            return 101
+
+        self.assertEquals(foobar(), 101)
+
+    @MonkeyPatch(vdscli, 'REQUEST_CONFIRMATION', True)
+    @MonkeyPatch(sys, 'stdin', StringIO.StringIO('n\n'))
+    def testDenied(self):
+        lst = []
+
+        @vdscli.request_confirmation
+        def appent_to_lst():
+            lst.append(1)
+
+        try:
+            appent_to_lst()
+        except SystemExit:
+            pass
+        self.assertEquals(lst, [])
+
+    @MonkeyPatch(vdscli, 'REQUEST_CONFIRMATION', True)
+    @MonkeyPatch(sys, 'stdin', StringIO.StringIO('Y\n'))
+    def testConfirmed(self):
+        lst = []
+
+        @vdscli.request_confirmation
+        def appent_to_lst():
+            lst.append(1)
+
+        try:
+            appent_to_lst()
+        except SystemExit:
+            pass
+        self.assertEquals(lst, [1])


-- 
To view, visit http://gerrit.ovirt.org/28174
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Idea34ad7c3d5b66993bcb56b61e7edb0549ef9fb
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Dima Kuznetsov <dkuzn...@redhat.com>
_______________________________________________
vdsm-patches mailing list
vdsm-patches@lists.fedorahosted.org
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to