Statistics
| Branch: | Tag: | Revision:

root / htools / Ganeti / OpCodes.hs @ 37904802

History | View | Annotate | Download (5.9 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Implementation of the opcodes.
4

    
5
-}
6

    
7
{-
8

    
9
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
10

    
11
This program is free software; you can redistribute it and/or modify
12
it under the terms of the GNU General Public License as published by
13
the Free Software Foundation; either version 2 of the License, or
14
(at your option) any later version.
15

    
16
This program is distributed in the hope that it will be useful, but
17
WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19
General Public License for more details.
20

    
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24
02110-1301, USA.
25

    
26
-}
27

    
28
module Ganeti.OpCodes
29
  ( OpCode(..)
30
  , TagObject(..)
31
  , tagObjectFrom
32
  , encodeTagObject
33
  , decodeTagObject
34
  , ReplaceDisksMode(..)
35
  , DiskIndex
36
  , mkDiskIndex
37
  , unDiskIndex
38
  , opID
39
  , allOpIDs
40
  ) where
41

    
42
import Text.JSON (readJSON, showJSON, makeObj, JSON, JSValue(..), fromJSString)
43
import Text.JSON.Pretty (pp_value)
44

    
45
import qualified Ganeti.Constants as C
46
import Ganeti.THH
47

    
48
import Ganeti.JSON
49

    
50
-- | Data type representing what items do the tag operations apply to.
51
$(declareSADT "TagType"
52
  [ ("TagTypeInstance", 'C.tagInstance)
53
  , ("TagTypeNode",     'C.tagNode)
54
  , ("TagTypeGroup",    'C.tagNodegroup)
55
  , ("TagTypeCluster",  'C.tagCluster)
56
  ])
57
$(makeJSONInstance ''TagType)
58

    
59
-- | Data type holding a tag object (type and object name).
60
data TagObject = TagInstance String
61
               | TagNode     String
62
               | TagGroup    String
63
               | TagCluster
64
               deriving (Show, Read, Eq)
65

    
66
-- | Tag type for a given tag object.
67
tagTypeOf :: TagObject -> TagType
68
tagTypeOf (TagInstance {}) = TagTypeInstance
69
tagTypeOf (TagNode     {}) = TagTypeNode
70
tagTypeOf (TagGroup    {}) = TagTypeGroup
71
tagTypeOf (TagCluster  {}) = TagTypeCluster
72

    
73
-- | Gets the potential tag object name.
74
tagNameOf :: TagObject -> Maybe String
75
tagNameOf (TagInstance s) = Just s
76
tagNameOf (TagNode     s) = Just s
77
tagNameOf (TagGroup    s) = Just s
78
tagNameOf  TagCluster     = Nothing
79

    
80
-- | Builds a 'TagObject' from a tag type and name.
81
tagObjectFrom :: (Monad m) => TagType -> JSValue -> m TagObject
82
tagObjectFrom TagTypeInstance (JSString s) =
83
  return . TagInstance $ fromJSString s
84
tagObjectFrom TagTypeNode     (JSString s) = return . TagNode $ fromJSString s
85
tagObjectFrom TagTypeGroup    (JSString s) = return . TagGroup $ fromJSString s
86
tagObjectFrom TagTypeCluster   JSNull      = return TagCluster
87
tagObjectFrom t v =
88
  fail $ "Invalid tag type/name combination: " ++ show t ++ "/" ++
89
         show (pp_value v)
90

    
91
-- | Name of the tag \"name\" field.
92
tagNameField :: String
93
tagNameField = "name"
94

    
95
-- | Custom encoder for 'TagObject' as represented in an opcode.
96
encodeTagObject :: TagObject -> (JSValue, [(String, JSValue)])
97
encodeTagObject t = ( showJSON (tagTypeOf t)
98
                    , [(tagNameField, maybe JSNull showJSON (tagNameOf t))] )
99

    
100
-- | Custom decoder for 'TagObject' as represented in an opcode.
101
decodeTagObject :: (Monad m) => [(String, JSValue)] -> JSValue -> m TagObject
102
decodeTagObject obj kind = do
103
  ttype <- fromJVal kind
104
  tname <- fromObj obj tagNameField
105
  tagObjectFrom ttype tname
106

    
107
-- | Replace disks type.
108
$(declareSADT "ReplaceDisksMode"
109
  [ ("ReplaceOnPrimary",    'C.replaceDiskPri)
110
  , ("ReplaceOnSecondary",  'C.replaceDiskSec)
111
  , ("ReplaceNewSecondary", 'C.replaceDiskChg)
112
  , ("ReplaceAuto",         'C.replaceDiskAuto)
113
  ])
114
$(makeJSONInstance ''ReplaceDisksMode)
115

    
116
-- | Disk index type (embedding constraints on the index value via a
117
-- smart constructor).
118
newtype DiskIndex = DiskIndex { unDiskIndex :: Int }
119
  deriving (Show, Read, Eq, Ord)
120

    
121
-- | Smart constructor for 'DiskIndex'.
122
mkDiskIndex :: (Monad m) => Int -> m DiskIndex
123
mkDiskIndex i | i >= 0 && i < C.maxDisks = return (DiskIndex i)
124
              | otherwise = fail $ "Invalid value for disk index '" ++
125
                            show i ++ "', required between 0 and " ++
126
                            show C.maxDisks
127

    
128
instance JSON DiskIndex where
129
  readJSON v = readJSON v >>= mkDiskIndex
130
  showJSON = showJSON . unDiskIndex
131

    
132
-- | OpCode representation.
133
--
134
-- We only implement a subset of Ganeti opcodes: those which are actually used
135
-- in the htools codebase.
136
$(genOpCode "OpCode"
137
  [ ("OpTestDelay",
138
     [ simpleField "duration"  [t| Double   |]
139
     , simpleField "on_master" [t| Bool     |]
140
     , simpleField "on_nodes"  [t| [String] |]
141
     ])
142
  , ("OpInstanceReplaceDisks",
143
     [ simpleField "instance_name" [t| String |]
144
     , optionalField $ simpleField "remote_node" [t| String |]
145
     , simpleField "mode"  [t| ReplaceDisksMode |]
146
     , simpleField "disks" [t| [DiskIndex] |]
147
     , optionalField $ simpleField "iallocator" [t| String |]
148
     ])
149
  , ("OpInstanceFailover",
150
     [ simpleField "instance_name"      [t| String |]
151
     , simpleField "ignore_consistency" [t| Bool   |]
152
     , optionalField $ simpleField "target_node" [t| String |]
153
     ])
154
  , ("OpInstanceMigrate",
155
     [ simpleField "instance_name"  [t| String |]
156
     , simpleField "live"           [t| Bool   |]
157
     , simpleField "cleanup"        [t| Bool   |]
158
     , defaultField [| False |] $ simpleField "allow_failover" [t| Bool |]
159
     , optionalField $ simpleField "target_node" [t| String |]
160
     ])
161
  , ("OpTagsSet",
162
     [ customField 'decodeTagObject 'encodeTagObject $
163
       simpleField "kind" [t| TagObject |]
164
     , simpleField "tags" [t| [String]  |]
165
     ])
166
  , ("OpTagsDel",
167
     [ customField 'decodeTagObject 'encodeTagObject $
168
       simpleField "kind" [t| TagObject |]
169
     , simpleField "tags" [t| [String]  |]
170
     ])
171
  ])
172

    
173
-- | Returns the OP_ID for a given opcode value.
174
$(genOpID ''OpCode "opID")
175

    
176
-- | A list of all defined/supported opcode IDs.
177
$(genAllOpIDs ''OpCode "allOpIDs")
178

    
179
instance JSON OpCode where
180
  readJSON = loadOpCode
181
  showJSON = saveOpCode