1 {-# LANGUAGE ExistentialQuantification, TemplateHaskell #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Implementation of the opcodes.
10 Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 , ReplaceDisksMode(..)
48 import Text.JSON (readJSON, JSObject, JSON, JSValue(..), makeObj, fromJSObject)
49 import qualified Text.JSON
53 import qualified Ganeti.Hs2Py.OpDoc as OpDoc
54 import Ganeti.OpParams
55 import Ganeti.PyValueInstances ()
57 import Ganeti.Query.Language (queryTypeOpToRaw)
59 import Data.List (intercalate)
62 import qualified Ganeti.Constants as C
64 instance PyValue DiskIndex where
65 showValue = showValue . unDiskIndex
67 instance PyValue IDiskParams where
68 showValue _ = error "OpCodes.showValue(IDiskParams): unhandled case"
70 instance PyValue RecreateDisksInfo where
71 showValue RecreateDisksAll = "[]"
72 showValue (RecreateDisksIndices is) = showValue is
73 showValue (RecreateDisksParams is) = showValue is
75 instance PyValue a => PyValue (SetParamsMods a) where
76 showValue SetParamsEmpty = "[]"
77 showValue _ = error "OpCodes.showValue(SetParamsMods): unhandled case"
79 instance PyValue a => PyValue (NonNegative a) where
80 showValue = showValue . fromNonNegative
82 instance PyValue a => PyValue (NonEmpty a) where
83 showValue = showValue . fromNonEmpty
85 -- FIXME: should use the 'toRaw' function instead of being harcoded or
86 -- perhaps use something similar to the NonNegative type instead of
87 -- using the declareSADT
88 instance PyValue ExportMode where
89 showValue ExportModeLocal = show C.exportModeLocal
90 showValue ExportModeRemote = show C.exportModeLocal
92 instance PyValue CVErrorCode where
93 showValue = cVErrorCodeToRaw
95 instance PyValue VerifyOptionalChecks where
96 showValue = verifyOptionalChecksToRaw
98 instance PyValue INicParams where
99 showValue = error "instance PyValue INicParams: not implemented"
101 instance PyValue a => PyValue (JSObject a) where
103 "{" ++ intercalate ", " (map showPair (fromJSObject obj)) ++ "}"
104 where showPair (k, v) = show k ++ ":" ++ showValue v
106 instance PyValue JSValue where
107 showValue (JSObject obj) = showValue obj
110 type JobIdListOnly = [(Bool, Either String JobId)]
112 type InstanceMultiAllocResponse =
113 ([(Bool, Either String JobId)], NonEmptyString)
116 (NonEmptyString, NonEmptyString, TagKind, NonEmptyString)
119 ([QueryFieldDef], [[(QueryResultCode, JSValue)]])
121 type QueryFieldsResponse = [QueryFieldDef]
123 -- | OpCode representation.
125 -- We only implement a subset of Ganeti opcodes: those which are actually used
126 -- in the htools codebase.
128 [ ("OpClusterPostInit",
130 OpDoc.opClusterPostInit,
133 , ("OpClusterDestroy",
134 [t| NonEmptyString |],
135 OpDoc.opClusterDestroy,
139 [t| JSObject JSValue |],
140 OpDoc.opClusterQuery,
143 , ("OpClusterVerify",
144 [t| JobIdListOnly |],
145 OpDoc.opClusterVerify,
146 [ pDebugSimulateErrors
154 , ("OpClusterVerifyConfig",
156 OpDoc.opClusterVerifyConfig,
157 [ pDebugSimulateErrors
163 , ("OpClusterVerifyGroup",
165 OpDoc.opClusterVerifyGroup,
167 , pDebugSimulateErrors
174 , ("OpClusterVerifyDisks",
175 [t| JobIdListOnly |],
176 OpDoc.opClusterVerifyDisks,
179 , ("OpGroupVerifyDisks",
180 [t| (Map String String, [String], Map String [[String]]) |],
181 OpDoc.opGroupVerifyDisks,
185 , ("OpClusterRepairDiskSizes",
186 [t| [(NonEmptyString, NonNegative Int, NonEmptyString, NonNegative Int)]|],
187 OpDoc.opClusterRepairDiskSizes,
191 , ("OpClusterConfigQuery",
193 OpDoc.opClusterConfigQuery,
197 , ("OpClusterRename",
198 [t| NonEmptyString |],
199 OpDoc.opClusterRename,
203 , ("OpClusterSetParams",
205 OpDoc.opClusterSetParams,
210 , pEnabledHypervisors
220 , pMaintainNodeHealth
223 , withDoc "Cluster-wide node parameter defaults" pNdParams
224 , withDoc "Cluster-wide ipolicy specs" pIpolicy
232 , pUseExternalMipScript
233 , pEnabledDiskTemplates
235 , pClusterFileStorageDir
236 , pClusterSharedFileStorageDir
239 , ("OpClusterRedistConf",
241 OpDoc.opClusterRedistConf,
244 , ("OpClusterActivateMasterIp",
246 OpDoc.opClusterActivateMasterIp,
249 , ("OpClusterDeactivateMasterIp",
251 OpDoc.opClusterDeactivateMasterIp,
255 [t| QueryResponse |],
264 [t| QueryFieldsResponse |],
271 [t| [[(QueryResultCode, JSValue)]] |],
274 , withDoc "List of node UUIDs to run the OOB command against" pNodeUuids
281 , ("OpRestrictedCommand",
282 [t| [(Bool, String)] |],
283 OpDoc.opRestrictedCommand,
286 "Nodes on which the command should be run (at least one)"
289 "Node UUIDs on which the command should be run (at least one)"
320 , withDoc "Empty list to query all nodes, node names otherwise" pNames
324 , ("OpNodeQueryvols",
326 OpDoc.opNodeQueryvols,
328 , withDoc "Empty list to query all nodes, node names otherwise" pNodes
331 , ("OpNodeQueryStorage",
333 OpDoc.opNodeQueryStorage,
337 "Empty list to query all, list of names to query otherwise"
342 , ("OpNodeModifyStorage",
344 OpDoc.opNodeModifyStorage,
352 , ("OpRepairNodeStorage",
354 OpDoc.opRepairNodeStorage,
362 , ("OpNodeSetParams",
363 [t| [(NonEmptyString, JSValue)] |],
364 OpDoc.opNodeSetParams,
371 , withDoc "Whether to mark the node offline" pOffline
381 , ("OpNodePowercycle",
382 [t| Maybe NonEmptyString |],
383 OpDoc.opNodePowercycle,
390 [t| JobIdListOnly |],
396 , pMigrationTargetNode
397 , pMigrationTargetNodeUuid
404 [t| JobIdListOnly |],
405 OpDoc.opNodeEvacuate,
415 , ("OpInstanceCreate",
416 [t| [NonEmptyString] |],
417 OpDoc.opInstanceCreate,
423 , pOpportunisticLocking
446 , pSourceShutdownTimeout
455 , ("OpInstanceMultiAlloc",
456 [t| InstanceMultiAllocResponse |],
457 OpDoc.opInstanceMultiAlloc,
458 [ pOpportunisticLocking
460 , pMultiAllocInstances
463 , ("OpInstanceReinstall",
465 OpDoc.opInstanceReinstall,
473 , ("OpInstanceRemove",
475 OpDoc.opInstanceRemove,
482 , ("OpInstanceRename",
483 [t| NonEmptyString |],
484 OpDoc.opInstanceRename,
487 , withDoc "New instance name" pNewName
492 , ("OpInstanceStartup",
494 OpDoc.opInstanceStartup,
498 , pIgnoreOfflineNodes
505 , ("OpInstanceShutdown",
507 OpDoc.opInstanceShutdown,
511 , pIgnoreOfflineNodes
516 , ("OpInstanceReboot",
518 OpDoc.opInstanceReboot,
526 , ("OpInstanceReplaceDisks",
528 OpDoc.opInstanceReplaceDisks,
540 , ("OpInstanceFailover",
542 OpDoc.opInstanceFailover,
547 , pMigrationTargetNode
548 , pMigrationTargetNodeUuid
554 , ("OpInstanceMigrate",
556 OpDoc.opInstanceMigrate,
561 , pMigrationTargetNode
562 , pMigrationTargetNodeUuid
572 OpDoc.opInstanceMove,
578 , pMoveTargetNodeUuid
582 , ("OpInstanceConsole",
583 [t| JSObject JSValue |],
584 OpDoc.opInstanceConsole,
589 , ("OpInstanceActivateDisks",
590 [t| [(NonEmptyString, NonEmptyString, NonEmptyString)] |],
591 OpDoc.opInstanceActivateDisks,
598 , ("OpInstanceDeactivateDisks",
600 OpDoc.opInstanceDeactivateDisks,
606 , ("OpInstanceRecreateDisks",
608 OpDoc.opInstanceRecreateDisks,
612 , withDoc "New instance nodes, if relocation is desired" pNodes
613 , withDoc "New instance node UUIDs, if relocation is desired" pNodeUuids
617 , ("OpInstanceQuery",
619 OpDoc.opInstanceQuery,
623 "Empty list to query all instances, instance names otherwise"
627 , ("OpInstanceQueryData",
628 [t| JSObject (JSObject JSValue) |],
629 OpDoc.opInstanceQueryData,
635 , ("OpInstanceSetParams",
636 [t| [(NonEmptyString, JSValue)] |],
637 OpDoc.opInstanceSetParams,
643 , pInstParamsNicChanges
644 , pInstParamsDiskChanges
651 , withDoc "Secondary node (used when changing disk template)" pRemoteNode
653 "Secondary node UUID (used when changing disk template)"
658 , withDoc "Whether to mark the instance as offline" pOffline
662 , ("OpInstanceGrowDisk",
664 OpDoc.opInstanceGrowDisk,
673 , ("OpInstanceChangeGroup",
674 [t| JobIdListOnly |],
675 OpDoc.opInstanceChangeGroup,
687 , pNodeGroupAllocPolicy
692 , withDoc "Group-wide ipolicy specs" pIpolicy
695 , ("OpGroupAssignNodes",
697 OpDoc.opGroupAssignNodes,
700 , withDoc "List of nodes to assign" pRequiredNodes
701 , withDoc "List of node UUIDs to assign" pRequiredNodeUuids
708 , withDoc "Empty list to query all groups, group names otherwise" pNames
711 , ("OpGroupSetParams",
712 [t| [(NonEmptyString, JSValue)] |],
713 OpDoc.opGroupSetParams,
715 , pNodeGroupAllocPolicy
720 , withDoc "Group-wide ipolicy specs" pIpolicy
730 [t| NonEmptyString |],
733 , withDoc "New group name" pNewName
736 , ("OpGroupEvacuate",
737 [t| JobIdListOnly |],
738 OpDoc.opGroupEvacuate,
749 , withDoc "Which operating systems to diagnose" pNames
752 , ("OpExtStorageDiagnose",
754 OpDoc.opExtStorageDiagnose,
756 , withDoc "Which ExtStorage Provider to diagnose" pNames
760 [t| JSObject (Either Bool [NonEmptyString]) |],
763 , withDoc "Empty list to query all nodes, node names otherwise" pNodes
766 , ("OpBackupPrepare",
767 [t| Maybe (JSObject JSValue) |],
768 OpDoc.opBackupPrepare,
775 [t| (Bool, [Bool]) |],
776 OpDoc.opBackupExport,
781 , pExportTargetNodeUuid
784 , pIgnoreRemoveFailures
785 , defaultField [| ExportModeLocal |] pExportMode
792 OpDoc.opBackupRemove,
798 [t| [NonEmptyString] |],
802 , withDoc "Name of object to retrieve tags from" pTagsName
806 [t| [(NonEmptyString, NonEmptyString)] |],
816 , withDoc "Name of object where tag(s) should be added" pTagsName
824 , withDoc "Name of object where tag(s) should be deleted" pTagsName
837 , ("OpTestAllocator",
839 OpDoc.opTestAllocator,
840 [ pIAllocatorDirection
852 , pIAllocatorInstances
853 , pIAllocatorEvacMode
855 , pIAllocatorSpindleUse
862 [ pJQueueNotifyWaitLock
874 , pTestDummySubmitJobs
888 , withDoc "Network tags" pInstTags
891 , ("OpNetworkRemove",
893 OpDoc.opNetworkRemove,
898 , ("OpNetworkSetParams",
900 OpDoc.opNetworkSetParams,
906 , withDoc "Which external IP addresses to reserve" pNetworkAddRsvdIps
907 , pNetworkRemoveRsvdIps
910 , ("OpNetworkConnect",
912 OpDoc.opNetworkConnect,
920 , ("OpNetworkDisconnect",
922 OpDoc.opNetworkDisconnect,
929 OpDoc.opNetworkQuery,
932 , withDoc "Empty list to query all groups, group names otherwise" pNames
937 -- | Returns the OP_ID for a given opcode value.
938 $(genOpID ''OpCode "opID")
940 -- | A list of all defined/supported opcode IDs.
941 $(genAllOpIDs ''OpCode "allOpIDs")
943 instance JSON OpCode where
944 readJSON = loadOpCode
945 showJSON = saveOpCode
947 -- | Generates the summary value for an opcode.
948 opSummaryVal :: OpCode -> Maybe String
949 opSummaryVal OpClusterVerifyGroup { opGroupName = s } = Just (fromNonEmpty s)
950 opSummaryVal OpGroupVerifyDisks { opGroupName = s } = Just (fromNonEmpty s)
951 opSummaryVal OpClusterRename { opName = s } = Just (fromNonEmpty s)
952 opSummaryVal OpQuery { opWhat = s } = Just (queryTypeOpToRaw s)
953 opSummaryVal OpQueryFields { opWhat = s } = Just (queryTypeOpToRaw s)
954 opSummaryVal OpNodeRemove { opNodeName = s } = Just (fromNonEmpty s)
955 opSummaryVal OpNodeAdd { opNodeName = s } = Just (fromNonEmpty s)
956 opSummaryVal OpNodeModifyStorage { opNodeName = s } = Just (fromNonEmpty s)
957 opSummaryVal OpRepairNodeStorage { opNodeName = s } = Just (fromNonEmpty s)
958 opSummaryVal OpNodeSetParams { opNodeName = s } = Just (fromNonEmpty s)
959 opSummaryVal OpNodePowercycle { opNodeName = s } = Just (fromNonEmpty s)
960 opSummaryVal OpNodeMigrate { opNodeName = s } = Just (fromNonEmpty s)
961 opSummaryVal OpNodeEvacuate { opNodeName = s } = Just (fromNonEmpty s)
962 opSummaryVal OpInstanceCreate { opInstanceName = s } = Just s
963 opSummaryVal OpInstanceReinstall { opInstanceName = s } = Just s
964 opSummaryVal OpInstanceRemove { opInstanceName = s } = Just s
965 -- FIXME: instance rename should show both names; currently it shows none
966 -- opSummaryVal OpInstanceRename { opInstanceName = s } = Just s
967 opSummaryVal OpInstanceStartup { opInstanceName = s } = Just s
968 opSummaryVal OpInstanceShutdown { opInstanceName = s } = Just s
969 opSummaryVal OpInstanceReboot { opInstanceName = s } = Just s
970 opSummaryVal OpInstanceReplaceDisks { opInstanceName = s } = Just s
971 opSummaryVal OpInstanceFailover { opInstanceName = s } = Just s
972 opSummaryVal OpInstanceMigrate { opInstanceName = s } = Just s
973 opSummaryVal OpInstanceMove { opInstanceName = s } = Just s
974 opSummaryVal OpInstanceConsole { opInstanceName = s } = Just s
975 opSummaryVal OpInstanceActivateDisks { opInstanceName = s } = Just s
976 opSummaryVal OpInstanceDeactivateDisks { opInstanceName = s } = Just s
977 opSummaryVal OpInstanceRecreateDisks { opInstanceName = s } = Just s
978 opSummaryVal OpInstanceSetParams { opInstanceName = s } = Just s
979 opSummaryVal OpInstanceGrowDisk { opInstanceName = s } = Just s
980 opSummaryVal OpInstanceChangeGroup { opInstanceName = s } = Just s
981 opSummaryVal OpGroupAdd { opGroupName = s } = Just (fromNonEmpty s)
982 opSummaryVal OpGroupAssignNodes { opGroupName = s } = Just (fromNonEmpty s)
983 opSummaryVal OpGroupSetParams { opGroupName = s } = Just (fromNonEmpty s)
984 opSummaryVal OpGroupRemove { opGroupName = s } = Just (fromNonEmpty s)
985 opSummaryVal OpGroupEvacuate { opGroupName = s } = Just (fromNonEmpty s)
986 opSummaryVal OpBackupPrepare { opInstanceName = s } = Just s
987 opSummaryVal OpBackupExport { opInstanceName = s } = Just s
988 opSummaryVal OpBackupRemove { opInstanceName = s } = Just s
989 opSummaryVal OpTagsGet { opKind = s } = Just (show s)
990 opSummaryVal OpTagsSearch { opTagSearchPattern = s } = Just (fromNonEmpty s)
991 opSummaryVal OpTestDelay { opDelayDuration = d } = Just (show d)
992 opSummaryVal OpTestAllocator { opIallocator = s } =
993 -- FIXME: Python doesn't handle None fields well, so we have behave the same
994 Just $ maybe "None" fromNonEmpty s
995 opSummaryVal OpNetworkAdd { opNetworkName = s} = Just (fromNonEmpty s)
996 opSummaryVal OpNetworkRemove { opNetworkName = s} = Just (fromNonEmpty s)
997 opSummaryVal OpNetworkSetParams { opNetworkName = s} = Just (fromNonEmpty s)
998 opSummaryVal OpNetworkConnect { opNetworkName = s} = Just (fromNonEmpty s)
999 opSummaryVal OpNetworkDisconnect { opNetworkName = s} = Just (fromNonEmpty s)
1000 opSummaryVal _ = Nothing
1002 -- | Computes the summary of the opcode.
1003 opSummary :: OpCode -> String
1005 case opSummaryVal op of
1006 Nothing -> op_suffix
1007 Just s -> op_suffix ++ "(" ++ s ++ ")"
1008 where op_suffix = drop 3 $ opID op
1010 -- | Generic\/common opcode parameters.
1011 $(buildObject "CommonOpParams" "op"
1020 -- | Default common parameter values.
1021 defOpParams :: CommonOpParams
1023 CommonOpParams { opDryRun = Nothing
1024 , opDebugLevel = Nothing
1025 , opPriority = OpPrioNormal
1026 , opDepends = Nothing
1027 , opComment = Nothing
1031 -- | The top-level opcode type.
1032 data MetaOpCode = MetaOpCode { metaParams :: CommonOpParams
1033 , metaOpCode :: OpCode
1034 } deriving (Show, Eq)
1036 -- | JSON serialisation for 'MetaOpCode'.
1037 showMeta :: MetaOpCode -> JSValue
1038 showMeta (MetaOpCode params op) =
1039 let objparams = toDictCommonOpParams params
1040 objop = toDictOpCode op
1041 in makeObj (objparams ++ objop)
1043 -- | JSON deserialisation for 'MetaOpCode'
1044 readMeta :: JSValue -> Text.JSON.Result MetaOpCode
1048 return $ MetaOpCode meta op
1050 instance JSON MetaOpCode where
1054 -- | Wraps an 'OpCode' with the default parameters to build a
1056 wrapOpCode :: OpCode -> MetaOpCode
1057 wrapOpCode = MetaOpCode defOpParams
1059 -- | Sets the comment on a meta opcode.
1060 setOpComment :: String -> MetaOpCode -> MetaOpCode
1061 setOpComment comment (MetaOpCode common op) =
1062 MetaOpCode (common { opComment = Just comment}) op
1064 -- | Sets the priority on a meta opcode.
1065 setOpPriority :: OpSubmitPriority -> MetaOpCode -> MetaOpCode
1066 setOpPriority prio (MetaOpCode common op) =
1067 MetaOpCode (common { opPriority = prio }) op