40 |
40 |
, Request(..)
|
41 |
41 |
, ClusterData(..)
|
42 |
42 |
, emptyCluster
|
|
43 |
, compareNameComponent
|
|
44 |
, prefixMatch
|
|
45 |
, LookupResult(..)
|
|
46 |
, MatchPriority(..)
|
43 |
47 |
) where
|
44 |
48 |
|
45 |
49 |
import Data.List
|
|
50 |
import Data.Function
|
46 |
51 |
import qualified Data.Map as M
|
47 |
52 |
import Text.Printf (printf)
|
48 |
53 |
|
... | ... | |
52 |
57 |
import qualified Ganeti.HTools.Group as Group
|
53 |
58 |
|
54 |
59 |
import Ganeti.HTools.Types
|
|
60 |
import Ganeti.HTools.Utils
|
55 |
61 |
|
56 |
62 |
-- * Constants
|
57 |
63 |
|
... | ... | |
94 |
100 |
, cdTags :: [String] -- ^ The cluster tags
|
95 |
101 |
} deriving (Show, Read)
|
96 |
102 |
|
|
103 |
-- | The priority of a match in a lookup result.
|
|
104 |
data MatchPriority = ExactMatch
|
|
105 |
| MultipleMatch
|
|
106 |
| PartialMatch
|
|
107 |
| FailMatch
|
|
108 |
deriving (Show, Read, Enum, Eq, Ord)
|
|
109 |
|
|
110 |
-- | The result of a name lookup in a list.
|
|
111 |
data LookupResult = LookupResult
|
|
112 |
{ lrMatchPriority :: MatchPriority -- ^ The result type
|
|
113 |
-- | Matching value (for ExactMatch, PartialMatch), Lookup string otherwise
|
|
114 |
, lrContent :: String
|
|
115 |
} deriving (Show, Read)
|
|
116 |
|
|
117 |
-- | Lookup results have an absolute preference ordering.
|
|
118 |
instance Eq LookupResult where
|
|
119 |
(==) = (==) `on` lrMatchPriority
|
|
120 |
|
|
121 |
instance Ord LookupResult where
|
|
122 |
compare = compare `on` lrMatchPriority
|
|
123 |
|
97 |
124 |
-- | An empty cluster.
|
98 |
125 |
emptyCluster :: ClusterData
|
99 |
126 |
emptyCluster = ClusterData Container.empty Container.empty Container.empty []
|
... | ... | |
121 |
148 |
Nothing -> fail $ "Unknown group '" ++ gname ++ "' for node " ++ nname
|
122 |
149 |
Just idx -> return idx
|
123 |
150 |
|
|
151 |
-- | Check for prefix matches in names.
|
|
152 |
-- Implemented in Ganeti core utils.text.MatchNameComponent
|
|
153 |
-- as the regexp r"^%s(\..*)?$" % re.escape(key)
|
|
154 |
prefixMatch :: String -- ^ Lookup
|
|
155 |
-> String -- ^ Full name
|
|
156 |
-> Bool -- ^ Whether there is a prefix match
|
|
157 |
prefixMatch lkp = isPrefixOf (lkp ++ ".")
|
|
158 |
|
|
159 |
-- | Is the lookup priority a "good" one?
|
|
160 |
goodMatchPriority :: MatchPriority -> Bool
|
|
161 |
goodMatchPriority ExactMatch = True
|
|
162 |
goodMatchPriority PartialMatch = True
|
|
163 |
goodMatchPriority _ = False
|
|
164 |
|
|
165 |
-- | Is the lookup result an actual match?
|
|
166 |
goodLookupResult :: LookupResult -> Bool
|
|
167 |
goodLookupResult = goodMatchPriority . lrMatchPriority
|
|
168 |
|
|
169 |
-- | Compares a canonical name and a lookup string.
|
|
170 |
compareNameComponent :: String -- ^ Canonical (target) name
|
|
171 |
-> String -- ^ Partial (lookup) name
|
|
172 |
-> LookupResult -- ^ Result of the lookup
|
|
173 |
compareNameComponent cnl lkp =
|
|
174 |
select (LookupResult FailMatch lkp)
|
|
175 |
[ (cnl == lkp , LookupResult ExactMatch cnl)
|
|
176 |
, (prefixMatch lkp cnl , LookupResult PartialMatch cnl)
|
|
177 |
]
|
|
178 |
|
|
179 |
-- | Lookup a string and choose the best result.
|
|
180 |
chooseLookupResult :: String -- ^ Lookup key
|
|
181 |
-> String -- ^ String to compare to the lookup key
|
|
182 |
-> LookupResult -- ^ Previous result
|
|
183 |
-> LookupResult -- ^ New result
|
|
184 |
chooseLookupResult lkp cstr old =
|
|
185 |
-- default: use class order to pick the minimum result
|
|
186 |
select (min new old)
|
|
187 |
-- special cases:
|
|
188 |
-- short circuit if the new result is an exact match
|
|
189 |
[ ((lrMatchPriority new) == ExactMatch, new)
|
|
190 |
-- if both are partial matches generate a multiple match
|
|
191 |
, (partial2, LookupResult MultipleMatch lkp)
|
|
192 |
] where new = compareNameComponent cstr lkp
|
|
193 |
partial2 = all ((PartialMatch==) . lrMatchPriority) [old, new]
|
|
194 |
|
|
195 |
-- | Find the canonical name for a lookup string in a list of names.
|
|
196 |
lookupName :: [String] -- ^ List of keys
|
|
197 |
-> String -- ^ Lookup string
|
|
198 |
-> LookupResult -- ^ Result of the lookup
|
|
199 |
lookupName l s = foldr (chooseLookupResult s)
|
|
200 |
(LookupResult FailMatch s) l
|
|
201 |
|
124 |
202 |
-- | Given a list of elements (and their names), assign indices to them.
|
125 |
203 |
assignIndices :: (Element a) =>
|
126 |
204 |
[(String, a)]
|