Modify Haskell code to accept the attach/detach action and the "UUID"
disk parameter. Also, modify the _ConvertNicDiskModifications function
to accept the new DDM_ATTACH/DDM_DETACH values. Finally, do minor
changes in Python code and tests in order to make the tests pass.

Signed-off-by: Alex Pyrgiotis <[email protected]>

diff --git a/lib/client/gnt_instance.py b/lib/client/gnt_instance.py
index b93ffa0..1a589ea 100644
--- a/lib/client/gnt_instance.py
+++ b/lib/client/gnt_instance.py
@@ -1256,37 +1256,59 @@ def _ConvertNicDiskModifications(mods):
       # Add item as last item (legacy interface)
       action = constants.DDM_ADD
       identifier = -1
+    elif identifier == constants.DDM_ATTACH:
+      # Attach item as last item (legacy interface)
+      action = constants.DDM_ATTACH
+      identifier = -1
     elif identifier == constants.DDM_REMOVE:
       # Remove last item (legacy interface)
       action = constants.DDM_REMOVE
       identifier = -1
+    elif identifier == constants.DDM_DETACH:
+      # Detach last item (legacy interface)
+      action = constants.DDM_DETACH
+      identifier = -1
     else:
-      # Modifications and adding/removing at arbitrary indices
+      # Modifications and adding/attaching/removing/detaching at arbitrary
+      # indices
       add = params.pop(constants.DDM_ADD, _MISSING)
+      attach = params.pop(constants.DDM_ATTACH, _MISSING)
       remove = params.pop(constants.DDM_REMOVE, _MISSING)
+      detach = params.pop(constants.DDM_DETACH, _MISSING)
       modify = params.pop(constants.DDM_MODIFY, _MISSING)
 
       if modify is _MISSING:
-        if not (add is _MISSING or remove is _MISSING):
-          raise errors.OpPrereqError("Cannot add and remove at the same time",
-                                     errors.ECODE_INVAL)
-        elif add is not _MISSING:
-          action = constants.DDM_ADD
-        elif remove is not _MISSING:
-          action = constants.DDM_REMOVE
-        else:
-          action = constants.DDM_MODIFY
-
-      elif add is _MISSING and remove is _MISSING:
+        # Check if the user has requested more than one operation and raise an
+        # exception. If no operations have been given, default to modify.
+        action = constants.DDM_MODIFY
+        ops = {
+          constants.DDM_ADD: add,
+          constants.DDM_ATTACH: attach,
+          constants.DDM_REMOVE: remove,
+          constants.DDM_DETACH: detach
+        }
+        count = 0
+        for op, param in ops.items():
+          if param is not _MISSING:
+            count += 1
+            action = op
+        if count > 1:
+          raise errors.OpPrereqError(
+            "Cannot do more than one of the following operations at the"
+            " same time: %s" % ", ".join(ops.keys()),
+            errors.ECODE_INVAL)
+
+      elif (add is _MISSING and attach is _MISSING and remove is _MISSING and
+            detach is _MISSING):
         action = constants.DDM_MODIFY
       else:
-        raise errors.OpPrereqError("Cannot modify and add/remove at the"
-                                   " same time", errors.ECODE_INVAL)
+        raise errors.OpPrereqError("Cannot modify and add/attach/remove/detach"
+                                   " at the same time", errors.ECODE_INVAL)
 
       assert not (constants.DDMS_VALUES_WITH_MODIFY & set(params.keys()))
 
-    if action == constants.DDM_REMOVE and params:
-      raise errors.OpPrereqError("Not accepting parameters on removal",
+    if action in (constants.DDM_REMOVE, constants.DDM_DETACH) and params:
+      raise errors.OpPrereqError("Not accepting parameters on removal/detach",
                                  errors.ECODE_INVAL)
 
     result.append((action, identifier, params))
diff --git a/src/Ganeti/Constants.hs b/src/Ganeti/Constants.hs
index ada0549..bbe0f1b 100644
--- a/src/Ganeti/Constants.hs
+++ b/src/Ganeti/Constants.hs
@@ -1195,14 +1195,20 @@ inisectOspPrivate = "os_private"
 ddmAdd :: String
 ddmAdd = Types.ddmFullToRaw DdmFullAdd
 
+ddmAttach :: String
+ddmAttach = Types.ddmFullToRaw DdmFullAttach
+
 ddmModify :: String
 ddmModify = Types.ddmFullToRaw DdmFullModify
 
 ddmRemove :: String
 ddmRemove = Types.ddmFullToRaw DdmFullRemove
 
+ddmDetach :: String
+ddmDetach = Types.ddmFullToRaw DdmFullDetach
+
 ddmsValues :: FrozenSet String
-ddmsValues = ConstantUtils.mkSet [ddmAdd, ddmRemove]
+ddmsValues = ConstantUtils.mkSet [ddmAdd, ddmAttach, ddmRemove, ddmDetach]
 
 ddmsValuesWithModify :: FrozenSet String
 ddmsValuesWithModify = ConstantUtils.mkSet $ map Types.ddmFullToRaw 
[minBound..]
diff --git a/src/Ganeti/Types.hs b/src/Ganeti/Types.hs
index bc804fb..57de8fb 100644
--- a/src/Ganeti/Types.hs
+++ b/src/Ganeti/Types.hs
@@ -430,7 +430,9 @@ $(THH.makeJSONInstance ''CVErrorCode)
 -- | Dynamic device modification, just add/remove version.
 $(THH.declareLADT ''String "DdmSimple"
      [ ("DdmSimpleAdd",    "add")
+     , ("DdmSimpleAttach", "attach")
      , ("DdmSimpleRemove", "remove")
+     , ("DdmSimpleDetach", "detach")
      ])
 $(THH.makeJSONInstance ''DdmSimple)
 
@@ -439,7 +441,9 @@ $(THH.makeJSONInstance ''DdmSimple)
 -- TODO: DDM_SWAP, DDM_MOVE?
 $(THH.declareLADT ''String "DdmFull"
      [ ("DdmFullAdd",    "add")
+     , ("DdmFullAttach", "attach")
      , ("DdmFullRemove", "remove")
+     , ("DdmFullDetach", "detach")
      , ("DdmFullModify", "modify")
      ])
 $(THH.makeJSONInstance ''DdmFull)
-- 
1.7.10.4

Reply via email to