diff --git a/Ganeti/OpCodes.hs b/Ganeti/OpCodes.hs
new file mode 100644
index 0000000000000000000000000000000000000000..8954d50bc050c67b111512e52bc69b0e5c0d1ddf
--- /dev/null
+++ b/Ganeti/OpCodes.hs
@@ -0,0 +1,137 @@
+{-| Implementation of the opcodes.
+
+-}
+
+{-
+
+Copyright (C) 2009 Google Inc.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.
+
+-}
+
+module Ganeti.OpCodes
+ ( OpCode(..)
+ , ReplaceDisksMode(..)
+ , opID
+ ) where
+
+import Data.List
+import Control.Monad
+import Text.JSON (JSObject, JSValue, readJSON, showJSON, makeObj, JSON)
+import qualified Text.JSON as J
+import Text.JSON.Types
+
+import Ganeti.HTools.Utils
+
+data ReplaceDisksMode = ReplaceOnPrimary
+ | ReplaceOnSecondary
+ | ReplaceNewSecondary
+ | ReplaceAuto
+ deriving Show
+
+instance JSON ReplaceDisksMode where
+ showJSON m = case m of
+ ReplaceOnPrimary -> showJSON "replace_on_primary"
+ ReplaceOnSecondary -> showJSON "replace_on_secondary"
+ ReplaceNewSecondary -> showJSON "replace_new_secondary"
+ ReplaceAuto -> showJSON "replace_auto"
+ readJSON s = case readJSON s of
+ J.Ok "replace_on_primary" -> J.Ok ReplaceOnPrimary
+ J.Ok "replace_on_secondary" -> J.Ok ReplaceOnSecondary
+ J.Ok "replace_new_secondary" -> J.Ok ReplaceNewSecondary
+ J.Ok "replace_auto" -> J.Ok ReplaceAuto
+ _ -> J.Error "Can't parse a valid ReplaceDisksMode"
+
+data OpCode = OpTestDelay Double Bool [String]
+ | OpReplaceDisks String (Maybe String) ReplaceDisksMode
+ [Int] (Maybe String)
+ | OpFailoverInstance String Bool
+ | OpMigrateInstance String Bool Bool
+ deriving Show
+
+
+opID :: OpCode -> String
+opID (OpTestDelay _ _ _) = "OP_TEST_DELAY"
+opID (OpReplaceDisks _ _ _ _ _) = "OP_INSTANCE_REPLACE_DISKS"
+opID (OpFailoverInstance _ _) = "OP_INSTANCE_FAILOVER"
+opID (OpMigrateInstance _ _ _) = "OP_INSTANCE_MIGRATE"
+
+loadOpCode :: JSValue -> J.Result OpCode
+loadOpCode v = do
+ o <- readJSON v::J.Result (JSObject JSValue)
+ op_id <- fromObj "OP_ID" o
+ case op_id of
+ "OP_TEST_DELAY" -> do
+ on_nodes <- fromObj "on_nodes" o
+ on_master <- fromObj "on_master" o
+ duration <- fromObj "duration" o
+ return $ OpTestDelay duration on_master on_nodes
+ "OP_INSTANCE_REPLACE_DISKS" -> do
+ inst <- fromObj "instance_name" o
+ node <- fromObj "remote_node" o
+ mode <- fromObj "mode" o
+ disks <- fromObj "disks" o
+ ialloc <- fromObj "iallocator" o
+ return $ OpReplaceDisks inst node mode disks ialloc
+ "OP_INSTANCE_FAILOVER" -> do
+ inst <- fromObj "instance_name" o
+ consist <- fromObj "ignore_consistency" o
+ return $ OpFailoverInstance inst consist
+ "OP_INSTANCE_MIGRATE" -> do
+ inst <- fromObj "instance_name" o
+ live <- fromObj "live" o
+ cleanup <- fromObj "cleanup" o
+ return $ OpMigrateInstance inst live cleanup
+ _ -> J.Error $ "Unknown opcode " ++ op_id
+
+saveOpCode :: OpCode -> JSValue
+saveOpCode op@(OpTestDelay duration on_master on_nodes) =
+ let ol = [ ("OP_ID", showJSON $ opID op)
+ , ("duration", showJSON duration)
+ , ("on_master", showJSON on_master)
+ , ("on_nodes", showJSON on_nodes) ]
+ in makeObj ol
+
+saveOpCode op@(OpReplaceDisks inst node mode disks iallocator) =
+ let ol = [ ("OP_ID", showJSON $ opID op)
+ , ("instance_name", showJSON inst)
+ , ("mode", showJSON mode)
+ , ("disks", showJSON disks)]
+ ol2 = case node of
+ Just n -> ("remote_node", showJSON n):ol
+ Nothing -> ol
+ ol3 = case iallocator of
+ Just i -> ("iallocator", showJSON i):ol2
+ Nothing -> ol2
+ in makeObj ol3
+
+saveOpCode op@(OpFailoverInstance inst consist) =
+ let ol = [ ("OP_ID", showJSON $ opID op)
+ , ("instance_name", showJSON inst)
+ , ("ignore_consistency", showJSON consist) ]
+ in makeObj ol
+
+saveOpCode op@(OpMigrateInstance inst live cleanup) =
+ let ol = [ ("OP_ID", showJSON $ opID op)
+ , ("instance_name", showJSON inst)
+ , ("live", showJSON live)
+ , ("cleanup", showJSON cleanup) ]
+ in makeObj ol
+
+instance JSON OpCode where
+ readJSON = loadOpCode
+ showJSON = saveOpCode