These functions now make RPCs to WConfd
instead of locking the config.

Signed-off-by: BSRK Aditya <[email protected]>
---
 lib/config/__init__.py                   |   26 +++---
 src/Ganeti/WConfd/ConfigModifications.hs |  137 ++++++++++++++++++++++++++++--
 2 files changed, 140 insertions(+), 23 deletions(-)

diff --git a/lib/config/__init__.py b/lib/config/__init__.py
index ec1ce51..220f50d 100644
--- a/lib/config/__init__.py
+++ b/lib/config/__init__.py
@@ -376,25 +376,21 @@ class ConfigWriter(object):
     instance.serial_no += 1
     instance.mtime = time.time()
 
-  @ConfigSync()
   def AddInstanceDisk(self, inst_uuid, disk, idx=None, replace=False):
-    """Add a disk to the config and attach it to instance.
-
-    This is a simple wrapper over L{_UnlockedAddDisk} and
-    L{_UnlockedAttachInstanceDisk}.
+    """Add a disk to the config and attach it to instance."""
+    if not isinstance(disk, objects.Disk):
+      raise errors.ProgrammerError("Invalid type passed to AddInstanceDisk")
 
-    """
-    self._UnlockedAddDisk(disk, replace=replace)
-    self._UnlockedAttachInstanceDisk(inst_uuid, disk.uuid, idx)
+    disk.UpgradeConfig()
+    utils.SimpleRetry(True, self._wconfd.AddInstanceDisk, 0.1, 30,
+                      args=[inst_uuid, disk.ToDict(), idx, replace])
+    self.OutDate()
 
-  @ConfigSync()
   def AttachInstanceDisk(self, inst_uuid, disk_uuid, idx=None):
-    """Attach an existing disk to an instance.
-
-    This is a simple wrapper over L{_UnlockedAttachInstanceDisk}.
-
-    """
-    self._UnlockedAttachInstanceDisk(inst_uuid, disk_uuid, idx)
+    """Attach an existing disk to an instance."""
+    utils.SimpleRetry(True, self._wconfd.AttachInstanceDisk, 0.1, 30,
+                      args=[inst_uuid, disk_uuid, idx])
+    self.OutDate()
 
   def _UnlockedDetachInstanceDisk(self, inst_uuid, disk_uuid):
     """Detach a disk from an instance.
diff --git a/src/Ganeti/WConfd/ConfigModifications.hs 
b/src/Ganeti/WConfd/ConfigModifications.hs
index c51b4b1..8a69599 100644
--- a/src/Ganeti/WConfd/ConfigModifications.hs
+++ b/src/Ganeti/WConfd/ConfigModifications.hs
@@ -39,28 +39,43 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 module Ganeti.WConfd.ConfigModifications where
 
-import Control.Lens.Setter ((.~))
+import Control.Lens.Setter ((.~), (%~))
 import Control.Lens.Traversal (mapMOf)
-import Control.Monad (unless)
+import Control.Monad (unless, when, forM_)
 import Control.Monad.IO.Class (liftIO)
-import Data.Maybe (isJust, maybeToList)
+import Data.Maybe (isJust, maybeToList, fromMaybe)
 import Language.Haskell.TH (Name)
-import System.Time (getClockTime)
+import System.Time (getClockTime, ClockTime)
 import Text.Printf (printf)
 import qualified Data.Map as M
 import qualified Data.Set as S
 
-import Ganeti.BasicTypes (GenericResult(..), toError)
+import Ganeti.BasicTypes (GenericResult(..), genericResult, toError)
 import Ganeti.Errors (GanetiException(..))
-import Ganeti.JSON (GenericContainer(..), alterContainerL)
+import Ganeti.JSON (Container, GenericContainer(..), alterContainerL
+                   , lookupContainer, MaybeForJSON(..))
 import Ganeti.Locking.Locks (ClientId, ciIdentifier)
-import Ganeti.Logging.Lifted (logDebug)
+import Ganeti.Logging.Lifted (logDebug, logInfo)
 import Ganeti.Objects
 import Ganeti.Objects.Lens
 import Ganeti.WConfd.ConfigState (ConfigState, csConfigData, csConfigDataL)
 import Ganeti.WConfd.Monad (WConfdMonad, modifyConfigWithLock)
 import qualified Ganeti.WConfd.TempRes as T
 
+type DiskUUID = String
+type InstanceUUID = String
+
+-- * accessor functions
+
+getInstanceByUUID :: ConfigState
+                  -> InstanceUUID
+                  -> GenericResult GanetiException Instance
+getInstanceByUUID cs uuid = lookupContainer
+  (Bad . ConfigurationError $
+    printf "Could not find instance with UUID %s" uuid)
+  uuid
+  (configInstances . csConfigData $ cs)
+
 -- * getters
 
 -- | Gets all logical volumes in the cluster
@@ -89,7 +104,7 @@ getAllIDs cs =
 
       instKeys = keysFromC . configInstances . csConfigData $ cs
       nodeKeys = keysFromC . configNodes . csConfigData $ cs
-      
+
       instValues = map uuidOf . valuesFromC
                  . configInstances . csConfigData $ cs
       nodeValues = map uuidOf . valuesFromC . configNodes . csConfigData $ cs
@@ -158,6 +173,79 @@ addInstanceChecks inst replace cs = do
              "Cannot replace %s: UUID %s not present"
              (show $ instName inst) (instUuid inst)
 
+addDiskChecks :: Disk
+              -> Bool
+              -> ConfigState
+              -> GenericResult GanetiException ()
+addDiskChecks disk replace cs =
+  if replace
+    then do
+      let check = checkUUIDpresent cs disk
+      unless check . Bad . ConfigurationError $ printf
+             "Cannot add %s: UUID %s already in use"
+             (show $ diskName disk) (diskUuid disk)
+    else do
+      let check = checkUniqueUUID cs disk
+      unless check . Bad . ConfigurationError $ printf
+             "Cannot replace %s: UUID %s not present"
+             (show $ diskName disk) (diskUuid disk)
+
+attachInstanceDiskChecks :: InstanceUUID
+                         -> DiskUUID
+                         -> MaybeForJSON Int
+                         -> ConfigState
+                         -> GenericResult GanetiException ()
+attachInstanceDiskChecks uuidInst uuidDisk idx' cs = do
+  let diskPresent = elem uuidDisk . map diskUuid . M.elems
+                  . fromContainer . configDisks . csConfigData $ cs
+  unless diskPresent . Bad . ConfigurationError $ printf
+    "Disk %s doesn't exist" uuidDisk
+
+  inst <- getInstanceByUUID cs uuidInst
+  let numDisks = length $ instDisks inst
+      idx = fromMaybe numDisks (unMaybeForJSON idx')
+
+  when (idx < 0) . Bad . GenericError $
+    "Not accepting negative indices other than -1"
+  when (idx > numDisks) . Bad . GenericError $ printf
+    "Got disk index %d, but there are only %d" idx numDisks
+
+  let insts = M.elems . fromContainer . configInstances . csConfigData $ cs
+  forM_ insts (\inst' -> when (uuidDisk `elem` instDisks inst') . Bad
+    . ReservationError $ printf "Disk %s already attached to instance %s"
+        uuidDisk (show $ instName inst))
+
+-- * Pure config modifications functions
+
+attachInstanceDisk' :: InstanceUUID
+                    -> DiskUUID
+                    -> MaybeForJSON Int
+                    -> ClockTime
+                    -> ConfigState
+                    -> ConfigState
+attachInstanceDisk' iUuid dUuid idx' ct cs =
+  let inst = genericResult (error "impossible") id (getInstanceByUUID cs iUuid)
+      numDisks = length $ instDisks inst
+      idx = fromMaybe numDisks (unMaybeForJSON idx')
+
+      insert = instDisksL %~ (\ds -> take idx ds ++ [dUuid] ++ drop idx ds)
+      incr = instSerialL %~ (+ 1)
+      time = instMtimeL .~ ct
+
+      inst' = time . incr . insert $ inst
+      disks = updateIvNames idx inst' (configDisks . csConfigData $ cs)
+
+      ri = csConfigDataL . configInstancesL
+         . alterContainerL iUuid .~ Just inst'
+      rds = csConfigDataL . configDisksL .~ disks
+  in rds . ri $ cs
+    where updateIvNames :: Int -> Instance -> Container Disk -> Container Disk
+          updateIvNames idx inst (GenericContainer m) =
+            let dUuids = drop idx (instDisks inst)
+                upgradeIv m' (idx'', dUuid') =
+                  M.adjust (diskIvNameL .~ "disk/" ++ show idx'') dUuid' m'
+            in GenericContainer $ foldl upgradeIv m (zip [idx..] dUuids)
+
 -- * RPCs
 
 -- | Add a new instance to the configuration, release DRBD minors,
@@ -183,8 +271,41 @@ addInstance inst cid replace = do
   logDebug $ "AddInstance: result of config modification is " ++ show r
   return $ isJust r
 
+addInstanceDisk :: InstanceUUID
+                -> Disk
+                -> MaybeForJSON Int
+                -> Bool
+                -> WConfdMonad Bool
+addInstanceDisk iUuid disk idx replace = do
+  logInfo $ printf "Adding disk %s to configuration" (diskUuid disk)
+  ct <- liftIO getClockTime
+  let addD = csConfigDataL . configDisksL . alterContainerL (uuidOf disk)
+               .~ Just disk
+      incrSerialNo = csConfigDataL . configSerialL %~ (+1)
+  r <- modifyConfigWithLock (\_ cs -> do
+           toError $ addDiskChecks disk replace cs
+           let cs' = incrSerialNo . addD $ cs
+           toError $ attachInstanceDiskChecks iUuid (diskUuid disk) idx cs'
+           return $ attachInstanceDisk' iUuid (diskUuid disk) idx ct cs')
+       . T.releaseDRBDMinors $ uuidOf disk
+  return $ isJust r
+
+attachInstanceDisk :: InstanceUUID
+                   -> DiskUUID
+                   -> MaybeForJSON Int
+                   -> WConfdMonad Bool
+attachInstanceDisk iUuid dUuid idx = do
+  ct <- liftIO getClockTime
+  r <- modifyConfigWithLock (\_ cs -> do
+           toError $ attachInstanceDiskChecks iUuid dUuid idx cs
+           return $ attachInstanceDisk' iUuid dUuid idx ct cs)
+       (return ())
+  return $ isJust r
+
 -- * The list of functions exported to RPC.
 
 exportedFunctions :: [Name]
 exportedFunctions = [ 'addInstance
+                    , 'addInstanceDisk
+                    , 'attachInstanceDisk
                     ]
-- 
1.7.10.4

Reply via email to