This patch extends 'gnt-instance modify' by allowing a user to remove a
list of public/private OS parameters from an instance. This can be
useful before performing a reinstall to a new OS provider. Example
usage:

$ gnt-instance modify --remove-os-parameters parm1,parm2 <instance_name>

or

$ gnt-instance modify --remove-os-parameters-private parm3 <instance_name>

Signed-off-by: Yiannis Tsiouris <ts...@grnet.gr>
---
 lib/cli_opts.py                   | 17 +++++++++++++++++
 lib/client/gnt_instance.py        | 16 +++++++++++++++-
 lib/cmdlib/instance_set_params.py | 28 +++++++++++++++++++++++++---
 man/gnt-instance.rst              |  7 ++++++-
 src/Ganeti/OpCodes.hs             |  2 ++
 src/Ganeti/OpParams.hs            | 12 ++++++++++++
 test/hs/Test/Ganeti/OpCodes.hs    |  2 ++
 7 files changed, 79 insertions(+), 5 deletions(-)

diff --git a/lib/cli_opts.py b/lib/cli_opts.py
index 3faf2bf..1624910 100644
--- a/lib/cli_opts.py
+++ b/lib/cli_opts.py
@@ -221,6 +221,8 @@ __all__ = [
   "REASON_OPT",
   "REBOOT_TYPE_OPT",
   "REMOVE_INSTANCE_OPT",
+  "REMOVE_OSPARAMS_OPT",
+  "REMOVE_OSPARAMS_PRIVATE_OPT",
   "REMOVE_RESERVED_IPS_OPT",
   "REMOVE_UIDS_OPT",
   "RESERVED_LVS_OPT",
@@ -744,6 +746,21 @@ CLEAR_OSPARAMS_PRIVATE_OPT = 
cli_option("--clear-os-parameters-private",
                                         help="Clear current private OS"
                                              " parameters")
 
+REMOVE_OSPARAMS_OPT = cli_option("--remove-os-parameters",
+                                 dest="remove_osparams",
+                                 type="list",
+                                 default=None,
+                                 help="Comma-separated list of OS parameters"
+                                      " that should be removed")
+
+REMOVE_OSPARAMS_PRIVATE_OPT = cli_option("--remove-os-parameters-private",
+                                         dest="remove_osparams_private",
+                                         type="list",
+                                         default=None,
+                                         help="Comma-separated list of private"
+                                              " OS parameters that should be"
+                                              " removed")
+
 FORCE_VARIANT_OPT = cli_option("--force-variant", dest="force_variant",
                                action="store_true", default=False,
                                help="Force an unknown variant")
diff --git a/lib/client/gnt_instance.py b/lib/client/gnt_instance.py
index f6effd0..bc4482b 100644
--- a/lib/client/gnt_instance.py
+++ b/lib/client/gnt_instance.py
@@ -1372,6 +1372,7 @@ def SetInstanceParams(opts, args):
   if not (opts.nics or opts.disks or opts.disk_template or opts.hvparams or
           opts.beparams or opts.os or opts.osparams or opts.osparams_private
           or opts.clear_osparams or opts.clear_osparams_private
+          or opts.remove_osparams or opts.remove_osparams_private
           or opts.offline_inst or opts.online_inst or opts.runtime_mem or
           opts.new_primary_node or opts.instance_communication is not None):
     ToStderr("Please give at least one of the parameters.")
@@ -1436,7 +1437,17 @@ def SetInstanceParams(opts, args):
 
   instance_comm = opts.instance_communication
 
+  if opts.clear_osparams and opts.remove_osparams is not None:
+    raise errors.OpPrereqError("Using --remove-os-parameters with "
+      "--clear-os-parameters is not possible", errors.ECODE_INVAL)
+
+  if opts.clear_osparams_private and opts.remove_osparams_private is not None:
+    raise errors.OpPrereqError("Using --remove-os-parameters-private with "
+      "--clear-os-parameters-private is not possible", errors.ECODE_INVAL)
+
   clear_osparams_priv = opts.clear_osparams_private
+  remove_osparams = opts.remove_osparams or []
+  remove_osps_priv = opts.remove_osparams_private or []
 
   op = opcodes.OpInstanceSetParams(instance_name=args[0],
                                    nics=nics,
@@ -1458,6 +1469,8 @@ def SetInstanceParams(opts, args):
                                    osparams_private=opts.osparams_private,
                                    clear_osparams=opts.clear_osparams,
                                    clear_osparams_private=clear_osparams_priv,
+                                   remove_osparams=remove_osparams,
+                                   remove_osparams_private=remove_osps_priv,
                                    force_variant=opts.force_variant,
                                    force=opts.force,
                                    wait_for_sync=opts.wait_for_sync,
@@ -1674,7 +1687,8 @@ commands = {
      NOCONFLICTSCHECK_OPT, NEW_PRIMARY_OPT, HOTPLUG_OPT,
      HOTPLUG_IF_POSSIBLE_OPT, INSTANCE_COMMUNICATION_OPT,
      EXT_PARAMS_OPT, FILESTORE_DRIVER_OPT, FILESTORE_DIR_OPT,
-     CLEAR_OSPARAMS_OPT, CLEAR_OSPARAMS_PRIVATE_OPT],
+     CLEAR_OSPARAMS_OPT, CLEAR_OSPARAMS_PRIVATE_OPT,
+     REMOVE_OSPARAMS_OPT, REMOVE_OSPARAMS_PRIVATE_OPT],
     "<instance>", "Alters the parameters of an instance"),
   "shutdown": (
     GenericManyOps("shutdown", _ShutdownInstance), [ArgInstance()],
diff --git a/lib/cmdlib/instance_set_params.py 
b/lib/cmdlib/instance_set_params.py
index b4553c8..6b9a2ba 100644
--- a/lib/cmdlib/instance_set_params.py
+++ b/lib/cmdlib/instance_set_params.py
@@ -338,6 +338,7 @@ class LUInstanceSetParams(LogicalUnit):
             self.op.osparams or self.op.offline is not None or
             self.op.runtime_mem or self.op.pnode or self.op.osparams_private or
             self.op.clear_osparams or self.op.clear_osparams_private or
+            self.op.remove_osparams or self.op.remove_osparams_private or
             self.op.instance_communication is not None):
       raise errors.OpPrereqError("No changes submitted", errors.ECODE_INVAL)
 
@@ -993,9 +994,12 @@ class LUInstanceSetParams(LogicalUnit):
                    else self.instance.os)
 
     if (self.op.osparams or self.op.osparams_private or
-        self.op.clear_osparams or self.op.clear_osparams_private):
+        self.op.clear_osparams or self.op.clear_osparams_private or
+        self.op.remove_osparams or self.op.remove_osparams_private):
       public_parms = self.op.osparams or {}
       private_parms = self.op.osparams_private or {}
+      remove_osparams = self.op.remove_osparams or []
+      remove_osparams_private = self.op.remove_osparams_private or []
       self.os_inst_removed = self.os_inst_private_removed = []
       dupe_keys = utils.GetRepeatedKeys(public_parms, private_parms)
 
@@ -1011,6 +1015,24 @@ class LUInstanceSetParams(LogicalUnit):
         self.os_inst_private_removed = self.instance.osparams_private
         self.instance.osparams_private = {}
 
+      for osp in remove_osparams:
+        if osp in public_parms:
+          raise errors.OpPrereqError("Requested both removal and addition of "
+                                     "param %s" % osp)
+
+        if osp in self.instance.osparams:
+          self.os_inst_removed.append(osp)
+          del self.instance.osparams[osp]
+
+      for osp in remove_osparams_private:
+        if osp in private_parms:
+          raise errors.OpPrereqError("Requested both removal and addition of "
+                                     "param %s" % osp)
+
+        if osp in self.instance.osparams_private:
+          self.os_inst_private_removed.append(osp)
+          del self.instance.osparams_private[osp]
+
       self.os_inst = GetUpdatedParams(self.instance.osparams,
                                       public_parms)
       self.os_inst_private = GetUpdatedParams(self.instance.osparams_private,
@@ -1966,12 +1988,12 @@ class LUInstanceSetParams(LogicalUnit):
       self.instance.os = self.op.os_name
 
     # osparams changes
-    if self.op.clear_osparams:
+    if self.op.clear_osparams or self.op.remove_osparams:
       self.instance.osparams = self.os_inst
       for osp in self.os_inst_removed:
         result.append(("os/%s" % osp, "<removed>"))
 
-    if self.op.clear_osparams_private:
+    if self.op.clear_osparams_private or self.op.remove_osparams_private:
       self.instance.osparams_private = self.os_inst_private
       for osp in self.os_inst_private_removed:
         result.append(("os_private/%s" % osp, "<removed>"))
diff --git a/man/gnt-instance.rst b/man/gnt-instance.rst
index 8408a8f..f1e2640 100644
--- a/man/gnt-instance.rst
+++ b/man/gnt-instance.rst
@@ -1380,6 +1380,8 @@ MODIFY
 | [--os-parameters-private *param*=*value*... ]
 | [--clear-os-parameters]
 | [--clear-os-parameters-private]
+| [--remove-os-parameters *param*[,*param*...]]
+| [--remove-os-parameters-private *param*[,*param*...]]
 | [\--offline \| \--online]
 | [\--submit] [\--print-jobid]
 | [\--ignore-ipolicy]
@@ -1399,7 +1401,10 @@ which options can be specified, see the **add** command.
 
 The ``--clear-os-parameters`` option will clear all current (public)
 instance OS parameters and the ``--clear-os-parameters-private`` will
-clear all current private OS parameters.
+clear all current private OS parameters. Similarly, the
+``--remove-os-parameters`` option will clear only the specified
+parameters and the ``--remove-os-parameters-private`` will clear only
+the specified private OS parameters.
 
 The ``-t (--disk-template)`` option will change the disk template of
 the instance.  Currently, conversions between all the available
diff --git a/src/Ganeti/OpCodes.hs b/src/Ganeti/OpCodes.hs
index c26a085..d792190 100644
--- a/src/Ganeti/OpCodes.hs
+++ b/src/Ganeti/OpCodes.hs
@@ -722,6 +722,8 @@ $(genOpCode "OpCode"
      , pInstOsParamsPrivate
      , pInstOsParamsClear
      , pInstOsParamsPrivateClear
+     , pInstOsParamsRemove
+     , pInstOsParamsPrivateRemove
      , pWaitForSync
      , withDoc "Whether to mark the instance as offline" pOffline
      , pIpConflictsCheck
diff --git a/src/Ganeti/OpParams.hs b/src/Ganeti/OpParams.hs
index 2b4b70f..fc0cef5 100644
--- a/src/Ganeti/OpParams.hs
+++ b/src/Ganeti/OpParams.hs
@@ -141,6 +141,8 @@ module Ganeti.OpParams
   , pInstOsParamsSecret
   , pInstOsParamsClear
   , pInstOsParamsPrivateClear
+  , pInstOsParamsRemove
+  , pInstOsParamsPrivateRemove
   , pCandidatePoolSize
   , pMaxRunningJobs
   , pMaxTrackedJobs
@@ -1260,6 +1262,16 @@ pInstOsParamsPrivateClear =
   withDoc "Clear current private OS parameters from instance" $
   defaultFalse "clear_osparams_private"
 
+pInstOsParamsRemove :: Field
+pInstOsParamsRemove =
+  withDoc "Remove OS parameters from instance" .
+  optionalField $ simpleField "remove_osparams" [t| [String] |]
+
+pInstOsParamsPrivateRemove :: Field
+pInstOsParamsPrivateRemove =
+  withDoc "Remove private OS parameters from instance" .
+  optionalField $ simpleField "remove_osparams_private" [t| [String] |]
+
 pPrimaryNode :: Field
 pPrimaryNode =
   withDoc "Primary node for an instance" $
diff --git a/test/hs/Test/Ganeti/OpCodes.hs b/test/hs/Test/Ganeti/OpCodes.hs
index 96402c5..2d7078c 100644
--- a/test/hs/Test/Ganeti/OpCodes.hs
+++ b/test/hs/Test/Ganeti/OpCodes.hs
@@ -433,6 +433,8 @@ genOpCodeFromId op_id =
         <*> genMaybe arbitraryPrivateJSObj  -- osparams_private
         <*> arbitrary                       -- clear_osparams
         <*> arbitrary                       -- clear_osparams_private
+        <*> genMaybe (listOf genPrintableAsciiString) -- remove_osparams
+        <*> genMaybe (listOf genPrintableAsciiString) -- 
remove_osparams_private
         <*> arbitrary                       -- wait_for_sync
         <*> arbitrary                       -- offline
         <*> arbitrary                       -- conflicts_check
-- 
2.10.2

Reply via email to