Statistics
| Branch: | Tag: | Revision:

root / lib / ht.py @ bc57fa8d

History | View | Annotate | Download (17 kB)

1 62e0e880 Iustin Pop
#
2 62e0e880 Iustin Pop
#
3 62e0e880 Iustin Pop
4 2c9fa1ff Iustin Pop
# Copyright (C) 2010, 2011, 2012 Google Inc.
5 62e0e880 Iustin Pop
#
6 62e0e880 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 62e0e880 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 62e0e880 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 62e0e880 Iustin Pop
# (at your option) any later version.
10 62e0e880 Iustin Pop
#
11 62e0e880 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 62e0e880 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 62e0e880 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 62e0e880 Iustin Pop
# General Public License for more details.
15 62e0e880 Iustin Pop
#
16 62e0e880 Iustin Pop
# You should have received a copy of the GNU General Public License
17 62e0e880 Iustin Pop
# along with this program; if not, write to the Free Software
18 62e0e880 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 62e0e880 Iustin Pop
# 02110-1301, USA.
20 62e0e880 Iustin Pop
21 62e0e880 Iustin Pop
22 62e0e880 Iustin Pop
"""Module implementing the parameter types code."""
23 62e0e880 Iustin Pop
24 8c9ee749 Michael Hanselmann
import re
25 b247c6fc Michael Hanselmann
import operator
26 72cd5493 Jose A. Lopes
import ipaddr
27 8c9ee749 Michael Hanselmann
28 62e0e880 Iustin Pop
from ganeti import compat
29 8c9ee749 Michael Hanselmann
from ganeti import utils
30 8620f50e Michael Hanselmann
from ganeti import constants
31 72cd5493 Jose A. Lopes
from ganeti import objects
32 8c9ee749 Michael Hanselmann
33 8c9ee749 Michael Hanselmann
34 8c9ee749 Michael Hanselmann
_PAREN_RE = re.compile("^[a-zA-Z0-9_-]+$")
35 8c9ee749 Michael Hanselmann
36 8c9ee749 Michael Hanselmann
37 8c9ee749 Michael Hanselmann
def Parens(text):
38 8c9ee749 Michael Hanselmann
  """Enclose text in parens if necessary.
39 8c9ee749 Michael Hanselmann

40 8c9ee749 Michael Hanselmann
  @param text: Text
41 8c9ee749 Michael Hanselmann

42 8c9ee749 Michael Hanselmann
  """
43 8c9ee749 Michael Hanselmann
  text = str(text)
44 8c9ee749 Michael Hanselmann
45 8c9ee749 Michael Hanselmann
  if _PAREN_RE.match(text):
46 8c9ee749 Michael Hanselmann
    return text
47 8c9ee749 Michael Hanselmann
  else:
48 8c9ee749 Michael Hanselmann
    return "(%s)" % text
49 8c9ee749 Michael Hanselmann
50 8c9ee749 Michael Hanselmann
51 9eec6d67 Michael Hanselmann
class _WrapperBase(object):
52 7fc548e9 Michael Hanselmann
  __slots__ = [
53 7fc548e9 Michael Hanselmann
    "_fn",
54 7fc548e9 Michael Hanselmann
    "_text",
55 7fc548e9 Michael Hanselmann
    ]
56 7fc548e9 Michael Hanselmann
57 7fc548e9 Michael Hanselmann
  def __init__(self, text, fn):
58 7fc548e9 Michael Hanselmann
    """Initializes this class.
59 7fc548e9 Michael Hanselmann

60 7fc548e9 Michael Hanselmann
    @param text: Description
61 7fc548e9 Michael Hanselmann
    @param fn: Wrapped function
62 7fc548e9 Michael Hanselmann

63 7fc548e9 Michael Hanselmann
    """
64 9eec6d67 Michael Hanselmann
    assert text.strip()
65 9eec6d67 Michael Hanselmann
66 7fc548e9 Michael Hanselmann
    self._text = text
67 7fc548e9 Michael Hanselmann
    self._fn = fn
68 7fc548e9 Michael Hanselmann
69 7fc548e9 Michael Hanselmann
  def __call__(self, *args):
70 7fc548e9 Michael Hanselmann
    return self._fn(*args)
71 7fc548e9 Michael Hanselmann
72 9eec6d67 Michael Hanselmann
73 9eec6d67 Michael Hanselmann
class _DescWrapper(_WrapperBase):
74 9eec6d67 Michael Hanselmann
  """Wrapper class for description text.
75 9eec6d67 Michael Hanselmann

76 9eec6d67 Michael Hanselmann
  """
77 7fc548e9 Michael Hanselmann
  def __str__(self):
78 7fc548e9 Michael Hanselmann
    return self._text
79 7fc548e9 Michael Hanselmann
80 7fc548e9 Michael Hanselmann
81 9eec6d67 Michael Hanselmann
class _CommentWrapper(_WrapperBase):
82 9eec6d67 Michael Hanselmann
  """Wrapper class for comment.
83 9eec6d67 Michael Hanselmann

84 9eec6d67 Michael Hanselmann
  """
85 9eec6d67 Michael Hanselmann
  def __str__(self):
86 9eec6d67 Michael Hanselmann
    return "%s [%s]" % (self._fn, self._text)
87 9eec6d67 Michael Hanselmann
88 9eec6d67 Michael Hanselmann
89 8c9ee749 Michael Hanselmann
def WithDesc(text):
90 8c9ee749 Michael Hanselmann
  """Builds wrapper class with description text.
91 8c9ee749 Michael Hanselmann

92 8c9ee749 Michael Hanselmann
  @type text: string
93 8c9ee749 Michael Hanselmann
  @param text: Description text
94 8c9ee749 Michael Hanselmann
  @return: Callable class
95 8c9ee749 Michael Hanselmann

96 8c9ee749 Michael Hanselmann
  """
97 8c9ee749 Michael Hanselmann
  assert text[0] == text[0].upper()
98 8c9ee749 Michael Hanselmann
99 7fc548e9 Michael Hanselmann
  return compat.partial(_DescWrapper, text)
100 8c9ee749 Michael Hanselmann
101 8c9ee749 Michael Hanselmann
102 9eec6d67 Michael Hanselmann
def Comment(text):
103 9eec6d67 Michael Hanselmann
  """Builds wrapper for adding comment to description text.
104 9eec6d67 Michael Hanselmann

105 9eec6d67 Michael Hanselmann
  @type text: string
106 9eec6d67 Michael Hanselmann
  @param text: Comment text
107 9eec6d67 Michael Hanselmann
  @return: Callable class
108 9eec6d67 Michael Hanselmann

109 9eec6d67 Michael Hanselmann
  """
110 9eec6d67 Michael Hanselmann
  assert not frozenset(text).intersection("[]")
111 9eec6d67 Michael Hanselmann
112 9eec6d67 Michael Hanselmann
  return compat.partial(_CommentWrapper, text)
113 9eec6d67 Michael Hanselmann
114 9eec6d67 Michael Hanselmann
115 8c9ee749 Michael Hanselmann
def CombinationDesc(op, args, fn):
116 8c9ee749 Michael Hanselmann
  """Build description for combinating operator.
117 8c9ee749 Michael Hanselmann

118 8c9ee749 Michael Hanselmann
  @type op: string
119 8c9ee749 Michael Hanselmann
  @param op: Operator as text (e.g. "and")
120 8c9ee749 Michael Hanselmann
  @type args: list
121 8c9ee749 Michael Hanselmann
  @param args: Operator arguments
122 8c9ee749 Michael Hanselmann
  @type fn: callable
123 8c9ee749 Michael Hanselmann
  @param fn: Wrapped function
124 8c9ee749 Michael Hanselmann

125 8c9ee749 Michael Hanselmann
  """
126 a138ead7 Michael Hanselmann
  # Some type descriptions are rather long. If "None" is listed at the
127 a138ead7 Michael Hanselmann
  # end or somewhere in between it is easily missed. Therefore it should
128 a138ead7 Michael Hanselmann
  # be at the beginning, e.g. "None or (long description)".
129 a138ead7 Michael Hanselmann
  if __debug__ and TNone in args and args.index(TNone) > 0:
130 a138ead7 Michael Hanselmann
    raise Exception("TNone must be listed first")
131 a138ead7 Michael Hanselmann
132 8c9ee749 Michael Hanselmann
  if len(args) == 1:
133 8c9ee749 Michael Hanselmann
    descr = str(args[0])
134 8c9ee749 Michael Hanselmann
  else:
135 8c9ee749 Michael Hanselmann
    descr = (" %s " % op).join(Parens(i) for i in args)
136 8c9ee749 Michael Hanselmann
137 8c9ee749 Michael Hanselmann
  return WithDesc(descr)(fn)
138 8c9ee749 Michael Hanselmann
139 62e0e880 Iustin Pop
140 62e0e880 Iustin Pop
# Modifiable default values; need to define these here before the
141 62e0e880 Iustin Pop
# actual LUs
142 62e0e880 Iustin Pop
143 8c9ee749 Michael Hanselmann
@WithDesc(str([]))
144 62e0e880 Iustin Pop
def EmptyList():
145 62e0e880 Iustin Pop
  """Returns an empty list.
146 62e0e880 Iustin Pop

147 62e0e880 Iustin Pop
  """
148 62e0e880 Iustin Pop
  return []
149 62e0e880 Iustin Pop
150 62e0e880 Iustin Pop
151 8c9ee749 Michael Hanselmann
@WithDesc(str({}))
152 62e0e880 Iustin Pop
def EmptyDict():
153 62e0e880 Iustin Pop
  """Returns an empty dict.
154 62e0e880 Iustin Pop

155 62e0e880 Iustin Pop
  """
156 62e0e880 Iustin Pop
  return {}
157 62e0e880 Iustin Pop
158 62e0e880 Iustin Pop
159 62e0e880 Iustin Pop
#: The without-default default value
160 62e0e880 Iustin Pop
NoDefault = object()
161 62e0e880 Iustin Pop
162 62e0e880 Iustin Pop
163 62e0e880 Iustin Pop
# Some basic types
164 8620f50e Michael Hanselmann
@WithDesc("Anything")
165 8620f50e Michael Hanselmann
def TAny(_):
166 8620f50e Michael Hanselmann
  """Accepts any value.
167 8620f50e Michael Hanselmann

168 8620f50e Michael Hanselmann
  """
169 8620f50e Michael Hanselmann
  return True
170 8620f50e Michael Hanselmann
171 8620f50e Michael Hanselmann
172 8c9ee749 Michael Hanselmann
@WithDesc("NotNone")
173 62e0e880 Iustin Pop
def TNotNone(val):
174 62e0e880 Iustin Pop
  """Checks if the given value is not None.
175 62e0e880 Iustin Pop

176 62e0e880 Iustin Pop
  """
177 62e0e880 Iustin Pop
  return val is not None
178 62e0e880 Iustin Pop
179 62e0e880 Iustin Pop
180 8c9ee749 Michael Hanselmann
@WithDesc("None")
181 62e0e880 Iustin Pop
def TNone(val):
182 62e0e880 Iustin Pop
  """Checks if the given value is None.
183 62e0e880 Iustin Pop

184 62e0e880 Iustin Pop
  """
185 62e0e880 Iustin Pop
  return val is None
186 62e0e880 Iustin Pop
187 62e0e880 Iustin Pop
188 e055a2ab Dimitris Aragiorgis
@WithDesc("ValueNone")
189 e055a2ab Dimitris Aragiorgis
def TValueNone(val):
190 e055a2ab Dimitris Aragiorgis
  """Checks if the given value is L{constants.VALUE_NONE}.
191 e055a2ab Dimitris Aragiorgis

192 e055a2ab Dimitris Aragiorgis
  """
193 e055a2ab Dimitris Aragiorgis
  return val == constants.VALUE_NONE
194 e055a2ab Dimitris Aragiorgis
195 e055a2ab Dimitris Aragiorgis
196 8c9ee749 Michael Hanselmann
@WithDesc("Boolean")
197 62e0e880 Iustin Pop
def TBool(val):
198 62e0e880 Iustin Pop
  """Checks if the given value is a boolean.
199 62e0e880 Iustin Pop

200 62e0e880 Iustin Pop
  """
201 62e0e880 Iustin Pop
  return isinstance(val, bool)
202 62e0e880 Iustin Pop
203 62e0e880 Iustin Pop
204 8c9ee749 Michael Hanselmann
@WithDesc("Integer")
205 62e0e880 Iustin Pop
def TInt(val):
206 62e0e880 Iustin Pop
  """Checks if the given value is an integer.
207 62e0e880 Iustin Pop

208 62e0e880 Iustin Pop
  """
209 8568de9e Michael Hanselmann
  # For backwards compatibility with older Python versions, boolean values are
210 8568de9e Michael Hanselmann
  # also integers and should be excluded in this test.
211 8568de9e Michael Hanselmann
  #
212 8568de9e Michael Hanselmann
  # >>> (isinstance(False, int), isinstance(True, int))
213 8568de9e Michael Hanselmann
  # (True, True)
214 b99b607f Michael Hanselmann
  return isinstance(val, (int, long)) and not isinstance(val, bool)
215 62e0e880 Iustin Pop
216 62e0e880 Iustin Pop
217 8c9ee749 Michael Hanselmann
@WithDesc("Float")
218 62e0e880 Iustin Pop
def TFloat(val):
219 62e0e880 Iustin Pop
  """Checks if the given value is a float.
220 62e0e880 Iustin Pop

221 62e0e880 Iustin Pop
  """
222 62e0e880 Iustin Pop
  return isinstance(val, float)
223 62e0e880 Iustin Pop
224 62e0e880 Iustin Pop
225 8c9ee749 Michael Hanselmann
@WithDesc("String")
226 62e0e880 Iustin Pop
def TString(val):
227 62e0e880 Iustin Pop
  """Checks if the given value is a string.
228 62e0e880 Iustin Pop

229 62e0e880 Iustin Pop
  """
230 62e0e880 Iustin Pop
  return isinstance(val, basestring)
231 62e0e880 Iustin Pop
232 62e0e880 Iustin Pop
233 8c9ee749 Michael Hanselmann
@WithDesc("EvalToTrue")
234 62e0e880 Iustin Pop
def TTrue(val):
235 62e0e880 Iustin Pop
  """Checks if a given value evaluates to a boolean True value.
236 62e0e880 Iustin Pop

237 62e0e880 Iustin Pop
  """
238 62e0e880 Iustin Pop
  return bool(val)
239 62e0e880 Iustin Pop
240 62e0e880 Iustin Pop
241 62e0e880 Iustin Pop
def TElemOf(target_list):
242 62e0e880 Iustin Pop
  """Builds a function that checks if a given value is a member of a list.
243 62e0e880 Iustin Pop

244 62e0e880 Iustin Pop
  """
245 8c9ee749 Michael Hanselmann
  def fn(val):
246 8c9ee749 Michael Hanselmann
    return val in target_list
247 8c9ee749 Michael Hanselmann
248 8c9ee749 Michael Hanselmann
  return WithDesc("OneOf %s" % (utils.CommaJoin(target_list), ))(fn)
249 62e0e880 Iustin Pop
250 62e0e880 Iustin Pop
251 62e0e880 Iustin Pop
# Container types
252 8c9ee749 Michael Hanselmann
@WithDesc("List")
253 62e0e880 Iustin Pop
def TList(val):
254 62e0e880 Iustin Pop
  """Checks if the given value is a list.
255 62e0e880 Iustin Pop

256 62e0e880 Iustin Pop
  """
257 62e0e880 Iustin Pop
  return isinstance(val, list)
258 62e0e880 Iustin Pop
259 62e0e880 Iustin Pop
260 dd076c21 Iustin Pop
@WithDesc("Tuple")
261 dd076c21 Iustin Pop
def TTuple(val):
262 dd076c21 Iustin Pop
  """Checks if the given value is a tuple.
263 dd076c21 Iustin Pop

264 dd076c21 Iustin Pop
  """
265 dd076c21 Iustin Pop
  return isinstance(val, tuple)
266 dd076c21 Iustin Pop
267 dd076c21 Iustin Pop
268 8c9ee749 Michael Hanselmann
@WithDesc("Dictionary")
269 62e0e880 Iustin Pop
def TDict(val):
270 62e0e880 Iustin Pop
  """Checks if the given value is a dictionary.
271 62e0e880 Iustin Pop

272 62e0e880 Iustin Pop
  """
273 62e0e880 Iustin Pop
  return isinstance(val, dict)
274 62e0e880 Iustin Pop
275 62e0e880 Iustin Pop
276 62e0e880 Iustin Pop
def TIsLength(size):
277 62e0e880 Iustin Pop
  """Check is the given container is of the given size.
278 62e0e880 Iustin Pop

279 62e0e880 Iustin Pop
  """
280 8c9ee749 Michael Hanselmann
  def fn(container):
281 8c9ee749 Michael Hanselmann
    return len(container) == size
282 8c9ee749 Michael Hanselmann
283 8c9ee749 Michael Hanselmann
  return WithDesc("Length %s" % (size, ))(fn)
284 62e0e880 Iustin Pop
285 62e0e880 Iustin Pop
286 62e0e880 Iustin Pop
# Combinator types
287 62e0e880 Iustin Pop
def TAnd(*args):
288 62e0e880 Iustin Pop
  """Combine multiple functions using an AND operation.
289 62e0e880 Iustin Pop

290 62e0e880 Iustin Pop
  """
291 62e0e880 Iustin Pop
  def fn(val):
292 62e0e880 Iustin Pop
    return compat.all(t(val) for t in args)
293 8c9ee749 Michael Hanselmann
294 8c9ee749 Michael Hanselmann
  return CombinationDesc("and", args, fn)
295 62e0e880 Iustin Pop
296 62e0e880 Iustin Pop
297 62e0e880 Iustin Pop
def TOr(*args):
298 b3ab9a8a Christos Stavrakakis
  """Combine multiple functions using an OR operation.
299 62e0e880 Iustin Pop

300 62e0e880 Iustin Pop
  """
301 62e0e880 Iustin Pop
  def fn(val):
302 62e0e880 Iustin Pop
    return compat.any(t(val) for t in args)
303 8c9ee749 Michael Hanselmann
304 8c9ee749 Michael Hanselmann
  return CombinationDesc("or", args, fn)
305 62e0e880 Iustin Pop
306 62e0e880 Iustin Pop
307 62e0e880 Iustin Pop
def TMap(fn, test):
308 62e0e880 Iustin Pop
  """Checks that a modified version of the argument passes the given test.
309 62e0e880 Iustin Pop

310 62e0e880 Iustin Pop
  """
311 8c9ee749 Michael Hanselmann
  return WithDesc("Result of %s must be %s" %
312 8c9ee749 Michael Hanselmann
                  (Parens(fn), Parens(test)))(lambda val: test(fn(val)))
313 62e0e880 Iustin Pop
314 62e0e880 Iustin Pop
315 8620f50e Michael Hanselmann
def TRegex(pobj):
316 8620f50e Michael Hanselmann
  """Checks whether a string matches a specific regular expression.
317 8620f50e Michael Hanselmann

318 8620f50e Michael Hanselmann
  @param pobj: Compiled regular expression as returned by C{re.compile}
319 8620f50e Michael Hanselmann

320 8620f50e Michael Hanselmann
  """
321 8620f50e Michael Hanselmann
  desc = WithDesc("String matching regex \"%s\"" %
322 8620f50e Michael Hanselmann
                  pobj.pattern.encode("string_escape"))
323 8620f50e Michael Hanselmann
324 8620f50e Michael Hanselmann
  return desc(TAnd(TString, pobj.match))
325 8620f50e Michael Hanselmann
326 8620f50e Michael Hanselmann
327 fd9f58fd Iustin Pop
def TMaybe(test):
328 fd9f58fd Iustin Pop
  """Wrap a test in a TOr(TNone, test).
329 fd9f58fd Iustin Pop

330 fd9f58fd Iustin Pop
  This makes it easier to define TMaybe* types.
331 fd9f58fd Iustin Pop

332 fd9f58fd Iustin Pop
  """
333 fd9f58fd Iustin Pop
  return TOr(TNone, test)
334 fd9f58fd Iustin Pop
335 fd9f58fd Iustin Pop
336 e055a2ab Dimitris Aragiorgis
def TMaybeValueNone(test):
337 e055a2ab Dimitris Aragiorgis
  """Used for unsetting values.
338 e055a2ab Dimitris Aragiorgis

339 e055a2ab Dimitris Aragiorgis
  """
340 e055a2ab Dimitris Aragiorgis
  return TMaybe(TOr(TValueNone, test))
341 e055a2ab Dimitris Aragiorgis
342 e055a2ab Dimitris Aragiorgis
343 62e0e880 Iustin Pop
# Type aliases
344 62e0e880 Iustin Pop
345 62e0e880 Iustin Pop
#: a non-empty string
346 8c9ee749 Michael Hanselmann
TNonEmptyString = WithDesc("NonEmptyString")(TAnd(TString, TTrue))
347 62e0e880 Iustin Pop
348 62e0e880 Iustin Pop
#: a maybe non-empty string
349 fd9f58fd Iustin Pop
TMaybeString = TMaybe(TNonEmptyString)
350 62e0e880 Iustin Pop
351 62e0e880 Iustin Pop
#: a maybe boolean (bool or none)
352 fd9f58fd Iustin Pop
TMaybeBool = TMaybe(TBool)
353 62e0e880 Iustin Pop
354 5f074973 Michael Hanselmann
#: Maybe a dictionary (dict or None)
355 fd9f58fd Iustin Pop
TMaybeDict = TMaybe(TDict)
356 62e0e880 Iustin Pop
357 ab98e236 Michele Tartara
#: Maybe a list (list or None)
358 ab98e236 Michele Tartara
TMaybeList = TMaybe(TList)
359 ab98e236 Michele Tartara
360 72cd5493 Jose A. Lopes
361 72cd5493 Jose A. Lopes
#: a non-negative number (value > 0)
362 72cd5493 Jose A. Lopes
# val_type should be TInt, TDouble (== TFloat), or TNumber
363 72cd5493 Jose A. Lopes
def TNonNegative(val_type):
364 72cd5493 Jose A. Lopes
  return WithDesc("EqualOrGreaterThanZero")(TAnd(val_type, lambda v: v >= 0))
365 72cd5493 Jose A. Lopes
366 72cd5493 Jose A. Lopes
367 72cd5493 Jose A. Lopes
#: a positive number (value >= 0)
368 72cd5493 Jose A. Lopes
# val_type should be TInt, TDouble (== TFloat), or TNumber
369 72cd5493 Jose A. Lopes
def TPositive(val_type):
370 72cd5493 Jose A. Lopes
  return WithDesc("GreaterThanZero")(TAnd(val_type, lambda v: v > 0))
371 72cd5493 Jose A. Lopes
372 72cd5493 Jose A. Lopes
373 2c9fa1ff Iustin Pop
#: a non-negative integer (value >= 0)
374 72cd5493 Jose A. Lopes
TNonNegativeInt = TNonNegative(TInt)
375 2c9fa1ff Iustin Pop
376 2c9fa1ff Iustin Pop
#: a positive integer (value > 0)
377 72cd5493 Jose A. Lopes
TPositiveInt = TPositive(TInt)
378 62e0e880 Iustin Pop
379 2c0af7da Guido Trotter
#: a maybe positive integer (positive integer or None)
380 fd9f58fd Iustin Pop
TMaybePositiveInt = TMaybe(TPositiveInt)
381 2c0af7da Guido Trotter
382 2c9fa1ff Iustin Pop
#: a negative integer (value < 0)
383 2c9fa1ff Iustin Pop
TNegativeInt = \
384 b247c6fc Michael Hanselmann
  TAnd(TInt, WithDesc("LessThanZero")(compat.partial(operator.gt, 0)))
385 b247c6fc Michael Hanselmann
386 beff3779 Renรฉ Nussbaumer
#: a positive float
387 2c9fa1ff Iustin Pop
TNonNegativeFloat = \
388 2c9fa1ff Iustin Pop
  TAnd(TFloat, WithDesc("EqualOrGreaterThanZero")(lambda v: v >= 0.0))
389 beff3779 Renรฉ Nussbaumer
390 8620f50e Michael Hanselmann
#: Job ID
391 2c9fa1ff Iustin Pop
TJobId = WithDesc("JobId")(TOr(TNonNegativeInt,
392 bdfd7802 Michael Hanselmann
                               TRegex(re.compile("^%s$" %
393 bdfd7802 Michael Hanselmann
                                                 constants.JOB_ID_TEMPLATE))))
394 8620f50e Michael Hanselmann
395 72cd5493 Jose A. Lopes
#: Double (== Float)
396 72cd5493 Jose A. Lopes
TDouble = TFloat
397 72cd5493 Jose A. Lopes
398 697f49d5 Michael Hanselmann
#: Number
399 697f49d5 Michael Hanselmann
TNumber = TOr(TInt, TFloat)
400 697f49d5 Michael Hanselmann
401 b247c6fc Michael Hanselmann
#: Relative job ID
402 2c9fa1ff Iustin Pop
TRelativeJobId = WithDesc("RelativeJobId")(TNegativeInt)
403 b247c6fc Michael Hanselmann
404 62e0e880 Iustin Pop
405 16091a6e Michael Hanselmann
def TInstanceOf(cls):
406 16091a6e Michael Hanselmann
  """Checks if a given value is an instance of C{cls}.
407 16091a6e Michael Hanselmann

408 16091a6e Michael Hanselmann
  @type cls: class
409 16091a6e Michael Hanselmann
  @param cls: Class object
410 b1e47e2d Renรฉ Nussbaumer

411 b1e47e2d Renรฉ Nussbaumer
  """
412 16091a6e Michael Hanselmann
  name = "%s.%s" % (cls.__module__, cls.__name__)
413 16091a6e Michael Hanselmann
414 16091a6e Michael Hanselmann
  desc = WithDesc("Instance of %s" % (Parens(name), ))
415 16091a6e Michael Hanselmann
416 16091a6e Michael Hanselmann
  return desc(lambda val: isinstance(val, cls))
417 b1e47e2d Renรฉ Nussbaumer
418 b1e47e2d Renรฉ Nussbaumer
419 62e0e880 Iustin Pop
def TListOf(my_type):
420 62e0e880 Iustin Pop
  """Checks if a given value is a list with all elements of the same type.
421 62e0e880 Iustin Pop

422 62e0e880 Iustin Pop
  """
423 8c9ee749 Michael Hanselmann
  desc = WithDesc("List of %s" % (Parens(my_type), ))
424 8c9ee749 Michael Hanselmann
  return desc(TAnd(TList, lambda lst: compat.all(my_type(v) for v in lst)))
425 62e0e880 Iustin Pop
426 62e0e880 Iustin Pop
427 fd9f58fd Iustin Pop
TMaybeListOf = lambda item_type: TMaybe(TListOf(item_type))
428 ff8067cf Michael Hanselmann
429 ff8067cf Michael Hanselmann
430 72cd5493 Jose A. Lopes
def TTupleOf(*val_types):
431 72cd5493 Jose A. Lopes
  """Checks if a given value is a list with the proper size and its
432 72cd5493 Jose A. Lopes
     elements match the given types.
433 72cd5493 Jose A. Lopes

434 72cd5493 Jose A. Lopes
  """
435 72cd5493 Jose A. Lopes
  desc = WithDesc("Tuple of %s" % (Parens(val_types), ))
436 72cd5493 Jose A. Lopes
  return desc(TAnd(TIsLength(len(val_types)), TItems(val_types)))
437 72cd5493 Jose A. Lopes
438 72cd5493 Jose A. Lopes
439 72cd5493 Jose A. Lopes
def TSetOf(val_type):
440 72cd5493 Jose A. Lopes
  """Checks if a given value is a list with all elements of the same
441 72cd5493 Jose A. Lopes
     type and eliminates duplicated elements.
442 72cd5493 Jose A. Lopes

443 72cd5493 Jose A. Lopes
  """
444 72cd5493 Jose A. Lopes
  desc = WithDesc("Set of %s" % (Parens(val_type), ))
445 72cd5493 Jose A. Lopes
  return desc(lambda st: TListOf(val_type)(list(set(st))))
446 72cd5493 Jose A. Lopes
447 72cd5493 Jose A. Lopes
448 62e0e880 Iustin Pop
def TDictOf(key_type, val_type):
449 62e0e880 Iustin Pop
  """Checks a dict type for the type of its key/values.
450 62e0e880 Iustin Pop

451 62e0e880 Iustin Pop
  """
452 8c9ee749 Michael Hanselmann
  desc = WithDesc("Dictionary with keys of %s and values of %s" %
453 8c9ee749 Michael Hanselmann
                  (Parens(key_type), Parens(val_type)))
454 8c9ee749 Michael Hanselmann
455 8c9ee749 Michael Hanselmann
  def fn(container):
456 8c9ee749 Michael Hanselmann
    return (compat.all(key_type(v) for v in container.keys()) and
457 8c9ee749 Michael Hanselmann
            compat.all(val_type(v) for v in container.values()))
458 8c9ee749 Michael Hanselmann
459 8c9ee749 Michael Hanselmann
  return desc(TAnd(TDict, fn))
460 a464ce71 Michael Hanselmann
461 a464ce71 Michael Hanselmann
462 a464ce71 Michael Hanselmann
def _TStrictDictCheck(require_all, exclusive, items, val):
463 a464ce71 Michael Hanselmann
  """Helper function for L{TStrictDict}.
464 a464ce71 Michael Hanselmann

465 a464ce71 Michael Hanselmann
  """
466 a464ce71 Michael Hanselmann
  notfound_fn = lambda _: not exclusive
467 a464ce71 Michael Hanselmann
468 a464ce71 Michael Hanselmann
  if require_all and not frozenset(val.keys()).issuperset(items.keys()):
469 a464ce71 Michael Hanselmann
    # Requires items not found in value
470 a464ce71 Michael Hanselmann
    return False
471 a464ce71 Michael Hanselmann
472 a464ce71 Michael Hanselmann
  return compat.all(items.get(key, notfound_fn)(value)
473 a464ce71 Michael Hanselmann
                    for (key, value) in val.items())
474 a464ce71 Michael Hanselmann
475 a464ce71 Michael Hanselmann
476 a464ce71 Michael Hanselmann
def TStrictDict(require_all, exclusive, items):
477 a464ce71 Michael Hanselmann
  """Strict dictionary check with specific keys.
478 a464ce71 Michael Hanselmann

479 a464ce71 Michael Hanselmann
  @type require_all: boolean
480 a464ce71 Michael Hanselmann
  @param require_all: Whether all keys in L{items} are required
481 a464ce71 Michael Hanselmann
  @type exclusive: boolean
482 a464ce71 Michael Hanselmann
  @param exclusive: Whether only keys listed in L{items} should be accepted
483 a464ce71 Michael Hanselmann
  @type items: dictionary
484 a464ce71 Michael Hanselmann
  @param items: Mapping from key (string) to verification function
485 a464ce71 Michael Hanselmann

486 a464ce71 Michael Hanselmann
  """
487 a464ce71 Michael Hanselmann
  descparts = ["Dictionary containing"]
488 a464ce71 Michael Hanselmann
489 a464ce71 Michael Hanselmann
  if exclusive:
490 a464ce71 Michael Hanselmann
    descparts.append(" none but the")
491 a464ce71 Michael Hanselmann
492 a464ce71 Michael Hanselmann
  if require_all:
493 a464ce71 Michael Hanselmann
    descparts.append(" required")
494 a464ce71 Michael Hanselmann
495 a464ce71 Michael Hanselmann
  if len(items) == 1:
496 a464ce71 Michael Hanselmann
    descparts.append(" key ")
497 a464ce71 Michael Hanselmann
  else:
498 a464ce71 Michael Hanselmann
    descparts.append(" keys ")
499 a464ce71 Michael Hanselmann
500 a464ce71 Michael Hanselmann
  descparts.append(utils.CommaJoin("\"%s\" (value %s)" % (key, value)
501 a464ce71 Michael Hanselmann
                                   for (key, value) in items.items()))
502 a464ce71 Michael Hanselmann
503 a464ce71 Michael Hanselmann
  desc = WithDesc("".join(descparts))
504 a464ce71 Michael Hanselmann
505 a464ce71 Michael Hanselmann
  return desc(TAnd(TDict,
506 a464ce71 Michael Hanselmann
                   compat.partial(_TStrictDictCheck, require_all, exclusive,
507 a464ce71 Michael Hanselmann
                                  items)))
508 8620f50e Michael Hanselmann
509 8620f50e Michael Hanselmann
510 8620f50e Michael Hanselmann
def TItems(items):
511 8620f50e Michael Hanselmann
  """Checks individual items of a container.
512 8620f50e Michael Hanselmann

513 8620f50e Michael Hanselmann
  If the verified value and the list of expected items differ in length, this
514 8620f50e Michael Hanselmann
  check considers only as many items as are contained in the shorter list. Use
515 8620f50e Michael Hanselmann
  L{TIsLength} to enforce a certain length.
516 8620f50e Michael Hanselmann

517 8620f50e Michael Hanselmann
  @type items: list
518 8620f50e Michael Hanselmann
  @param items: List of checks
519 8620f50e Michael Hanselmann

520 8620f50e Michael Hanselmann
  """
521 8620f50e Michael Hanselmann
  assert items, "Need items"
522 8620f50e Michael Hanselmann
523 8620f50e Michael Hanselmann
  text = ["Item", "item"]
524 8620f50e Michael Hanselmann
  desc = WithDesc(utils.CommaJoin("%s %s is %s" %
525 8620f50e Michael Hanselmann
                                  (text[int(idx > 0)], idx, Parens(check))
526 8620f50e Michael Hanselmann
                                  for (idx, check) in enumerate(items)))
527 8620f50e Michael Hanselmann
528 8620f50e Michael Hanselmann
  return desc(lambda value: compat.all(check(i)
529 8620f50e Michael Hanselmann
                                       for (check, i) in zip(items, value)))
530 72cd5493 Jose A. Lopes
531 72cd5493 Jose A. Lopes
532 72cd5493 Jose A. Lopes
TAllocPolicy = TElemOf(constants.VALID_ALLOC_POLICIES)
533 72cd5493 Jose A. Lopes
TCVErrorCode = TElemOf(constants.CV_ALL_ECODES_STRINGS)
534 72cd5493 Jose A. Lopes
TQueryResultCode = TElemOf(constants.RS_ALL)
535 72cd5493 Jose A. Lopes
TExportTarget = TOr(TNonEmptyString, TList)
536 72cd5493 Jose A. Lopes
TExportMode = TElemOf(constants.EXPORT_MODES)
537 72cd5493 Jose A. Lopes
TDiskIndex = TAnd(TNonNegativeInt, lambda val: val < constants.MAX_DISKS)
538 72cd5493 Jose A. Lopes
TReplaceDisksMode = TElemOf(constants.REPLACE_MODES)
539 72cd5493 Jose A. Lopes
TDiskTemplate = TElemOf(constants.DISK_TEMPLATES)
540 d067f40b Jose A. Lopes
TEvacMode = TElemOf(constants.NODE_EVAC_MODES)
541 72cd5493 Jose A. Lopes
TIAllocatorTestDir = TElemOf(constants.VALID_IALLOCATOR_DIRECTIONS)
542 72cd5493 Jose A. Lopes
TIAllocatorMode = TElemOf(constants.VALID_IALLOCATOR_MODES)
543 f198cf91 Thomas Thrainer
TImportExportCompression = TElemOf(constants.IEC_ALL)
544 72cd5493 Jose A. Lopes
545 72cd5493 Jose A. Lopes
546 72cd5493 Jose A. Lopes
def TSetParamsMods(fn):
547 72cd5493 Jose A. Lopes
  """Generates a check for modification lists.
548 72cd5493 Jose A. Lopes

549 72cd5493 Jose A. Lopes
  """
550 72cd5493 Jose A. Lopes
  # Old format
551 72cd5493 Jose A. Lopes
  # TODO: Remove in version 2.11 including support in LUInstanceSetParams
552 72cd5493 Jose A. Lopes
  old_mod_item_fn = \
553 72cd5493 Jose A. Lopes
    TAnd(TIsLength(2),
554 72cd5493 Jose A. Lopes
         TItems([TOr(TElemOf(constants.DDMS_VALUES), TNonNegativeInt), fn]))
555 72cd5493 Jose A. Lopes
556 72cd5493 Jose A. Lopes
  # New format, supporting adding/removing disks/NICs at arbitrary indices
557 72cd5493 Jose A. Lopes
  mod_item_fn = \
558 72cd5493 Jose A. Lopes
      TAnd(TIsLength(3), TItems([
559 72cd5493 Jose A. Lopes
        TElemOf(constants.DDMS_VALUES_WITH_MODIFY),
560 72cd5493 Jose A. Lopes
        Comment("Device index, can be negative, e.g. -1 for last disk")
561 72cd5493 Jose A. Lopes
                 (TOr(TInt, TString)),
562 72cd5493 Jose A. Lopes
        fn,
563 72cd5493 Jose A. Lopes
        ]))
564 72cd5493 Jose A. Lopes
565 72cd5493 Jose A. Lopes
  return TOr(Comment("Recommended")(TListOf(mod_item_fn)),
566 72cd5493 Jose A. Lopes
             Comment("Deprecated")(TListOf(old_mod_item_fn)))
567 72cd5493 Jose A. Lopes
568 72cd5493 Jose A. Lopes
569 72cd5493 Jose A. Lopes
TINicParams = \
570 72cd5493 Jose A. Lopes
    Comment("NIC parameters")(TDictOf(TElemOf(constants.INIC_PARAMS),
571 9e67e425 Jose A. Lopes
                                      TMaybe(TString)))
572 72cd5493 Jose A. Lopes
573 72cd5493 Jose A. Lopes
TIDiskParams = \
574 72cd5493 Jose A. Lopes
    Comment("Disk parameters")(TDictOf(TElemOf(constants.IDISK_PARAMS),
575 72cd5493 Jose A. Lopes
                                       TOr(TNonEmptyString, TInt)))
576 72cd5493 Jose A. Lopes
577 72cd5493 Jose A. Lopes
THypervisor = TElemOf(constants.HYPER_TYPES)
578 72cd5493 Jose A. Lopes
TMigrationMode = TElemOf(constants.HT_MIGRATION_MODES)
579 72cd5493 Jose A. Lopes
TNICMode = TElemOf(constants.NIC_VALID_MODES)
580 72cd5493 Jose A. Lopes
TInstCreateMode = TElemOf(constants.INSTANCE_CREATE_MODES)
581 72cd5493 Jose A. Lopes
TRebootType = TElemOf(constants.REBOOT_TYPES)
582 72cd5493 Jose A. Lopes
TFileDriver = TElemOf(constants.FILE_DRIVER)
583 72cd5493 Jose A. Lopes
TOobCommand = TElemOf(constants.OOB_COMMANDS)
584 72cd5493 Jose A. Lopes
TQueryTypeOp = TElemOf(constants.QR_VIA_OP)
585 72cd5493 Jose A. Lopes
586 72cd5493 Jose A. Lopes
TDiskParams = \
587 72cd5493 Jose A. Lopes
    Comment("Disk parameters")(TDictOf(TNonEmptyString,
588 72cd5493 Jose A. Lopes
                                       TOr(TNonEmptyString, TInt)))
589 72cd5493 Jose A. Lopes
590 72cd5493 Jose A. Lopes
TDiskChanges = \
591 72cd5493 Jose A. Lopes
    TAnd(TIsLength(2),
592 72cd5493 Jose A. Lopes
         TItems([Comment("Disk index")(TNonNegativeInt),
593 72cd5493 Jose A. Lopes
                 Comment("Parameters")(TDiskParams)]))
594 72cd5493 Jose A. Lopes
595 72cd5493 Jose A. Lopes
TRecreateDisksInfo = TOr(TListOf(TNonNegativeInt), TListOf(TDiskChanges))
596 72cd5493 Jose A. Lopes
597 72cd5493 Jose A. Lopes
598 72cd5493 Jose A. Lopes
def TStorageType(val):
599 72cd5493 Jose A. Lopes
  """Builds a function that checks if a given value is a valid storage
600 72cd5493 Jose A. Lopes
  type.
601 72cd5493 Jose A. Lopes

602 72cd5493 Jose A. Lopes
  """
603 72cd5493 Jose A. Lopes
  return (val in constants.STORAGE_TYPES)
604 72cd5493 Jose A. Lopes
605 72cd5493 Jose A. Lopes
606 72cd5493 Jose A. Lopes
TTagKind = TElemOf(constants.VALID_TAG_TYPES)
607 72cd5493 Jose A. Lopes
TDdmSimple = TElemOf(constants.DDMS_VALUES)
608 72cd5493 Jose A. Lopes
TVerifyOptionalChecks = TElemOf(constants.VERIFY_OPTIONAL_CHECKS)
609 72cd5493 Jose A. Lopes
610 72cd5493 Jose A. Lopes
611 72cd5493 Jose A. Lopes
@WithDesc("IPv4 network")
612 72cd5493 Jose A. Lopes
def _CheckCIDRNetNotation(value):
613 72cd5493 Jose A. Lopes
  """Ensure a given CIDR notation type is valid.
614 72cd5493 Jose A. Lopes

615 72cd5493 Jose A. Lopes
  """
616 72cd5493 Jose A. Lopes
  try:
617 72cd5493 Jose A. Lopes
    ipaddr.IPv4Network(value)
618 72cd5493 Jose A. Lopes
  except ipaddr.AddressValueError:
619 72cd5493 Jose A. Lopes
    return False
620 72cd5493 Jose A. Lopes
  return True
621 72cd5493 Jose A. Lopes
622 72cd5493 Jose A. Lopes
623 72cd5493 Jose A. Lopes
@WithDesc("IPv4 address")
624 72cd5493 Jose A. Lopes
def _CheckCIDRAddrNotation(value):
625 72cd5493 Jose A. Lopes
  """Ensure a given CIDR notation type is valid.
626 72cd5493 Jose A. Lopes

627 72cd5493 Jose A. Lopes
  """
628 72cd5493 Jose A. Lopes
  try:
629 72cd5493 Jose A. Lopes
    ipaddr.IPv4Address(value)
630 72cd5493 Jose A. Lopes
  except ipaddr.AddressValueError:
631 72cd5493 Jose A. Lopes
    return False
632 72cd5493 Jose A. Lopes
  return True
633 72cd5493 Jose A. Lopes
634 72cd5493 Jose A. Lopes
635 72cd5493 Jose A. Lopes
@WithDesc("IPv6 address")
636 72cd5493 Jose A. Lopes
def _CheckCIDR6AddrNotation(value):
637 72cd5493 Jose A. Lopes
  """Ensure a given CIDR notation type is valid.
638 72cd5493 Jose A. Lopes

639 72cd5493 Jose A. Lopes
  """
640 72cd5493 Jose A. Lopes
  try:
641 72cd5493 Jose A. Lopes
    ipaddr.IPv6Address(value)
642 72cd5493 Jose A. Lopes
  except ipaddr.AddressValueError:
643 72cd5493 Jose A. Lopes
    return False
644 72cd5493 Jose A. Lopes
  return True
645 72cd5493 Jose A. Lopes
646 72cd5493 Jose A. Lopes
647 72cd5493 Jose A. Lopes
@WithDesc("IPv6 network")
648 72cd5493 Jose A. Lopes
def _CheckCIDR6NetNotation(value):
649 72cd5493 Jose A. Lopes
  """Ensure a given CIDR notation type is valid.
650 72cd5493 Jose A. Lopes

651 72cd5493 Jose A. Lopes
  """
652 72cd5493 Jose A. Lopes
  try:
653 72cd5493 Jose A. Lopes
    ipaddr.IPv6Network(value)
654 72cd5493 Jose A. Lopes
  except ipaddr.AddressValueError:
655 72cd5493 Jose A. Lopes
    return False
656 72cd5493 Jose A. Lopes
  return True
657 72cd5493 Jose A. Lopes
658 72cd5493 Jose A. Lopes
659 72cd5493 Jose A. Lopes
TIPv4Address = TAnd(TString, _CheckCIDRAddrNotation)
660 72cd5493 Jose A. Lopes
TIPv6Address = TAnd(TString, _CheckCIDR6AddrNotation)
661 72cd5493 Jose A. Lopes
TIPv4Network = TAnd(TString, _CheckCIDRNetNotation)
662 72cd5493 Jose A. Lopes
TIPv6Network = TAnd(TString, _CheckCIDR6NetNotation)
663 72cd5493 Jose A. Lopes
664 72cd5493 Jose A. Lopes
665 72cd5493 Jose A. Lopes
def TObject(val_type):
666 72cd5493 Jose A. Lopes
  return TDictOf(TAny, val_type)
667 72cd5493 Jose A. Lopes
668 72cd5493 Jose A. Lopes
669 72cd5493 Jose A. Lopes
def TObjectCheck(obj, fields_types):
670 72cd5493 Jose A. Lopes
  """Helper to generate type checks for objects.
671 72cd5493 Jose A. Lopes

672 72cd5493 Jose A. Lopes
  @param obj: The object to generate type checks
673 72cd5493 Jose A. Lopes
  @param fields_types: The fields and their types as a dict
674 72cd5493 Jose A. Lopes
  @return: A ht type check function
675 72cd5493 Jose A. Lopes

676 72cd5493 Jose A. Lopes
  """
677 72cd5493 Jose A. Lopes
  assert set(obj.GetAllSlots()) == set(fields_types.keys()), \
678 72cd5493 Jose A. Lopes
    "%s != %s" % (set(obj.GetAllSlots()), set(fields_types.keys()))
679 72cd5493 Jose A. Lopes
  return TStrictDict(True, True, fields_types)
680 72cd5493 Jose A. Lopes
681 72cd5493 Jose A. Lopes
682 72cd5493 Jose A. Lopes
TQueryFieldDef = \
683 72cd5493 Jose A. Lopes
    TObjectCheck(objects.QueryFieldDefinition, {
684 72cd5493 Jose A. Lopes
        "name": TNonEmptyString,
685 72cd5493 Jose A. Lopes
        "title": TNonEmptyString,
686 72cd5493 Jose A. Lopes
        "kind": TElemOf(constants.QFT_ALL),
687 72cd5493 Jose A. Lopes
        "doc": TNonEmptyString
688 72cd5493 Jose A. Lopes
    })
689 72cd5493 Jose A. Lopes
690 72cd5493 Jose A. Lopes
TQueryRow = \
691 72cd5493 Jose A. Lopes
    TListOf(TAnd(TIsLength(2),
692 72cd5493 Jose A. Lopes
                 TItems([TElemOf(constants.RS_ALL), TAny])))
693 72cd5493 Jose A. Lopes
694 72cd5493 Jose A. Lopes
TQueryResult = TListOf(TQueryRow)
695 72cd5493 Jose A. Lopes
696 72cd5493 Jose A. Lopes
TQueryResponse = \
697 72cd5493 Jose A. Lopes
    TObjectCheck(objects.QueryResponse, {
698 72cd5493 Jose A. Lopes
        "fields": TListOf(TQueryFieldDef),
699 72cd5493 Jose A. Lopes
        "data": TQueryResult
700 72cd5493 Jose A. Lopes
    })
701 72cd5493 Jose A. Lopes
702 72cd5493 Jose A. Lopes
TQueryFieldsResponse = \
703 72cd5493 Jose A. Lopes
    TObjectCheck(objects.QueryFieldsResponse, {
704 72cd5493 Jose A. Lopes
        "fields": TListOf(TQueryFieldDef)
705 72cd5493 Jose A. Lopes
    })
706 72cd5493 Jose A. Lopes
707 72cd5493 Jose A. Lopes
TJobIdListItem = \
708 72cd5493 Jose A. Lopes
    TAnd(TIsLength(2),
709 72cd5493 Jose A. Lopes
         TItems([Comment("success")(TBool),
710 72cd5493 Jose A. Lopes
                 Comment("Job ID if successful, error message"
711 72cd5493 Jose A. Lopes
                         " otherwise")(TOr(TString, TJobId))]))
712 72cd5493 Jose A. Lopes
713 72cd5493 Jose A. Lopes
TJobIdList = TListOf(TJobIdListItem)
714 72cd5493 Jose A. Lopes
715 72cd5493 Jose A. Lopes
TJobIdListOnly = TStrictDict(True, True, {
716 72cd5493 Jose A. Lopes
  constants.JOB_IDS_KEY: Comment("List of submitted jobs")(TJobIdList)
717 72cd5493 Jose A. Lopes
  })
718 72cd5493 Jose A. Lopes
719 72cd5493 Jose A. Lopes
TInstanceMultiAllocResponse = \
720 72cd5493 Jose A. Lopes
    TStrictDict(True, True, {
721 72cd5493 Jose A. Lopes
      constants.JOB_IDS_KEY: Comment("List of submitted jobs")(TJobIdList),
722 884dc063 Jose A. Lopes
      constants.ALLOCATABLE_KEY: TListOf(TNonEmptyString),
723 884dc063 Jose A. Lopes
      constants.FAILED_KEY: TListOf(TNonEmptyString)
724 72cd5493 Jose A. Lopes
    })