Statistics
| Branch: | Tag: | Revision:

root / lib / query.py @ 7925d409

History | View | Annotate | Download (53.8 kB)

1 4ca96421 Michael Hanselmann
#
2 4ca96421 Michael Hanselmann
#
3 4ca96421 Michael Hanselmann
4 82599b3e Iustin Pop
# Copyright (C) 2010, 2011 Google Inc.
5 4ca96421 Michael Hanselmann
#
6 4ca96421 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 4ca96421 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 4ca96421 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 4ca96421 Michael Hanselmann
# (at your option) any later version.
10 4ca96421 Michael Hanselmann
#
11 4ca96421 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 4ca96421 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 4ca96421 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 4ca96421 Michael Hanselmann
# General Public License for more details.
15 4ca96421 Michael Hanselmann
#
16 4ca96421 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 4ca96421 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 4ca96421 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 4ca96421 Michael Hanselmann
# 02110-1301, USA.
20 4ca96421 Michael Hanselmann
21 4ca96421 Michael Hanselmann
22 8f8ce6d1 Michael Hanselmann
"""Module for query operations
23 8f8ce6d1 Michael Hanselmann

24 8f8ce6d1 Michael Hanselmann
How it works:
25 8f8ce6d1 Michael Hanselmann

26 8f8ce6d1 Michael Hanselmann
  - Add field definitions
27 8f8ce6d1 Michael Hanselmann
    - See how L{NODE_FIELDS} is built
28 8f8ce6d1 Michael Hanselmann
    - Each field gets:
29 8f8ce6d1 Michael Hanselmann
      - Query field definition (L{objects.QueryFieldDefinition}, use
30 8f8ce6d1 Michael Hanselmann
        L{_MakeField} for creating), containing:
31 8f8ce6d1 Michael Hanselmann
          - Name, must be lowercase and match L{FIELD_NAME_RE}
32 8f8ce6d1 Michael Hanselmann
          - Title for tables, must not contain whitespace and match
33 8f8ce6d1 Michael Hanselmann
            L{TITLE_RE}
34 8f8ce6d1 Michael Hanselmann
          - Value data type, e.g. L{constants.QFT_NUMBER}
35 79b2ca83 Michael Hanselmann
          - Human-readable description, must not end with punctuation or
36 79b2ca83 Michael Hanselmann
            contain newlines
37 8f8ce6d1 Michael Hanselmann
      - Data request type, see e.g. C{NQ_*}
38 111bf531 Michael Hanselmann
      - OR-ed flags, see C{QFF_*}
39 8f8ce6d1 Michael Hanselmann
      - A retrieval function, see L{Query.__init__} for description
40 8f8ce6d1 Michael Hanselmann
    - Pass list of fields through L{_PrepareFieldList} for preparation and
41 8f8ce6d1 Michael Hanselmann
      checks
42 8f8ce6d1 Michael Hanselmann
  - Instantiate L{Query} with prepared field list definition and selected fields
43 8f8ce6d1 Michael Hanselmann
  - Call L{Query.RequestedData} to determine what data to collect/compute
44 8f8ce6d1 Michael Hanselmann
  - Call L{Query.Query} or L{Query.OldStyleQuery} with collected data and use
45 8f8ce6d1 Michael Hanselmann
    result
46 8f8ce6d1 Michael Hanselmann
      - Data container must support iteration using C{__iter__}
47 8f8ce6d1 Michael Hanselmann
      - Items are passed to retrieval functions and can have any format
48 8f8ce6d1 Michael Hanselmann
  - Call L{Query.GetFields} to get list of definitions for selected fields
49 8f8ce6d1 Michael Hanselmann

50 8f8ce6d1 Michael Hanselmann
@attention: Retrieval functions must be idempotent. They can be called multiple
51 fb0be379 Michael Hanselmann
  times, in any order and any number of times.
52 8f8ce6d1 Michael Hanselmann

53 8f8ce6d1 Michael Hanselmann
"""
54 4ca96421 Michael Hanselmann
55 8235fe04 Michael Hanselmann
import logging
56 4ca96421 Michael Hanselmann
import operator
57 4ca96421 Michael Hanselmann
import re
58 4ca96421 Michael Hanselmann
59 4ca96421 Michael Hanselmann
from ganeti import constants
60 4ca96421 Michael Hanselmann
from ganeti import errors
61 4ca96421 Michael Hanselmann
from ganeti import utils
62 4ca96421 Michael Hanselmann
from ganeti import compat
63 4ca96421 Michael Hanselmann
from ganeti import objects
64 4ca96421 Michael Hanselmann
from ganeti import ht
65 fb0be379 Michael Hanselmann
from ganeti import qlang
66 4ca96421 Michael Hanselmann
67 82599b3e Iustin Pop
from ganeti.constants import (QFT_UNKNOWN, QFT_TEXT, QFT_BOOL, QFT_NUMBER,
68 82599b3e Iustin Pop
                              QFT_UNIT, QFT_TIMESTAMP, QFT_OTHER,
69 cfb084ae René Nussbaumer
                              RS_NORMAL, RS_UNKNOWN, RS_NODATA,
70 cfb084ae René Nussbaumer
                              RS_UNAVAIL, RS_OFFLINE)
71 82599b3e Iustin Pop
72 4ca96421 Michael Hanselmann
73 8f8ce6d1 Michael Hanselmann
# Constants for requesting data from the caller/data provider. Each property
74 8f8ce6d1 Michael Hanselmann
# collected/computed separately by the data provider should have its own to
75 8f8ce6d1 Michael Hanselmann
# only collect the requested data and not more.
76 8f8ce6d1 Michael Hanselmann
77 8235fe04 Michael Hanselmann
(NQ_CONFIG,
78 8235fe04 Michael Hanselmann
 NQ_INST,
79 8235fe04 Michael Hanselmann
 NQ_LIVE,
80 52b5d286 René Nussbaumer
 NQ_GROUP,
81 52b5d286 René Nussbaumer
 NQ_OOB) = range(1, 6)
82 8235fe04 Michael Hanselmann
83 1c8addc6 Michael Hanselmann
(IQ_CONFIG,
84 1c8addc6 Michael Hanselmann
 IQ_LIVE,
85 5d28cb6f Michael Hanselmann
 IQ_DISKUSAGE,
86 5d28cb6f Michael Hanselmann
 IQ_CONSOLE) = range(100, 104)
87 1c8addc6 Michael Hanselmann
88 24d16f76 Michael Hanselmann
(LQ_MODE,
89 24d16f76 Michael Hanselmann
 LQ_OWNER,
90 24d16f76 Michael Hanselmann
 LQ_PENDING) = range(10, 13)
91 8235fe04 Michael Hanselmann
92 8e21cfc0 Adeodato Simo
(GQ_CONFIG,
93 8e21cfc0 Adeodato Simo
 GQ_NODE,
94 8e21cfc0 Adeodato Simo
 GQ_INST) = range(200, 203)
95 8e21cfc0 Adeodato Simo
96 111bf531 Michael Hanselmann
# Query field flags
97 111bf531 Michael Hanselmann
QFF_HOSTNAME = 0x01
98 111bf531 Michael Hanselmann
QFF_IP_ADDRESS = 0x02
99 111bf531 Michael Hanselmann
# Next values: 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100, 0x200
100 111bf531 Michael Hanselmann
QFF_ALL = (QFF_HOSTNAME | QFF_IP_ADDRESS)
101 8e21cfc0 Adeodato Simo
102 4ca96421 Michael Hanselmann
FIELD_NAME_RE = re.compile(r"^[a-z0-9/._]+$")
103 4ca96421 Michael Hanselmann
TITLE_RE = re.compile(r"^[^\s]+$")
104 1ae17369 Michael Hanselmann
DOC_RE = re.compile(r"^[A-Z].*[^.,?!]$")
105 4ca96421 Michael Hanselmann
106 4ca96421 Michael Hanselmann
#: Verification function for each field type
107 4ca96421 Michael Hanselmann
_VERIFY_FN = {
108 82599b3e Iustin Pop
  QFT_UNKNOWN: ht.TNone,
109 82599b3e Iustin Pop
  QFT_TEXT: ht.TString,
110 82599b3e Iustin Pop
  QFT_BOOL: ht.TBool,
111 82599b3e Iustin Pop
  QFT_NUMBER: ht.TInt,
112 82599b3e Iustin Pop
  QFT_UNIT: ht.TInt,
113 82599b3e Iustin Pop
  QFT_TIMESTAMP: ht.TOr(ht.TInt, ht.TFloat),
114 82599b3e Iustin Pop
  QFT_OTHER: lambda _: True,
115 4ca96421 Michael Hanselmann
  }
116 4ca96421 Michael Hanselmann
117 e2d188cc Iustin Pop
# Unique objects for special field statuses
118 e2d188cc Iustin Pop
_FS_UNKNOWN = object()
119 e2d188cc Iustin Pop
_FS_NODATA = object()
120 e2d188cc Iustin Pop
_FS_UNAVAIL = object()
121 e2d188cc Iustin Pop
_FS_OFFLINE = object()
122 e2d188cc Iustin Pop
123 af58707c Iustin Pop
#: VType to QFT mapping
124 af58707c Iustin Pop
_VTToQFT = {
125 af58707c Iustin Pop
  # TODO: fix validation of empty strings
126 af58707c Iustin Pop
  constants.VTYPE_STRING: QFT_OTHER, # since VTYPE_STRINGs can be empty
127 af58707c Iustin Pop
  constants.VTYPE_MAYBE_STRING: QFT_OTHER,
128 af58707c Iustin Pop
  constants.VTYPE_BOOL: QFT_BOOL,
129 af58707c Iustin Pop
  constants.VTYPE_SIZE: QFT_UNIT,
130 af58707c Iustin Pop
  constants.VTYPE_INT: QFT_NUMBER,
131 af58707c Iustin Pop
  }
132 af58707c Iustin Pop
133 79b2ca83 Michael Hanselmann
_SERIAL_NO_DOC = "%s object serial number, incremented on each modification"
134 79b2ca83 Michael Hanselmann
135 4ca96421 Michael Hanselmann
136 4ca96421 Michael Hanselmann
def _GetUnknownField(ctx, item): # pylint: disable-msg=W0613
137 4ca96421 Michael Hanselmann
  """Gets the contents of an unknown field.
138 4ca96421 Michael Hanselmann

139 4ca96421 Michael Hanselmann
  """
140 e2d188cc Iustin Pop
  return _FS_UNKNOWN
141 4ca96421 Michael Hanselmann
142 4ca96421 Michael Hanselmann
143 4ca96421 Michael Hanselmann
def _GetQueryFields(fielddefs, selected):
144 4ca96421 Michael Hanselmann
  """Calculates the internal list of selected fields.
145 4ca96421 Michael Hanselmann

146 4ca96421 Michael Hanselmann
  Unknown fields are returned as L{constants.QFT_UNKNOWN}.
147 4ca96421 Michael Hanselmann

148 4ca96421 Michael Hanselmann
  @type fielddefs: dict
149 4ca96421 Michael Hanselmann
  @param fielddefs: Field definitions
150 4ca96421 Michael Hanselmann
  @type selected: list of strings
151 4ca96421 Michael Hanselmann
  @param selected: List of selected fields
152 4ca96421 Michael Hanselmann

153 4ca96421 Michael Hanselmann
  """
154 4ca96421 Michael Hanselmann
  result = []
155 4ca96421 Michael Hanselmann
156 4ca96421 Michael Hanselmann
  for name in selected:
157 4ca96421 Michael Hanselmann
    try:
158 4ca96421 Michael Hanselmann
      fdef = fielddefs[name]
159 4ca96421 Michael Hanselmann
    except KeyError:
160 79b2ca83 Michael Hanselmann
      fdef = (_MakeField(name, name, QFT_UNKNOWN, "Unknown field '%s'" % name),
161 111bf531 Michael Hanselmann
              None, 0, _GetUnknownField)
162 4ca96421 Michael Hanselmann
163 111bf531 Michael Hanselmann
    assert len(fdef) == 4
164 4ca96421 Michael Hanselmann
165 4ca96421 Michael Hanselmann
    result.append(fdef)
166 4ca96421 Michael Hanselmann
167 4ca96421 Michael Hanselmann
  return result
168 4ca96421 Michael Hanselmann
169 4ca96421 Michael Hanselmann
170 4ca96421 Michael Hanselmann
def GetAllFields(fielddefs):
171 4ca96421 Michael Hanselmann
  """Extract L{objects.QueryFieldDefinition} from field definitions.
172 4ca96421 Michael Hanselmann

173 4ca96421 Michael Hanselmann
  @rtype: list of L{objects.QueryFieldDefinition}
174 4ca96421 Michael Hanselmann

175 4ca96421 Michael Hanselmann
  """
176 111bf531 Michael Hanselmann
  return [fdef for (fdef, _, _, _) in fielddefs]
177 4ca96421 Michael Hanselmann
178 4ca96421 Michael Hanselmann
179 fb0be379 Michael Hanselmann
class _FilterHints:
180 fb0be379 Michael Hanselmann
  """Class for filter analytics.
181 fb0be379 Michael Hanselmann

182 fb0be379 Michael Hanselmann
  When filters are used, the user of the L{Query} class usually doesn't know
183 fb0be379 Michael Hanselmann
  exactly which items will be necessary for building the result. It therefore
184 fb0be379 Michael Hanselmann
  has to prepare and compute the input data for potentially returning
185 fb0be379 Michael Hanselmann
  everything.
186 fb0be379 Michael Hanselmann

187 fb0be379 Michael Hanselmann
  There are two ways to optimize this. The first, and simpler, is to assign
188 fb0be379 Michael Hanselmann
  each field a group of data, so that the caller can determine which
189 fb0be379 Michael Hanselmann
  computations are necessary depending on the data groups requested. The list
190 fb0be379 Michael Hanselmann
  of referenced groups must also be computed for fields referenced in the
191 fb0be379 Michael Hanselmann
  filter.
192 fb0be379 Michael Hanselmann

193 fb0be379 Michael Hanselmann
  The second is restricting the items based on a primary key. The primary key
194 fb0be379 Michael Hanselmann
  is usually a unique name (e.g. a node name). This class extracts all
195 fb0be379 Michael Hanselmann
  referenced names from a filter. If it encounters any filter condition which
196 fb0be379 Michael Hanselmann
  disallows such a list to be determined (e.g. a non-equality filter), all
197 fb0be379 Michael Hanselmann
  names will be requested.
198 fb0be379 Michael Hanselmann

199 fb0be379 Michael Hanselmann
  The end-effect is that any operation other than L{qlang.OP_OR} and
200 fb0be379 Michael Hanselmann
  L{qlang.OP_EQUAL} will make the query more expensive.
201 fb0be379 Michael Hanselmann

202 fb0be379 Michael Hanselmann
  """
203 fb0be379 Michael Hanselmann
  def __init__(self, namefield):
204 fb0be379 Michael Hanselmann
    """Initializes this class.
205 fb0be379 Michael Hanselmann

206 fb0be379 Michael Hanselmann
    @type namefield: string
207 fb0be379 Michael Hanselmann
    @param namefield: Field caller is interested in
208 fb0be379 Michael Hanselmann

209 fb0be379 Michael Hanselmann
    """
210 fb0be379 Michael Hanselmann
    self._namefield = namefield
211 fb0be379 Michael Hanselmann
212 fb0be379 Michael Hanselmann
    #: Whether all names need to be requested (e.g. if a non-equality operator
213 fb0be379 Michael Hanselmann
    #: has been used)
214 fb0be379 Michael Hanselmann
    self._allnames = False
215 fb0be379 Michael Hanselmann
216 fb0be379 Michael Hanselmann
    #: Which names to request
217 fb0be379 Michael Hanselmann
    self._names = None
218 fb0be379 Michael Hanselmann
219 fb0be379 Michael Hanselmann
    #: Data kinds referenced by the filter (used by L{Query.RequestedData})
220 fb0be379 Michael Hanselmann
    self._datakinds = set()
221 fb0be379 Michael Hanselmann
222 fb0be379 Michael Hanselmann
  def RequestedNames(self):
223 fb0be379 Michael Hanselmann
    """Returns all requested values.
224 fb0be379 Michael Hanselmann

225 fb0be379 Michael Hanselmann
    Returns C{None} if list of values can't be determined (e.g. encountered
226 fb0be379 Michael Hanselmann
    non-equality operators).
227 fb0be379 Michael Hanselmann

228 fb0be379 Michael Hanselmann
    @rtype: list
229 fb0be379 Michael Hanselmann

230 fb0be379 Michael Hanselmann
    """
231 fb0be379 Michael Hanselmann
    if self._allnames or self._names is None:
232 fb0be379 Michael Hanselmann
      return None
233 fb0be379 Michael Hanselmann
234 fb0be379 Michael Hanselmann
    return utils.UniqueSequence(self._names)
235 fb0be379 Michael Hanselmann
236 fb0be379 Michael Hanselmann
  def ReferencedData(self):
237 fb0be379 Michael Hanselmann
    """Returns all kinds of data referenced by the filter.
238 fb0be379 Michael Hanselmann

239 fb0be379 Michael Hanselmann
    """
240 fb0be379 Michael Hanselmann
    return frozenset(self._datakinds)
241 fb0be379 Michael Hanselmann
242 fb0be379 Michael Hanselmann
  def _NeedAllNames(self):
243 fb0be379 Michael Hanselmann
    """Changes internal state to request all names.
244 fb0be379 Michael Hanselmann

245 fb0be379 Michael Hanselmann
    """
246 fb0be379 Michael Hanselmann
    self._allnames = True
247 fb0be379 Michael Hanselmann
    self._names = None
248 fb0be379 Michael Hanselmann
249 fb0be379 Michael Hanselmann
  def NoteLogicOp(self, op):
250 fb0be379 Michael Hanselmann
    """Called when handling a logic operation.
251 fb0be379 Michael Hanselmann

252 fb0be379 Michael Hanselmann
    @type op: string
253 fb0be379 Michael Hanselmann
    @param op: Operator
254 fb0be379 Michael Hanselmann

255 fb0be379 Michael Hanselmann
    """
256 fb0be379 Michael Hanselmann
    if op != qlang.OP_OR:
257 fb0be379 Michael Hanselmann
      self._NeedAllNames()
258 fb0be379 Michael Hanselmann
259 fb0be379 Michael Hanselmann
  def NoteUnaryOp(self, op): # pylint: disable-msg=W0613
260 fb0be379 Michael Hanselmann
    """Called when handling an unary operation.
261 fb0be379 Michael Hanselmann

262 fb0be379 Michael Hanselmann
    @type op: string
263 fb0be379 Michael Hanselmann
    @param op: Operator
264 fb0be379 Michael Hanselmann

265 fb0be379 Michael Hanselmann
    """
266 fb0be379 Michael Hanselmann
    self._NeedAllNames()
267 fb0be379 Michael Hanselmann
268 fb0be379 Michael Hanselmann
  def NoteBinaryOp(self, op, datakind, name, value):
269 fb0be379 Michael Hanselmann
    """Called when handling a binary operation.
270 fb0be379 Michael Hanselmann

271 fb0be379 Michael Hanselmann
    @type op: string
272 fb0be379 Michael Hanselmann
    @param op: Operator
273 fb0be379 Michael Hanselmann
    @type name: string
274 fb0be379 Michael Hanselmann
    @param name: Left-hand side of operator (field name)
275 fb0be379 Michael Hanselmann
    @param value: Right-hand side of operator
276 fb0be379 Michael Hanselmann

277 fb0be379 Michael Hanselmann
    """
278 fb0be379 Michael Hanselmann
    if datakind is not None:
279 fb0be379 Michael Hanselmann
      self._datakinds.add(datakind)
280 fb0be379 Michael Hanselmann
281 fb0be379 Michael Hanselmann
    if self._allnames:
282 fb0be379 Michael Hanselmann
      return
283 fb0be379 Michael Hanselmann
284 fb0be379 Michael Hanselmann
    # If any operator other than equality was used, all names need to be
285 fb0be379 Michael Hanselmann
    # retrieved
286 fb0be379 Michael Hanselmann
    if op == qlang.OP_EQUAL and name == self._namefield:
287 fb0be379 Michael Hanselmann
      if self._names is None:
288 fb0be379 Michael Hanselmann
        self._names = []
289 fb0be379 Michael Hanselmann
      self._names.append(value)
290 fb0be379 Michael Hanselmann
    else:
291 fb0be379 Michael Hanselmann
      self._NeedAllNames()
292 fb0be379 Michael Hanselmann
293 fb0be379 Michael Hanselmann
294 fb0be379 Michael Hanselmann
def _WrapLogicOp(op_fn, sentences, ctx, item):
295 fb0be379 Michael Hanselmann
  """Wrapper for logic operator functions.
296 fb0be379 Michael Hanselmann

297 fb0be379 Michael Hanselmann
  """
298 fb0be379 Michael Hanselmann
  return op_fn(fn(ctx, item) for fn in sentences)
299 fb0be379 Michael Hanselmann
300 fb0be379 Michael Hanselmann
301 fb0be379 Michael Hanselmann
def _WrapUnaryOp(op_fn, inner, ctx, item):
302 fb0be379 Michael Hanselmann
  """Wrapper for unary operator functions.
303 fb0be379 Michael Hanselmann

304 fb0be379 Michael Hanselmann
  """
305 fb0be379 Michael Hanselmann
  return op_fn(inner(ctx, item))
306 fb0be379 Michael Hanselmann
307 fb0be379 Michael Hanselmann
308 fb0be379 Michael Hanselmann
def _WrapBinaryOp(op_fn, retrieval_fn, value, ctx, item):
309 fb0be379 Michael Hanselmann
  """Wrapper for binary operator functions.
310 fb0be379 Michael Hanselmann

311 fb0be379 Michael Hanselmann
  """
312 fb0be379 Michael Hanselmann
  return op_fn(retrieval_fn(ctx, item), value)
313 fb0be379 Michael Hanselmann
314 fb0be379 Michael Hanselmann
315 fb0be379 Michael Hanselmann
def _WrapNot(fn, lhs, rhs):
316 fb0be379 Michael Hanselmann
  """Negates the result of a wrapped function.
317 fb0be379 Michael Hanselmann

318 fb0be379 Michael Hanselmann
  """
319 fb0be379 Michael Hanselmann
  return not fn(lhs, rhs)
320 fb0be379 Michael Hanselmann
321 fb0be379 Michael Hanselmann
322 fb0be379 Michael Hanselmann
class _FilterCompilerHelper:
323 fb0be379 Michael Hanselmann
  """Converts a query filter to a callable usable for filtering.
324 fb0be379 Michael Hanselmann

325 fb0be379 Michael Hanselmann
  """
326 fb0be379 Michael Hanselmann
  # String statement has no effect, pylint: disable-msg=W0105
327 fb0be379 Michael Hanselmann
328 fb0be379 Michael Hanselmann
  #: How deep filters can be nested
329 fb0be379 Michael Hanselmann
  _LEVELS_MAX = 10
330 fb0be379 Michael Hanselmann
331 fb0be379 Michael Hanselmann
  # Unique identifiers for operator groups
332 fb0be379 Michael Hanselmann
  (_OPTYPE_LOGIC,
333 fb0be379 Michael Hanselmann
   _OPTYPE_UNARY,
334 fb0be379 Michael Hanselmann
   _OPTYPE_BINARY) = range(1, 4)
335 fb0be379 Michael Hanselmann
336 fb0be379 Michael Hanselmann
  """Functions for equality checks depending on field flags.
337 fb0be379 Michael Hanselmann

338 fb0be379 Michael Hanselmann
  List of tuples containing flags and a callable receiving the left- and
339 fb0be379 Michael Hanselmann
  right-hand side of the operator. The flags are an OR-ed value of C{QFF_*}
340 fb0be379 Michael Hanselmann
  (e.g. L{QFF_HOSTNAME}).
341 fb0be379 Michael Hanselmann

342 fb0be379 Michael Hanselmann
  Order matters. The first item with flags will be used. Flags are checked
343 fb0be379 Michael Hanselmann
  using binary AND.
344 fb0be379 Michael Hanselmann

345 fb0be379 Michael Hanselmann
  """
346 fb0be379 Michael Hanselmann
  _EQUALITY_CHECKS = [
347 fb0be379 Michael Hanselmann
    (QFF_HOSTNAME,
348 fb0be379 Michael Hanselmann
     lambda lhs, rhs: utils.MatchNameComponent(rhs, [lhs],
349 fb0be379 Michael Hanselmann
                                               case_sensitive=False)),
350 fb0be379 Michael Hanselmann
    (None, operator.eq),
351 fb0be379 Michael Hanselmann
    ]
352 fb0be379 Michael Hanselmann
353 fb0be379 Michael Hanselmann
  """Known operators
354 fb0be379 Michael Hanselmann

355 fb0be379 Michael Hanselmann
  Operator as key (C{qlang.OP_*}), value a tuple of operator group
356 fb0be379 Michael Hanselmann
  (C{_OPTYPE_*}) and a group-specific value:
357 fb0be379 Michael Hanselmann

358 fb0be379 Michael Hanselmann
    - C{_OPTYPE_LOGIC}: Callable taking any number of arguments; used by
359 fb0be379 Michael Hanselmann
      L{_HandleLogicOp}
360 fb0be379 Michael Hanselmann
    - C{_OPTYPE_UNARY}: Callable taking exactly one parameter; used by
361 fb0be379 Michael Hanselmann
      L{_HandleUnaryOp}
362 fb0be379 Michael Hanselmann
    - C{_OPTYPE_BINARY}: Callable taking exactly two parameters, the left- and
363 fb0be379 Michael Hanselmann
      right-hand side of the operator, used by L{_HandleBinaryOp}
364 fb0be379 Michael Hanselmann

365 fb0be379 Michael Hanselmann
  """
366 fb0be379 Michael Hanselmann
  _OPS = {
367 fb0be379 Michael Hanselmann
    # Logic operators
368 fb0be379 Michael Hanselmann
    qlang.OP_OR: (_OPTYPE_LOGIC, compat.any),
369 fb0be379 Michael Hanselmann
    qlang.OP_AND: (_OPTYPE_LOGIC, compat.all),
370 fb0be379 Michael Hanselmann
371 fb0be379 Michael Hanselmann
    # Unary operators
372 fb0be379 Michael Hanselmann
    qlang.OP_NOT: (_OPTYPE_UNARY, operator.not_),
373 fb0be379 Michael Hanselmann
374 fb0be379 Michael Hanselmann
    # Binary operators
375 fb0be379 Michael Hanselmann
    qlang.OP_EQUAL: (_OPTYPE_BINARY, _EQUALITY_CHECKS),
376 fb0be379 Michael Hanselmann
    qlang.OP_NOT_EQUAL:
377 fb0be379 Michael Hanselmann
      (_OPTYPE_BINARY, [(flags, compat.partial(_WrapNot, fn))
378 fb0be379 Michael Hanselmann
                        for (flags, fn) in _EQUALITY_CHECKS]),
379 fb0be379 Michael Hanselmann
    qlang.OP_GLOB: (_OPTYPE_BINARY, NotImplemented),
380 fb0be379 Michael Hanselmann
    qlang.OP_REGEXP: (_OPTYPE_BINARY, NotImplemented),
381 fb0be379 Michael Hanselmann
    qlang.OP_CONTAINS: (_OPTYPE_BINARY, [
382 fb0be379 Michael Hanselmann
      (None, operator.contains),
383 fb0be379 Michael Hanselmann
      ]),
384 fb0be379 Michael Hanselmann
    }
385 fb0be379 Michael Hanselmann
386 fb0be379 Michael Hanselmann
  def __init__(self, fields):
387 fb0be379 Michael Hanselmann
    """Initializes this class.
388 fb0be379 Michael Hanselmann

389 fb0be379 Michael Hanselmann
    @param fields: Field definitions (return value of L{_PrepareFieldList})
390 fb0be379 Michael Hanselmann

391 fb0be379 Michael Hanselmann
    """
392 fb0be379 Michael Hanselmann
    self._fields = fields
393 fb0be379 Michael Hanselmann
    self._hints = None
394 fb0be379 Michael Hanselmann
    self._op_handler = None
395 fb0be379 Michael Hanselmann
396 fb0be379 Michael Hanselmann
  def __call__(self, hints, filter_):
397 fb0be379 Michael Hanselmann
    """Converts a query filter into a callable function.
398 fb0be379 Michael Hanselmann

399 fb0be379 Michael Hanselmann
    @type hints: L{_FilterHints} or None
400 fb0be379 Michael Hanselmann
    @param hints: Callbacks doing analysis on filter
401 fb0be379 Michael Hanselmann
    @type filter_: list
402 fb0be379 Michael Hanselmann
    @param filter_: Filter structure
403 fb0be379 Michael Hanselmann
    @rtype: callable
404 fb0be379 Michael Hanselmann
    @return: Function receiving context and item as parameters, returning
405 fb0be379 Michael Hanselmann
             boolean as to whether item matches filter
406 fb0be379 Michael Hanselmann

407 fb0be379 Michael Hanselmann
    """
408 fb0be379 Michael Hanselmann
    self._op_handler = {
409 fb0be379 Michael Hanselmann
      self._OPTYPE_LOGIC:
410 fb0be379 Michael Hanselmann
        (self._HandleLogicOp, getattr(hints, "NoteLogicOp", None)),
411 fb0be379 Michael Hanselmann
      self._OPTYPE_UNARY:
412 fb0be379 Michael Hanselmann
        (self._HandleUnaryOp, getattr(hints, "NoteUnaryOp", None)),
413 fb0be379 Michael Hanselmann
      self._OPTYPE_BINARY:
414 fb0be379 Michael Hanselmann
        (self._HandleBinaryOp, getattr(hints, "NoteBinaryOp", None)),
415 fb0be379 Michael Hanselmann
      }
416 fb0be379 Michael Hanselmann
417 fb0be379 Michael Hanselmann
    try:
418 fb0be379 Michael Hanselmann
      filter_fn = self._Compile(filter_, 0)
419 fb0be379 Michael Hanselmann
    finally:
420 fb0be379 Michael Hanselmann
      self._op_handler = None
421 fb0be379 Michael Hanselmann
422 fb0be379 Michael Hanselmann
    return filter_fn
423 fb0be379 Michael Hanselmann
424 fb0be379 Michael Hanselmann
  def _Compile(self, filter_, level):
425 fb0be379 Michael Hanselmann
    """Inner function for converting filters.
426 fb0be379 Michael Hanselmann

427 fb0be379 Michael Hanselmann
    Calls the correct handler functions for the top-level operator. This
428 fb0be379 Michael Hanselmann
    function is called recursively (e.g. for logic operators).
429 fb0be379 Michael Hanselmann

430 fb0be379 Michael Hanselmann
    """
431 fb0be379 Michael Hanselmann
    if not (isinstance(filter_, (list, tuple)) and filter_):
432 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Invalid filter on level %s" % level)
433 fb0be379 Michael Hanselmann
434 fb0be379 Michael Hanselmann
    # Limit recursion
435 fb0be379 Michael Hanselmann
    if level >= self._LEVELS_MAX:
436 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Only up to %s levels are allowed (filter"
437 fb0be379 Michael Hanselmann
                                  " nested too deep)" % self._LEVELS_MAX)
438 fb0be379 Michael Hanselmann
439 fb0be379 Michael Hanselmann
    # Create copy to be modified
440 fb0be379 Michael Hanselmann
    operands = filter_[:]
441 fb0be379 Michael Hanselmann
    op = operands.pop(0)
442 fb0be379 Michael Hanselmann
443 fb0be379 Michael Hanselmann
    try:
444 fb0be379 Michael Hanselmann
      (kind, op_data) = self._OPS[op]
445 fb0be379 Michael Hanselmann
    except KeyError:
446 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unknown operator '%s'" % op)
447 fb0be379 Michael Hanselmann
448 fb0be379 Michael Hanselmann
    (handler, hints_cb) = self._op_handler[kind]
449 fb0be379 Michael Hanselmann
450 fb0be379 Michael Hanselmann
    return handler(hints_cb, level, op, op_data, operands)
451 fb0be379 Michael Hanselmann
452 fb0be379 Michael Hanselmann
  def _HandleLogicOp(self, hints_fn, level, op, op_fn, operands):
453 fb0be379 Michael Hanselmann
    """Handles logic operators.
454 fb0be379 Michael Hanselmann

455 fb0be379 Michael Hanselmann
    @type hints_fn: callable
456 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
457 fb0be379 Michael Hanselmann
    @type level: integer
458 fb0be379 Michael Hanselmann
    @param level: Current depth
459 fb0be379 Michael Hanselmann
    @type op: string
460 fb0be379 Michael Hanselmann
    @param op: Operator
461 fb0be379 Michael Hanselmann
    @type op_fn: callable
462 fb0be379 Michael Hanselmann
    @param op_fn: Function implementing operator
463 fb0be379 Michael Hanselmann
    @type operands: list
464 fb0be379 Michael Hanselmann
    @param operands: List of operands
465 fb0be379 Michael Hanselmann

466 fb0be379 Michael Hanselmann
    """
467 fb0be379 Michael Hanselmann
    if hints_fn:
468 fb0be379 Michael Hanselmann
      hints_fn(op)
469 fb0be379 Michael Hanselmann
470 fb0be379 Michael Hanselmann
    return compat.partial(_WrapLogicOp, op_fn,
471 fb0be379 Michael Hanselmann
                          [self._Compile(op, level + 1) for op in operands])
472 fb0be379 Michael Hanselmann
473 fb0be379 Michael Hanselmann
  def _HandleUnaryOp(self, hints_fn, level, op, op_fn, operands):
474 fb0be379 Michael Hanselmann
    """Handles unary operators.
475 fb0be379 Michael Hanselmann

476 fb0be379 Michael Hanselmann
    @type hints_fn: callable
477 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
478 fb0be379 Michael Hanselmann
    @type level: integer
479 fb0be379 Michael Hanselmann
    @param level: Current depth
480 fb0be379 Michael Hanselmann
    @type op: string
481 fb0be379 Michael Hanselmann
    @param op: Operator
482 fb0be379 Michael Hanselmann
    @type op_fn: callable
483 fb0be379 Michael Hanselmann
    @param op_fn: Function implementing operator
484 fb0be379 Michael Hanselmann
    @type operands: list
485 fb0be379 Michael Hanselmann
    @param operands: List of operands
486 fb0be379 Michael Hanselmann

487 fb0be379 Michael Hanselmann
    """
488 fb0be379 Michael Hanselmann
    if hints_fn:
489 fb0be379 Michael Hanselmann
      hints_fn(op)
490 fb0be379 Michael Hanselmann
491 fb0be379 Michael Hanselmann
    if len(operands) != 1:
492 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unary operator '%s' expects exactly one"
493 fb0be379 Michael Hanselmann
                                  " operand" % op)
494 fb0be379 Michael Hanselmann
495 fb0be379 Michael Hanselmann
    return compat.partial(_WrapUnaryOp, op_fn,
496 fb0be379 Michael Hanselmann
                          self._Compile(operands[0], level + 1))
497 fb0be379 Michael Hanselmann
498 fb0be379 Michael Hanselmann
  def _HandleBinaryOp(self, hints_fn, level, op, op_data, operands):
499 fb0be379 Michael Hanselmann
    """Handles binary operators.
500 fb0be379 Michael Hanselmann

501 fb0be379 Michael Hanselmann
    @type hints_fn: callable
502 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
503 fb0be379 Michael Hanselmann
    @type level: integer
504 fb0be379 Michael Hanselmann
    @param level: Current depth
505 fb0be379 Michael Hanselmann
    @type op: string
506 fb0be379 Michael Hanselmann
    @param op: Operator
507 fb0be379 Michael Hanselmann
    @param op_data: Functions implementing operators
508 fb0be379 Michael Hanselmann
    @type operands: list
509 fb0be379 Michael Hanselmann
    @param operands: List of operands
510 fb0be379 Michael Hanselmann

511 fb0be379 Michael Hanselmann
    """
512 fb0be379 Michael Hanselmann
    # Unused arguments, pylint: disable-msg=W0613
513 fb0be379 Michael Hanselmann
    try:
514 fb0be379 Michael Hanselmann
      (name, value) = operands
515 fb0be379 Michael Hanselmann
    except (ValueError, TypeError):
516 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Invalid binary operator, expected exactly"
517 fb0be379 Michael Hanselmann
                                  " two operands")
518 fb0be379 Michael Hanselmann
519 fb0be379 Michael Hanselmann
    try:
520 fb0be379 Michael Hanselmann
      (fdef, datakind, field_flags, retrieval_fn) = self._fields[name]
521 fb0be379 Michael Hanselmann
    except KeyError:
522 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unknown field '%s'" % name)
523 fb0be379 Michael Hanselmann
524 fb0be379 Michael Hanselmann
    assert fdef.kind != QFT_UNKNOWN
525 fb0be379 Michael Hanselmann
526 fb0be379 Michael Hanselmann
    # TODO: Type conversions?
527 fb0be379 Michael Hanselmann
528 fb0be379 Michael Hanselmann
    verify_fn = _VERIFY_FN[fdef.kind]
529 fb0be379 Michael Hanselmann
    if not verify_fn(value):
530 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unable to compare field '%s' (type '%s')"
531 fb0be379 Michael Hanselmann
                                  " with '%s', expected %s" %
532 fb0be379 Michael Hanselmann
                                  (name, fdef.kind, value.__class__.__name__,
533 fb0be379 Michael Hanselmann
                                   verify_fn))
534 fb0be379 Michael Hanselmann
535 fb0be379 Michael Hanselmann
    if hints_fn:
536 fb0be379 Michael Hanselmann
      hints_fn(op, datakind, name, value)
537 fb0be379 Michael Hanselmann
538 fb0be379 Michael Hanselmann
    for (fn_flags, fn) in op_data:
539 fb0be379 Michael Hanselmann
      if fn_flags is None or fn_flags & field_flags:
540 fb0be379 Michael Hanselmann
        return compat.partial(_WrapBinaryOp, fn, retrieval_fn, value)
541 fb0be379 Michael Hanselmann
542 fb0be379 Michael Hanselmann
    raise errors.ProgrammerError("Unable to find operator implementation"
543 fb0be379 Michael Hanselmann
                                 " (op '%s', flags %s)" % (op, field_flags))
544 fb0be379 Michael Hanselmann
545 fb0be379 Michael Hanselmann
546 fb0be379 Michael Hanselmann
def _CompileFilter(fields, hints, filter_):
547 fb0be379 Michael Hanselmann
  """Converts a query filter into a callable function.
548 fb0be379 Michael Hanselmann

549 fb0be379 Michael Hanselmann
  See L{_FilterCompilerHelper} for details.
550 fb0be379 Michael Hanselmann

551 fb0be379 Michael Hanselmann
  @rtype: callable
552 fb0be379 Michael Hanselmann

553 fb0be379 Michael Hanselmann
  """
554 fb0be379 Michael Hanselmann
  return _FilterCompilerHelper(fields)(hints, filter_)
555 fb0be379 Michael Hanselmann
556 fb0be379 Michael Hanselmann
557 4ca96421 Michael Hanselmann
class Query:
558 fb0be379 Michael Hanselmann
  def __init__(self, fieldlist, selected, filter_=None, namefield=None):
559 4ca96421 Michael Hanselmann
    """Initializes this class.
560 4ca96421 Michael Hanselmann

561 4ca96421 Michael Hanselmann
    The field definition is a dictionary with the field's name as a key and a
562 4ca96421 Michael Hanselmann
    tuple containing, in order, the field definition object
563 4ca96421 Michael Hanselmann
    (L{objects.QueryFieldDefinition}, the data kind to help calling code
564 4ca96421 Michael Hanselmann
    collect data and a retrieval function. The retrieval function is called
565 4ca96421 Michael Hanselmann
    with two parameters, in order, the data container and the item in container
566 4ca96421 Michael Hanselmann
    (see L{Query.Query}).
567 4ca96421 Michael Hanselmann

568 4ca96421 Michael Hanselmann
    Users of this class can call L{RequestedData} before preparing the data
569 4ca96421 Michael Hanselmann
    container to determine what data is needed.
570 4ca96421 Michael Hanselmann

571 4ca96421 Michael Hanselmann
    @type fieldlist: dictionary
572 4ca96421 Michael Hanselmann
    @param fieldlist: Field definitions
573 4ca96421 Michael Hanselmann
    @type selected: list of strings
574 4ca96421 Michael Hanselmann
    @param selected: List of selected fields
575 4ca96421 Michael Hanselmann

576 4ca96421 Michael Hanselmann
    """
577 fb0be379 Michael Hanselmann
    assert namefield is None or namefield in fieldlist
578 fb0be379 Michael Hanselmann
579 4ca96421 Michael Hanselmann
    self._fields = _GetQueryFields(fieldlist, selected)
580 4ca96421 Michael Hanselmann
581 fb0be379 Michael Hanselmann
    self._filter_fn = None
582 fb0be379 Michael Hanselmann
    self._requested_names = None
583 fb0be379 Michael Hanselmann
    self._filter_datakinds = frozenset()
584 fb0be379 Michael Hanselmann
585 fb0be379 Michael Hanselmann
    if filter_ is not None:
586 fb0be379 Michael Hanselmann
      # Collect requested names if wanted
587 fb0be379 Michael Hanselmann
      if namefield:
588 fb0be379 Michael Hanselmann
        hints = _FilterHints(namefield)
589 fb0be379 Michael Hanselmann
      else:
590 fb0be379 Michael Hanselmann
        hints = None
591 fb0be379 Michael Hanselmann
592 fb0be379 Michael Hanselmann
      # Build filter function
593 fb0be379 Michael Hanselmann
      self._filter_fn = _CompileFilter(fieldlist, hints, filter_)
594 fb0be379 Michael Hanselmann
      if hints:
595 fb0be379 Michael Hanselmann
        self._requested_names = hints.RequestedNames()
596 fb0be379 Michael Hanselmann
        self._filter_datakinds = hints.ReferencedData()
597 fb0be379 Michael Hanselmann
598 fb0be379 Michael Hanselmann
    if namefield is None:
599 fb0be379 Michael Hanselmann
      self._name_fn = None
600 fb0be379 Michael Hanselmann
    else:
601 fb0be379 Michael Hanselmann
      (_, _, _, self._name_fn) = fieldlist[namefield]
602 fb0be379 Michael Hanselmann
603 fb0be379 Michael Hanselmann
  def RequestedNames(self):
604 fb0be379 Michael Hanselmann
    """Returns all names referenced in the filter.
605 fb0be379 Michael Hanselmann

606 fb0be379 Michael Hanselmann
    If there is no filter or operators are preventing determining the exact
607 fb0be379 Michael Hanselmann
    names, C{None} is returned.
608 fb0be379 Michael Hanselmann

609 fb0be379 Michael Hanselmann
    """
610 fb0be379 Michael Hanselmann
    return self._requested_names
611 fb0be379 Michael Hanselmann
612 4ca96421 Michael Hanselmann
  def RequestedData(self):
613 4ca96421 Michael Hanselmann
    """Gets requested kinds of data.
614 4ca96421 Michael Hanselmann

615 4ca96421 Michael Hanselmann
    @rtype: frozenset
616 4ca96421 Michael Hanselmann

617 4ca96421 Michael Hanselmann
    """
618 fb0be379 Michael Hanselmann
    return (self._filter_datakinds |
619 fb0be379 Michael Hanselmann
            frozenset(datakind for (_, datakind, _, _) in self._fields
620 fb0be379 Michael Hanselmann
                      if datakind is not None))
621 4ca96421 Michael Hanselmann
622 4ca96421 Michael Hanselmann
  def GetFields(self):
623 4ca96421 Michael Hanselmann
    """Returns the list of fields for this query.
624 4ca96421 Michael Hanselmann

625 4ca96421 Michael Hanselmann
    Includes unknown fields.
626 4ca96421 Michael Hanselmann

627 4ca96421 Michael Hanselmann
    @rtype: List of L{objects.QueryFieldDefinition}
628 4ca96421 Michael Hanselmann

629 4ca96421 Michael Hanselmann
    """
630 4ca96421 Michael Hanselmann
    return GetAllFields(self._fields)
631 4ca96421 Michael Hanselmann
632 4ca96421 Michael Hanselmann
  def Query(self, ctx):
633 4ca96421 Michael Hanselmann
    """Execute a query.
634 4ca96421 Michael Hanselmann

635 4ca96421 Michael Hanselmann
    @param ctx: Data container passed to field retrieval functions, must
636 4ca96421 Michael Hanselmann
      support iteration using C{__iter__}
637 4ca96421 Michael Hanselmann

638 4ca96421 Michael Hanselmann
    """
639 fb0be379 Michael Hanselmann
    result = []
640 fb0be379 Michael Hanselmann
641 fb0be379 Michael Hanselmann
    for idx, item in enumerate(ctx):
642 fb0be379 Michael Hanselmann
      if not (self._filter_fn is None or self._filter_fn(ctx, item)):
643 fb0be379 Michael Hanselmann
        continue
644 4ca96421 Michael Hanselmann
645 fb0be379 Michael Hanselmann
      row = [_ProcessResult(fn(ctx, item)) for (_, _, _, fn) in self._fields]
646 fb0be379 Michael Hanselmann
647 fb0be379 Michael Hanselmann
      # Verify result
648 fb0be379 Michael Hanselmann
      if __debug__:
649 d1c3c3b3 Iustin Pop
        _VerifyResultRow(self._fields, row)
650 4ca96421 Michael Hanselmann
651 fb0be379 Michael Hanselmann
      if self._name_fn:
652 fb0be379 Michael Hanselmann
        (status, name) = _ProcessResult(self._name_fn(ctx, item))
653 fb0be379 Michael Hanselmann
        assert status == constants.RS_NORMAL
654 fb0be379 Michael Hanselmann
        # TODO: Are there cases where we wouldn't want to use NiceSort?
655 fb0be379 Michael Hanselmann
        sortname = utils.NiceSortKey(name)
656 fb0be379 Michael Hanselmann
      else:
657 fb0be379 Michael Hanselmann
        sortname = None
658 fb0be379 Michael Hanselmann
659 fb0be379 Michael Hanselmann
      result.append((sortname, idx, row))
660 fb0be379 Michael Hanselmann
661 fb0be379 Michael Hanselmann
    # TODO: Would "heapq" be more efficient than sorting?
662 fb0be379 Michael Hanselmann
663 fb0be379 Michael Hanselmann
    # Sorting in-place instead of using "sorted()"
664 fb0be379 Michael Hanselmann
    result.sort()
665 fb0be379 Michael Hanselmann
666 fb0be379 Michael Hanselmann
    assert not result or (len(result[0]) == 3 and len(result[-1]) == 3)
667 fb0be379 Michael Hanselmann
668 fb0be379 Michael Hanselmann
    return map(operator.itemgetter(2), result)
669 4ca96421 Michael Hanselmann
670 4ca96421 Michael Hanselmann
  def OldStyleQuery(self, ctx):
671 4ca96421 Michael Hanselmann
    """Query with "old" query result format.
672 4ca96421 Michael Hanselmann

673 4ca96421 Michael Hanselmann
    See L{Query.Query} for arguments.
674 4ca96421 Michael Hanselmann

675 4ca96421 Michael Hanselmann
    """
676 111bf531 Michael Hanselmann
    unknown = set(fdef.name for (fdef, _, _, _) in self._fields
677 111bf531 Michael Hanselmann
                  if fdef.kind == QFT_UNKNOWN)
678 4ca96421 Michael Hanselmann
    if unknown:
679 4ca96421 Michael Hanselmann
      raise errors.OpPrereqError("Unknown output fields selected: %s" %
680 4ca96421 Michael Hanselmann
                                 (utils.CommaJoin(unknown), ),
681 4ca96421 Michael Hanselmann
                                 errors.ECODE_INVAL)
682 4ca96421 Michael Hanselmann
683 4ca96421 Michael Hanselmann
    return [[value for (_, value) in row]
684 4ca96421 Michael Hanselmann
            for row in self.Query(ctx)]
685 4ca96421 Michael Hanselmann
686 4ca96421 Michael Hanselmann
687 e2d188cc Iustin Pop
def _ProcessResult(value):
688 e2d188cc Iustin Pop
  """Converts result values into externally-visible ones.
689 e2d188cc Iustin Pop

690 e2d188cc Iustin Pop
  """
691 e2d188cc Iustin Pop
  if value is _FS_UNKNOWN:
692 cfb084ae René Nussbaumer
    return (RS_UNKNOWN, None)
693 e2d188cc Iustin Pop
  elif value is _FS_NODATA:
694 cfb084ae René Nussbaumer
    return (RS_NODATA, None)
695 e2d188cc Iustin Pop
  elif value is _FS_UNAVAIL:
696 cfb084ae René Nussbaumer
    return (RS_UNAVAIL, None)
697 e2d188cc Iustin Pop
  elif value is _FS_OFFLINE:
698 cfb084ae René Nussbaumer
    return (RS_OFFLINE, None)
699 e2d188cc Iustin Pop
  else:
700 cfb084ae René Nussbaumer
    return (RS_NORMAL, value)
701 e2d188cc Iustin Pop
702 e2d188cc Iustin Pop
703 4ca96421 Michael Hanselmann
def _VerifyResultRow(fields, row):
704 4ca96421 Michael Hanselmann
  """Verifies the contents of a query result row.
705 4ca96421 Michael Hanselmann

706 4ca96421 Michael Hanselmann
  @type fields: list
707 4ca96421 Michael Hanselmann
  @param fields: Field definitions for result
708 4ca96421 Michael Hanselmann
  @type row: list of tuples
709 4ca96421 Michael Hanselmann
  @param row: Row data
710 4ca96421 Michael Hanselmann

711 4ca96421 Michael Hanselmann
  """
712 d1c3c3b3 Iustin Pop
  assert len(row) == len(fields)
713 d1c3c3b3 Iustin Pop
  errs = []
714 111bf531 Michael Hanselmann
  for ((status, value), (fdef, _, _, _)) in zip(row, fields):
715 cfb084ae René Nussbaumer
    if status == RS_NORMAL:
716 d1c3c3b3 Iustin Pop
      if not _VERIFY_FN[fdef.kind](value):
717 d1c3c3b3 Iustin Pop
        errs.append("normal field %s fails validation (value is %s)" %
718 d1c3c3b3 Iustin Pop
                    (fdef.name, value))
719 d1c3c3b3 Iustin Pop
    elif value is not None:
720 d1c3c3b3 Iustin Pop
      errs.append("abnormal field %s has a non-None value" % fdef.name)
721 d1c3c3b3 Iustin Pop
  assert not errs, ("Failed validation: %s in row %s" %
722 d1c3c3b3 Iustin Pop
                    (utils.CommaJoin(errors), row))
723 4ca96421 Michael Hanselmann
724 4ca96421 Michael Hanselmann
725 d63bd540 Iustin Pop
def _PrepareFieldList(fields, aliases):
726 4ca96421 Michael Hanselmann
  """Prepares field list for use by L{Query}.
727 4ca96421 Michael Hanselmann

728 4ca96421 Michael Hanselmann
  Converts the list to a dictionary and does some verification.
729 4ca96421 Michael Hanselmann

730 d63bd540 Iustin Pop
  @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data
731 d63bd540 Iustin Pop
      kind, retrieval function)
732 d63bd540 Iustin Pop
  @param fields: List of fields, see L{Query.__init__} for a better
733 d63bd540 Iustin Pop
      description
734 d63bd540 Iustin Pop
  @type aliases: list of tuples; (alias, target)
735 d63bd540 Iustin Pop
  @param aliases: list of tuples containing aliases; for each
736 d63bd540 Iustin Pop
      alias/target pair, a duplicate will be created in the field list
737 4ca96421 Michael Hanselmann
  @rtype: dict
738 4ca96421 Michael Hanselmann
  @return: Field dictionary for L{Query}
739 4ca96421 Michael Hanselmann

740 4ca96421 Michael Hanselmann
  """
741 89ce4acc Michael Hanselmann
  if __debug__:
742 89ce4acc Michael Hanselmann
    duplicates = utils.FindDuplicates(fdef.title.lower()
743 111bf531 Michael Hanselmann
                                      for (fdef, _, _, _) in fields)
744 89ce4acc Michael Hanselmann
    assert not duplicates, "Duplicate title(s) found: %r" % duplicates
745 4ca96421 Michael Hanselmann
746 4ca96421 Michael Hanselmann
  result = {}
747 4ca96421 Michael Hanselmann
748 4ca96421 Michael Hanselmann
  for field in fields:
749 111bf531 Michael Hanselmann
    (fdef, _, flags, fn) = field
750 4ca96421 Michael Hanselmann
751 4ca96421 Michael Hanselmann
    assert fdef.name and fdef.title, "Name and title are required"
752 4ca96421 Michael Hanselmann
    assert FIELD_NAME_RE.match(fdef.name)
753 4ca96421 Michael Hanselmann
    assert TITLE_RE.match(fdef.title)
754 79b2ca83 Michael Hanselmann
    assert (DOC_RE.match(fdef.doc) and len(fdef.doc.splitlines()) == 1 and
755 79b2ca83 Michael Hanselmann
            fdef.doc.strip() == fdef.doc), \
756 79b2ca83 Michael Hanselmann
           "Invalid description for field '%s'" % fdef.name
757 4ca96421 Michael Hanselmann
    assert callable(fn)
758 89ce4acc Michael Hanselmann
    assert fdef.name not in result, \
759 89ce4acc Michael Hanselmann
           "Duplicate field name '%s' found" % fdef.name
760 111bf531 Michael Hanselmann
    assert (flags & ~QFF_ALL) == 0, "Unknown flags for field '%s'" % fdef.name
761 4ca96421 Michael Hanselmann
762 4ca96421 Michael Hanselmann
    result[fdef.name] = field
763 4ca96421 Michael Hanselmann
764 d63bd540 Iustin Pop
  for alias, target in aliases:
765 d63bd540 Iustin Pop
    assert alias not in result, "Alias %s overrides an existing field" % alias
766 d63bd540 Iustin Pop
    assert target in result, "Missing target %s for alias %s" % (target, alias)
767 111bf531 Michael Hanselmann
    (fdef, k, flags, fn) = result[target]
768 d63bd540 Iustin Pop
    fdef = fdef.Copy()
769 d63bd540 Iustin Pop
    fdef.name = alias
770 111bf531 Michael Hanselmann
    result[alias] = (fdef, k, flags, fn)
771 d63bd540 Iustin Pop
772 d63bd540 Iustin Pop
  assert len(result) == len(fields) + len(aliases)
773 4ca96421 Michael Hanselmann
  assert compat.all(name == fdef.name
774 111bf531 Michael Hanselmann
                    for (name, (fdef, _, _, _)) in result.items())
775 4ca96421 Michael Hanselmann
776 4ca96421 Michael Hanselmann
  return result
777 4ca96421 Michael Hanselmann
778 4ca96421 Michael Hanselmann
779 b60fcb6f Michael Hanselmann
def GetQueryResponse(query, ctx):
780 b60fcb6f Michael Hanselmann
  """Prepares the response for a query.
781 b60fcb6f Michael Hanselmann

782 b60fcb6f Michael Hanselmann
  @type query: L{Query}
783 b60fcb6f Michael Hanselmann
  @param ctx: Data container, see L{Query.Query}
784 b60fcb6f Michael Hanselmann

785 b60fcb6f Michael Hanselmann
  """
786 b60fcb6f Michael Hanselmann
  return objects.QueryResponse(data=query.Query(ctx),
787 b60fcb6f Michael Hanselmann
                               fields=query.GetFields()).ToDict()
788 b60fcb6f Michael Hanselmann
789 b60fcb6f Michael Hanselmann
790 aa29e95f Michael Hanselmann
def QueryFields(fielddefs, selected):
791 aa29e95f Michael Hanselmann
  """Returns list of available fields.
792 aa29e95f Michael Hanselmann

793 aa29e95f Michael Hanselmann
  @type fielddefs: dict
794 aa29e95f Michael Hanselmann
  @param fielddefs: Field definitions
795 aa29e95f Michael Hanselmann
  @type selected: list of strings
796 aa29e95f Michael Hanselmann
  @param selected: List of selected fields
797 aa29e95f Michael Hanselmann
  @return: List of L{objects.QueryFieldDefinition}
798 aa29e95f Michael Hanselmann

799 aa29e95f Michael Hanselmann
  """
800 aa29e95f Michael Hanselmann
  if selected is None:
801 aa29e95f Michael Hanselmann
    # Client requests all fields, sort by name
802 aa29e95f Michael Hanselmann
    fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
803 aa29e95f Michael Hanselmann
                           key=operator.attrgetter("name"))
804 aa29e95f Michael Hanselmann
  else:
805 aa29e95f Michael Hanselmann
    # Keep order as requested by client
806 aa29e95f Michael Hanselmann
    fdefs = Query(fielddefs, selected).GetFields()
807 aa29e95f Michael Hanselmann
808 aa29e95f Michael Hanselmann
  return objects.QueryFieldsResponse(fields=fdefs).ToDict()
809 aa29e95f Michael Hanselmann
810 aa29e95f Michael Hanselmann
811 79b2ca83 Michael Hanselmann
def _MakeField(name, title, kind, doc):
812 4ca96421 Michael Hanselmann
  """Wrapper for creating L{objects.QueryFieldDefinition} instances.
813 4ca96421 Michael Hanselmann

814 4ca96421 Michael Hanselmann
  @param name: Field name as a regular expression
815 4ca96421 Michael Hanselmann
  @param title: Human-readable title
816 4ca96421 Michael Hanselmann
  @param kind: Field type
817 1ae17369 Michael Hanselmann
  @param doc: Human-readable description
818 4ca96421 Michael Hanselmann

819 4ca96421 Michael Hanselmann
  """
820 1ae17369 Michael Hanselmann
  return objects.QueryFieldDefinition(name=name, title=title, kind=kind,
821 1ae17369 Michael Hanselmann
                                      doc=doc)
822 8235fe04 Michael Hanselmann
823 8235fe04 Michael Hanselmann
824 8235fe04 Michael Hanselmann
def _GetNodeRole(node, master_name):
825 8235fe04 Michael Hanselmann
  """Determine node role.
826 8235fe04 Michael Hanselmann

827 8235fe04 Michael Hanselmann
  @type node: L{objects.Node}
828 8235fe04 Michael Hanselmann
  @param node: Node object
829 8235fe04 Michael Hanselmann
  @type master_name: string
830 8235fe04 Michael Hanselmann
  @param master_name: Master node name
831 8235fe04 Michael Hanselmann

832 8235fe04 Michael Hanselmann
  """
833 8235fe04 Michael Hanselmann
  if node.name == master_name:
834 1e28e3b8 Michael Hanselmann
    return constants.NR_MASTER
835 8235fe04 Michael Hanselmann
  elif node.master_candidate:
836 1e28e3b8 Michael Hanselmann
    return constants.NR_MCANDIDATE
837 8235fe04 Michael Hanselmann
  elif node.drained:
838 1e28e3b8 Michael Hanselmann
    return constants.NR_DRAINED
839 8235fe04 Michael Hanselmann
  elif node.offline:
840 1e28e3b8 Michael Hanselmann
    return constants.NR_OFFLINE
841 8235fe04 Michael Hanselmann
  else:
842 1e28e3b8 Michael Hanselmann
    return constants.NR_REGULAR
843 8235fe04 Michael Hanselmann
844 8235fe04 Michael Hanselmann
845 8235fe04 Michael Hanselmann
def _GetItemAttr(attr):
846 8235fe04 Michael Hanselmann
  """Returns a field function to return an attribute of the item.
847 8235fe04 Michael Hanselmann

848 8235fe04 Michael Hanselmann
  @param attr: Attribute name
849 8235fe04 Michael Hanselmann

850 8235fe04 Michael Hanselmann
  """
851 8235fe04 Michael Hanselmann
  getter = operator.attrgetter(attr)
852 e2d188cc Iustin Pop
  return lambda _, item: getter(item)
853 8235fe04 Michael Hanselmann
854 8235fe04 Michael Hanselmann
855 145bea54 Michael Hanselmann
def _GetItemTimestamp(getter):
856 145bea54 Michael Hanselmann
  """Returns function for getting timestamp of item.
857 145bea54 Michael Hanselmann

858 145bea54 Michael Hanselmann
  @type getter: callable
859 145bea54 Michael Hanselmann
  @param getter: Function to retrieve timestamp attribute
860 145bea54 Michael Hanselmann

861 145bea54 Michael Hanselmann
  """
862 145bea54 Michael Hanselmann
  def fn(_, item):
863 145bea54 Michael Hanselmann
    """Returns a timestamp of item.
864 145bea54 Michael Hanselmann

865 145bea54 Michael Hanselmann
    """
866 145bea54 Michael Hanselmann
    timestamp = getter(item)
867 145bea54 Michael Hanselmann
    if timestamp is None:
868 145bea54 Michael Hanselmann
      # Old configs might not have all timestamps
869 e2d188cc Iustin Pop
      return _FS_UNAVAIL
870 145bea54 Michael Hanselmann
    else:
871 e2d188cc Iustin Pop
      return timestamp
872 145bea54 Michael Hanselmann
873 145bea54 Michael Hanselmann
  return fn
874 145bea54 Michael Hanselmann
875 145bea54 Michael Hanselmann
876 145bea54 Michael Hanselmann
def _GetItemTimestampFields(datatype):
877 145bea54 Michael Hanselmann
  """Returns common timestamp fields.
878 145bea54 Michael Hanselmann

879 145bea54 Michael Hanselmann
  @param datatype: Field data type for use by L{Query.RequestedData}
880 145bea54 Michael Hanselmann

881 145bea54 Michael Hanselmann
  """
882 145bea54 Michael Hanselmann
  return [
883 79b2ca83 Michael Hanselmann
    (_MakeField("ctime", "CTime", QFT_TIMESTAMP, "Creation timestamp"),
884 111bf531 Michael Hanselmann
     datatype, 0, _GetItemTimestamp(operator.attrgetter("ctime"))),
885 79b2ca83 Michael Hanselmann
    (_MakeField("mtime", "MTime", QFT_TIMESTAMP, "Modification timestamp"),
886 111bf531 Michael Hanselmann
     datatype, 0, _GetItemTimestamp(operator.attrgetter("mtime"))),
887 145bea54 Michael Hanselmann
    ]
888 145bea54 Michael Hanselmann
889 145bea54 Michael Hanselmann
890 8235fe04 Michael Hanselmann
class NodeQueryData:
891 8235fe04 Michael Hanselmann
  """Data container for node data queries.
892 8235fe04 Michael Hanselmann

893 8235fe04 Michael Hanselmann
  """
894 8235fe04 Michael Hanselmann
  def __init__(self, nodes, live_data, master_name, node_to_primary,
895 8572f1fe René Nussbaumer
               node_to_secondary, groups, oob_support, cluster):
896 8235fe04 Michael Hanselmann
    """Initializes this class.
897 8235fe04 Michael Hanselmann

898 8235fe04 Michael Hanselmann
    """
899 8235fe04 Michael Hanselmann
    self.nodes = nodes
900 8235fe04 Michael Hanselmann
    self.live_data = live_data
901 8235fe04 Michael Hanselmann
    self.master_name = master_name
902 8235fe04 Michael Hanselmann
    self.node_to_primary = node_to_primary
903 8235fe04 Michael Hanselmann
    self.node_to_secondary = node_to_secondary
904 8235fe04 Michael Hanselmann
    self.groups = groups
905 52b5d286 René Nussbaumer
    self.oob_support = oob_support
906 8572f1fe René Nussbaumer
    self.cluster = cluster
907 8235fe04 Michael Hanselmann
908 8235fe04 Michael Hanselmann
    # Used for individual rows
909 8235fe04 Michael Hanselmann
    self.curlive_data = None
910 8235fe04 Michael Hanselmann
911 8235fe04 Michael Hanselmann
  def __iter__(self):
912 8235fe04 Michael Hanselmann
    """Iterate over all nodes.
913 8235fe04 Michael Hanselmann

914 8235fe04 Michael Hanselmann
    This function has side-effects and only one instance of the resulting
915 8235fe04 Michael Hanselmann
    generator should be used at a time.
916 8235fe04 Michael Hanselmann

917 8235fe04 Michael Hanselmann
    """
918 8235fe04 Michael Hanselmann
    for node in self.nodes:
919 8235fe04 Michael Hanselmann
      if self.live_data:
920 8235fe04 Michael Hanselmann
        self.curlive_data = self.live_data.get(node.name, None)
921 8235fe04 Michael Hanselmann
      else:
922 8235fe04 Michael Hanselmann
        self.curlive_data = None
923 8235fe04 Michael Hanselmann
      yield node
924 8235fe04 Michael Hanselmann
925 8235fe04 Michael Hanselmann
926 8235fe04 Michael Hanselmann
#: Fields that are direct attributes of an L{objects.Node} object
927 8235fe04 Michael Hanselmann
_NODE_SIMPLE_FIELDS = {
928 111bf531 Michael Hanselmann
  "drained": ("Drained", QFT_BOOL, 0, "Whether node is drained"),
929 111bf531 Michael Hanselmann
  "master_candidate": ("MasterC", QFT_BOOL, 0,
930 79b2ca83 Michael Hanselmann
                       "Whether node is a master candidate"),
931 111bf531 Michael Hanselmann
  "master_capable": ("MasterCapable", QFT_BOOL, 0,
932 79b2ca83 Michael Hanselmann
                     "Whether node can become a master candidate"),
933 111bf531 Michael Hanselmann
  "name": ("Node", QFT_TEXT, QFF_HOSTNAME, "Node name"),
934 111bf531 Michael Hanselmann
  "offline": ("Offline", QFT_BOOL, 0, "Whether node is marked offline"),
935 111bf531 Michael Hanselmann
  "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Node"),
936 111bf531 Michael Hanselmann
  "uuid": ("UUID", QFT_TEXT, 0, "Node UUID"),
937 111bf531 Michael Hanselmann
  "vm_capable": ("VMCapable", QFT_BOOL, 0, "Whether node can host instances"),
938 8235fe04 Michael Hanselmann
  }
939 8235fe04 Michael Hanselmann
940 8235fe04 Michael Hanselmann
941 8235fe04 Michael Hanselmann
#: Fields requiring talking to the node
942 effab4ca Iustin Pop
# Note that none of these are available for non-vm_capable nodes
943 8235fe04 Michael Hanselmann
_NODE_LIVE_FIELDS = {
944 79b2ca83 Michael Hanselmann
  "bootid": ("BootID", QFT_TEXT, "bootid",
945 79b2ca83 Michael Hanselmann
             "Random UUID renewed for each system reboot, can be used"
946 79b2ca83 Michael Hanselmann
             " for detecting reboots by tracking changes"),
947 79b2ca83 Michael Hanselmann
  "cnodes": ("CNodes", QFT_NUMBER, "cpu_nodes",
948 79b2ca83 Michael Hanselmann
             "Number of NUMA domains on node (if exported by hypervisor)"),
949 79b2ca83 Michael Hanselmann
  "csockets": ("CSockets", QFT_NUMBER, "cpu_sockets",
950 79b2ca83 Michael Hanselmann
               "Number of physical CPU sockets (if exported by hypervisor)"),
951 79b2ca83 Michael Hanselmann
  "ctotal": ("CTotal", QFT_NUMBER, "cpu_total", "Number of logical processors"),
952 79b2ca83 Michael Hanselmann
  "dfree": ("DFree", QFT_UNIT, "vg_free",
953 79b2ca83 Michael Hanselmann
            "Available disk space in volume group"),
954 79b2ca83 Michael Hanselmann
  "dtotal": ("DTotal", QFT_UNIT, "vg_size",
955 79b2ca83 Michael Hanselmann
             "Total disk space in volume group used for instance disk"
956 79b2ca83 Michael Hanselmann
             " allocation"),
957 79b2ca83 Michael Hanselmann
  "mfree": ("MFree", QFT_UNIT, "memory_free",
958 79b2ca83 Michael Hanselmann
            "Memory available for instance allocations"),
959 79b2ca83 Michael Hanselmann
  "mnode": ("MNode", QFT_UNIT, "memory_dom0",
960 79b2ca83 Michael Hanselmann
            "Amount of memory used by node (dom0 for Xen)"),
961 79b2ca83 Michael Hanselmann
  "mtotal": ("MTotal", QFT_UNIT, "memory_total",
962 79b2ca83 Michael Hanselmann
             "Total amount of memory of physical machine"),
963 8235fe04 Michael Hanselmann
  }
964 8235fe04 Michael Hanselmann
965 8235fe04 Michael Hanselmann
966 8572f1fe René Nussbaumer
def _GetGroup(cb):
967 8572f1fe René Nussbaumer
  """Build function for calling another function with an node group.
968 8572f1fe René Nussbaumer

969 8572f1fe René Nussbaumer
  @param cb: The callback to be called with the nodegroup
970 8572f1fe René Nussbaumer

971 8572f1fe René Nussbaumer
  """
972 8572f1fe René Nussbaumer
  def fn(ctx, node):
973 8572f1fe René Nussbaumer
    """Get group data for a node.
974 8572f1fe René Nussbaumer

975 8572f1fe René Nussbaumer
    @type ctx: L{NodeQueryData}
976 8572f1fe René Nussbaumer
    @type inst: L{objects.Node}
977 8572f1fe René Nussbaumer
    @param inst: Node object
978 8572f1fe René Nussbaumer

979 8572f1fe René Nussbaumer
    """
980 8572f1fe René Nussbaumer
    ng = ctx.groups.get(node.group, None)
981 8572f1fe René Nussbaumer
    if ng is None:
982 8572f1fe René Nussbaumer
      # Nodes always have a group, or the configuration is corrupt
983 e2d188cc Iustin Pop
      return _FS_UNAVAIL
984 8572f1fe René Nussbaumer
985 8572f1fe René Nussbaumer
    return cb(ctx, node, ng)
986 8572f1fe René Nussbaumer
987 8572f1fe René Nussbaumer
  return fn
988 8572f1fe René Nussbaumer
989 8572f1fe René Nussbaumer
990 8572f1fe René Nussbaumer
def _GetNodeGroup(ctx, node, ng): # pylint: disable-msg=W0613
991 8235fe04 Michael Hanselmann
  """Returns the name of a node's group.
992 8235fe04 Michael Hanselmann

993 8235fe04 Michael Hanselmann
  @type ctx: L{NodeQueryData}
994 8235fe04 Michael Hanselmann
  @type node: L{objects.Node}
995 8235fe04 Michael Hanselmann
  @param node: Node object
996 8572f1fe René Nussbaumer
  @type ng: L{objects.NodeGroup}
997 8572f1fe René Nussbaumer
  @param ng: The node group this node belongs to
998 8235fe04 Michael Hanselmann

999 8235fe04 Michael Hanselmann
  """
1000 e2d188cc Iustin Pop
  return ng.name
1001 8235fe04 Michael Hanselmann
1002 8235fe04 Michael Hanselmann
1003 52b5d286 René Nussbaumer
def _GetNodePower(ctx, node):
1004 52b5d286 René Nussbaumer
  """Returns the node powered state
1005 52b5d286 René Nussbaumer

1006 52b5d286 René Nussbaumer
  @type ctx: L{NodeQueryData}
1007 52b5d286 René Nussbaumer
  @type node: L{objects.Node}
1008 52b5d286 René Nussbaumer
  @param node: Node object
1009 52b5d286 René Nussbaumer

1010 52b5d286 René Nussbaumer
  """
1011 52b5d286 René Nussbaumer
  if ctx.oob_support[node.name]:
1012 e2d188cc Iustin Pop
    return node.powered
1013 52b5d286 René Nussbaumer
1014 e2d188cc Iustin Pop
  return _FS_UNAVAIL
1015 52b5d286 René Nussbaumer
1016 52b5d286 René Nussbaumer
1017 8572f1fe René Nussbaumer
def _GetNdParams(ctx, node, ng):
1018 8572f1fe René Nussbaumer
  """Returns the ndparams for this node.
1019 8572f1fe René Nussbaumer

1020 8572f1fe René Nussbaumer
  @type ctx: L{NodeQueryData}
1021 8572f1fe René Nussbaumer
  @type node: L{objects.Node}
1022 8572f1fe René Nussbaumer
  @param node: Node object
1023 8572f1fe René Nussbaumer
  @type ng: L{objects.NodeGroup}
1024 8572f1fe René Nussbaumer
  @param ng: The node group this node belongs to
1025 8572f1fe René Nussbaumer

1026 8572f1fe René Nussbaumer
  """
1027 e2d188cc Iustin Pop
  return ctx.cluster.SimpleFillND(ng.FillND(node))
1028 8572f1fe René Nussbaumer
1029 8572f1fe René Nussbaumer
1030 a6070ef7 Michael Hanselmann
def _GetLiveNodeField(field, kind, ctx, node):
1031 8235fe04 Michael Hanselmann
  """Gets the value of a "live" field from L{NodeQueryData}.
1032 8235fe04 Michael Hanselmann

1033 8235fe04 Michael Hanselmann
  @param field: Live field name
1034 8235fe04 Michael Hanselmann
  @param kind: Data kind, one of L{constants.QFT_ALL}
1035 8235fe04 Michael Hanselmann
  @type ctx: L{NodeQueryData}
1036 a6070ef7 Michael Hanselmann
  @type node: L{objects.Node}
1037 a6070ef7 Michael Hanselmann
  @param node: Node object
1038 8235fe04 Michael Hanselmann

1039 8235fe04 Michael Hanselmann
  """
1040 a6070ef7 Michael Hanselmann
  if node.offline:
1041 e2d188cc Iustin Pop
    return _FS_OFFLINE
1042 a6070ef7 Michael Hanselmann
1043 effab4ca Iustin Pop
  if not node.vm_capable:
1044 effab4ca Iustin Pop
    return _FS_UNAVAIL
1045 effab4ca Iustin Pop
1046 8235fe04 Michael Hanselmann
  if not ctx.curlive_data:
1047 e2d188cc Iustin Pop
    return _FS_NODATA
1048 8235fe04 Michael Hanselmann
1049 8235fe04 Michael Hanselmann
  try:
1050 8235fe04 Michael Hanselmann
    value = ctx.curlive_data[field]
1051 8235fe04 Michael Hanselmann
  except KeyError:
1052 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1053 8235fe04 Michael Hanselmann
1054 82599b3e Iustin Pop
  if kind == QFT_TEXT:
1055 e2d188cc Iustin Pop
    return value
1056 8235fe04 Michael Hanselmann
1057 82599b3e Iustin Pop
  assert kind in (QFT_NUMBER, QFT_UNIT)
1058 8235fe04 Michael Hanselmann
1059 8235fe04 Michael Hanselmann
  # Try to convert into number
1060 8235fe04 Michael Hanselmann
  try:
1061 e2d188cc Iustin Pop
    return int(value)
1062 8235fe04 Michael Hanselmann
  except (ValueError, TypeError):
1063 8235fe04 Michael Hanselmann
    logging.exception("Failed to convert node field '%s' (value %r) to int",
1064 8235fe04 Michael Hanselmann
                      value, field)
1065 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1066 8235fe04 Michael Hanselmann
1067 8235fe04 Michael Hanselmann
1068 8235fe04 Michael Hanselmann
def _BuildNodeFields():
1069 8235fe04 Michael Hanselmann
  """Builds list of fields for node queries.
1070 8235fe04 Michael Hanselmann

1071 8235fe04 Michael Hanselmann
  """
1072 8235fe04 Michael Hanselmann
  fields = [
1073 79b2ca83 Michael Hanselmann
    (_MakeField("pip", "PrimaryIP", QFT_TEXT, "Primary IP address"),
1074 111bf531 Michael Hanselmann
     NQ_CONFIG, 0, _GetItemAttr("primary_ip")),
1075 79b2ca83 Michael Hanselmann
    (_MakeField("sip", "SecondaryIP", QFT_TEXT, "Secondary IP address"),
1076 111bf531 Michael Hanselmann
     NQ_CONFIG, 0, _GetItemAttr("secondary_ip")),
1077 111bf531 Michael Hanselmann
    (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), NQ_CONFIG, 0,
1078 e2d188cc Iustin Pop
     lambda ctx, node: list(node.GetTags())),
1079 79b2ca83 Michael Hanselmann
    (_MakeField("master", "IsMaster", QFT_BOOL, "Whether node is master"),
1080 111bf531 Michael Hanselmann
     NQ_CONFIG, 0, lambda ctx, node: node.name == ctx.master_name),
1081 111bf531 Michael Hanselmann
    (_MakeField("group", "Group", QFT_TEXT, "Node group"), NQ_GROUP, 0,
1082 8572f1fe René Nussbaumer
     _GetGroup(_GetNodeGroup)),
1083 79b2ca83 Michael Hanselmann
    (_MakeField("group.uuid", "GroupUUID", QFT_TEXT, "UUID of node group"),
1084 111bf531 Michael Hanselmann
     NQ_CONFIG, 0, _GetItemAttr("group")),
1085 79b2ca83 Michael Hanselmann
    (_MakeField("powered", "Powered", QFT_BOOL,
1086 79b2ca83 Michael Hanselmann
                "Whether node is thought to be powered on"),
1087 111bf531 Michael Hanselmann
     NQ_OOB, 0, _GetNodePower),
1088 79b2ca83 Michael Hanselmann
    (_MakeField("ndparams", "NodeParameters", QFT_OTHER,
1089 79b2ca83 Michael Hanselmann
                "Merged node parameters"),
1090 111bf531 Michael Hanselmann
     NQ_GROUP, 0, _GetGroup(_GetNdParams)),
1091 79b2ca83 Michael Hanselmann
    (_MakeField("custom_ndparams", "CustomNodeParameters", QFT_OTHER,
1092 79b2ca83 Michael Hanselmann
                "Custom node parameters"),
1093 111bf531 Michael Hanselmann
      NQ_GROUP, 0, _GetItemAttr("ndparams")),
1094 8235fe04 Michael Hanselmann
    ]
1095 8235fe04 Michael Hanselmann
1096 79b2ca83 Michael Hanselmann
  # Node role
1097 79b2ca83 Michael Hanselmann
  role_values = (constants.NR_MASTER, constants.NR_MCANDIDATE,
1098 79b2ca83 Michael Hanselmann
                 constants.NR_REGULAR, constants.NR_DRAINED,
1099 79b2ca83 Michael Hanselmann
                 constants.NR_OFFLINE)
1100 79b2ca83 Michael Hanselmann
  role_doc = ("Node role; \"%s\" for master, \"%s\" for master candidate,"
1101 79b2ca83 Michael Hanselmann
              " \"%s\" for regular, \"%s\" for a drained, \"%s\" for offline" %
1102 79b2ca83 Michael Hanselmann
              role_values)
1103 111bf531 Michael Hanselmann
  fields.append((_MakeField("role", "Role", QFT_TEXT, role_doc), NQ_CONFIG, 0,
1104 79b2ca83 Michael Hanselmann
                 lambda ctx, node: _GetNodeRole(node, ctx.master_name)))
1105 79b2ca83 Michael Hanselmann
  assert set(role_values) == constants.NR_ALL
1106 79b2ca83 Michael Hanselmann
1107 8235fe04 Michael Hanselmann
  def _GetLength(getter):
1108 e2d188cc Iustin Pop
    return lambda ctx, node: len(getter(ctx)[node.name])
1109 8235fe04 Michael Hanselmann
1110 8235fe04 Michael Hanselmann
  def _GetList(getter):
1111 e2d188cc Iustin Pop
    return lambda ctx, node: list(getter(ctx)[node.name])
1112 8235fe04 Michael Hanselmann
1113 8235fe04 Michael Hanselmann
  # Add fields operating on instance lists
1114 79b2ca83 Michael Hanselmann
  for prefix, titleprefix, docword, getter in \
1115 79b2ca83 Michael Hanselmann
      [("p", "Pri", "primary", operator.attrgetter("node_to_primary")),
1116 79b2ca83 Michael Hanselmann
       ("s", "Sec", "secondary", operator.attrgetter("node_to_secondary"))]:
1117 111bf531 Michael Hanselmann
    # TODO: Allow filterting by hostname in list
1118 8235fe04 Michael Hanselmann
    fields.extend([
1119 79b2ca83 Michael Hanselmann
      (_MakeField("%sinst_cnt" % prefix, "%sinst" % prefix.upper(), QFT_NUMBER,
1120 79b2ca83 Michael Hanselmann
                  "Number of instances with this node as %s" % docword),
1121 111bf531 Michael Hanselmann
       NQ_INST, 0, _GetLength(getter)),
1122 8235fe04 Michael Hanselmann
      (_MakeField("%sinst_list" % prefix, "%sInstances" % titleprefix,
1123 79b2ca83 Michael Hanselmann
                  QFT_OTHER,
1124 79b2ca83 Michael Hanselmann
                  "List of instances with this node as %s" % docword),
1125 111bf531 Michael Hanselmann
       NQ_INST, 0, _GetList(getter)),
1126 8235fe04 Michael Hanselmann
      ])
1127 8235fe04 Michael Hanselmann
1128 8235fe04 Michael Hanselmann
  # Add simple fields
1129 111bf531 Michael Hanselmann
  fields.extend([
1130 111bf531 Michael Hanselmann
    (_MakeField(name, title, kind, doc), NQ_CONFIG, flags, _GetItemAttr(name))
1131 111bf531 Michael Hanselmann
    for (name, (title, kind, flags, doc)) in _NODE_SIMPLE_FIELDS.items()
1132 111bf531 Michael Hanselmann
    ])
1133 8235fe04 Michael Hanselmann
1134 8235fe04 Michael Hanselmann
  # Add fields requiring live data
1135 8235fe04 Michael Hanselmann
  fields.extend([
1136 111bf531 Michael Hanselmann
    (_MakeField(name, title, kind, doc), NQ_LIVE, 0,
1137 8235fe04 Michael Hanselmann
     compat.partial(_GetLiveNodeField, nfield, kind))
1138 79b2ca83 Michael Hanselmann
    for (name, (title, kind, nfield, doc)) in _NODE_LIVE_FIELDS.items()
1139 8235fe04 Michael Hanselmann
    ])
1140 8235fe04 Michael Hanselmann
1141 145bea54 Michael Hanselmann
  # Add timestamps
1142 145bea54 Michael Hanselmann
  fields.extend(_GetItemTimestampFields(NQ_CONFIG))
1143 145bea54 Michael Hanselmann
1144 d63bd540 Iustin Pop
  return _PrepareFieldList(fields, [])
1145 8235fe04 Michael Hanselmann
1146 8235fe04 Michael Hanselmann
1147 1c8addc6 Michael Hanselmann
class InstanceQueryData:
1148 1c8addc6 Michael Hanselmann
  """Data container for instance data queries.
1149 1c8addc6 Michael Hanselmann

1150 1c8addc6 Michael Hanselmann
  """
1151 1c8addc6 Michael Hanselmann
  def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
1152 5d28cb6f Michael Hanselmann
               live_data, wrongnode_inst, console):
1153 1c8addc6 Michael Hanselmann
    """Initializes this class.
1154 1c8addc6 Michael Hanselmann

1155 1c8addc6 Michael Hanselmann
    @param instances: List of instance objects
1156 1c8addc6 Michael Hanselmann
    @param cluster: Cluster object
1157 1c8addc6 Michael Hanselmann
    @type disk_usage: dict; instance name as key
1158 1c8addc6 Michael Hanselmann
    @param disk_usage: Per-instance disk usage
1159 1c8addc6 Michael Hanselmann
    @type offline_nodes: list of strings
1160 1c8addc6 Michael Hanselmann
    @param offline_nodes: List of offline nodes
1161 1c8addc6 Michael Hanselmann
    @type bad_nodes: list of strings
1162 1c8addc6 Michael Hanselmann
    @param bad_nodes: List of faulty nodes
1163 1c8addc6 Michael Hanselmann
    @type live_data: dict; instance name as key
1164 1c8addc6 Michael Hanselmann
    @param live_data: Per-instance live data
1165 e431074f René Nussbaumer
    @type wrongnode_inst: set
1166 e431074f René Nussbaumer
    @param wrongnode_inst: Set of instances running on wrong node(s)
1167 5d28cb6f Michael Hanselmann
    @type console: dict; instance name as key
1168 5d28cb6f Michael Hanselmann
    @param console: Per-instance console information
1169 1c8addc6 Michael Hanselmann

1170 1c8addc6 Michael Hanselmann
    """
1171 1c8addc6 Michael Hanselmann
    assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
1172 1c8addc6 Michael Hanselmann
           "Offline nodes not included in bad nodes"
1173 1c8addc6 Michael Hanselmann
    assert not (set(live_data.keys()) & set(bad_nodes)), \
1174 1c8addc6 Michael Hanselmann
           "Found live data for bad or offline nodes"
1175 1c8addc6 Michael Hanselmann
1176 1c8addc6 Michael Hanselmann
    self.instances = instances
1177 1c8addc6 Michael Hanselmann
    self.cluster = cluster
1178 1c8addc6 Michael Hanselmann
    self.disk_usage = disk_usage
1179 1c8addc6 Michael Hanselmann
    self.offline_nodes = offline_nodes
1180 1c8addc6 Michael Hanselmann
    self.bad_nodes = bad_nodes
1181 1c8addc6 Michael Hanselmann
    self.live_data = live_data
1182 e431074f René Nussbaumer
    self.wrongnode_inst = wrongnode_inst
1183 5d28cb6f Michael Hanselmann
    self.console = console
1184 1c8addc6 Michael Hanselmann
1185 1c8addc6 Michael Hanselmann
    # Used for individual rows
1186 1c8addc6 Michael Hanselmann
    self.inst_hvparams = None
1187 1c8addc6 Michael Hanselmann
    self.inst_beparams = None
1188 1c8addc6 Michael Hanselmann
    self.inst_nicparams = None
1189 1c8addc6 Michael Hanselmann
1190 1c8addc6 Michael Hanselmann
  def __iter__(self):
1191 1c8addc6 Michael Hanselmann
    """Iterate over all instances.
1192 1c8addc6 Michael Hanselmann

1193 1c8addc6 Michael Hanselmann
    This function has side-effects and only one instance of the resulting
1194 1c8addc6 Michael Hanselmann
    generator should be used at a time.
1195 1c8addc6 Michael Hanselmann

1196 1c8addc6 Michael Hanselmann
    """
1197 1c8addc6 Michael Hanselmann
    for inst in self.instances:
1198 1c8addc6 Michael Hanselmann
      self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
1199 1c8addc6 Michael Hanselmann
      self.inst_beparams = self.cluster.FillBE(inst)
1200 1c8addc6 Michael Hanselmann
      self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
1201 1c8addc6 Michael Hanselmann
                             for nic in inst.nics]
1202 1c8addc6 Michael Hanselmann
1203 1c8addc6 Michael Hanselmann
      yield inst
1204 1c8addc6 Michael Hanselmann
1205 1c8addc6 Michael Hanselmann
1206 1c8addc6 Michael Hanselmann
def _GetInstOperState(ctx, inst):
1207 1c8addc6 Michael Hanselmann
  """Get instance's operational status.
1208 1c8addc6 Michael Hanselmann

1209 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1210 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1211 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1212 1c8addc6 Michael Hanselmann

1213 1c8addc6 Michael Hanselmann
  """
1214 cfb084ae René Nussbaumer
  # Can't use RS_OFFLINE here as it would describe the instance to
1215 e2d188cc Iustin Pop
  # be offline when we actually don't know due to missing data
1216 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.bad_nodes:
1217 e2d188cc Iustin Pop
    return _FS_NODATA
1218 1c8addc6 Michael Hanselmann
  else:
1219 e2d188cc Iustin Pop
    return bool(ctx.live_data.get(inst.name))
1220 1c8addc6 Michael Hanselmann
1221 1c8addc6 Michael Hanselmann
1222 1c8addc6 Michael Hanselmann
def _GetInstLiveData(name):
1223 1c8addc6 Michael Hanselmann
  """Build function for retrieving live data.
1224 1c8addc6 Michael Hanselmann

1225 1c8addc6 Michael Hanselmann
  @type name: string
1226 1c8addc6 Michael Hanselmann
  @param name: Live data field name
1227 1c8addc6 Michael Hanselmann

1228 1c8addc6 Michael Hanselmann
  """
1229 1c8addc6 Michael Hanselmann
  def fn(ctx, inst):
1230 1c8addc6 Michael Hanselmann
    """Get live data for an instance.
1231 1c8addc6 Michael Hanselmann

1232 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1233 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1234 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1235 1c8addc6 Michael Hanselmann

1236 1c8addc6 Michael Hanselmann
    """
1237 1c8addc6 Michael Hanselmann
    if (inst.primary_node in ctx.bad_nodes or
1238 1c8addc6 Michael Hanselmann
        inst.primary_node in ctx.offline_nodes):
1239 cfb084ae René Nussbaumer
      # Can't use RS_OFFLINE here as it would describe the instance to be
1240 a6070ef7 Michael Hanselmann
      # offline when we actually don't know due to missing data
1241 e2d188cc Iustin Pop
      return _FS_NODATA
1242 1c8addc6 Michael Hanselmann
1243 1c8addc6 Michael Hanselmann
    if inst.name in ctx.live_data:
1244 1c8addc6 Michael Hanselmann
      data = ctx.live_data[inst.name]
1245 1c8addc6 Michael Hanselmann
      if name in data:
1246 e2d188cc Iustin Pop
        return data[name]
1247 1c8addc6 Michael Hanselmann
1248 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1249 1c8addc6 Michael Hanselmann
1250 1c8addc6 Michael Hanselmann
  return fn
1251 1c8addc6 Michael Hanselmann
1252 1c8addc6 Michael Hanselmann
1253 1c8addc6 Michael Hanselmann
def _GetInstStatus(ctx, inst):
1254 1c8addc6 Michael Hanselmann
  """Get instance status.
1255 1c8addc6 Michael Hanselmann

1256 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1257 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1258 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1259 1c8addc6 Michael Hanselmann

1260 1c8addc6 Michael Hanselmann
  """
1261 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.offline_nodes:
1262 61a980a9 Michael Hanselmann
    return constants.INSTST_NODEOFFLINE
1263 1c8addc6 Michael Hanselmann
1264 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.bad_nodes:
1265 61a980a9 Michael Hanselmann
    return constants.INSTST_NODEDOWN
1266 1c8addc6 Michael Hanselmann
1267 1c8addc6 Michael Hanselmann
  if bool(ctx.live_data.get(inst.name)):
1268 e431074f René Nussbaumer
    if inst.name in ctx.wrongnode_inst:
1269 61a980a9 Michael Hanselmann
      return constants.INSTST_WRONGNODE
1270 e431074f René Nussbaumer
    elif inst.admin_up:
1271 61a980a9 Michael Hanselmann
      return constants.INSTST_RUNNING
1272 1c8addc6 Michael Hanselmann
    else:
1273 61a980a9 Michael Hanselmann
      return constants.INSTST_ERRORUP
1274 1c8addc6 Michael Hanselmann
1275 1c8addc6 Michael Hanselmann
  if inst.admin_up:
1276 61a980a9 Michael Hanselmann
    return constants.INSTST_ERRORDOWN
1277 1c8addc6 Michael Hanselmann
1278 61a980a9 Michael Hanselmann
  return constants.INSTST_ADMINDOWN
1279 1c8addc6 Michael Hanselmann
1280 1c8addc6 Michael Hanselmann
1281 1c8addc6 Michael Hanselmann
def _GetInstDiskSize(index):
1282 1c8addc6 Michael Hanselmann
  """Build function for retrieving disk size.
1283 1c8addc6 Michael Hanselmann

1284 1c8addc6 Michael Hanselmann
  @type index: int
1285 1c8addc6 Michael Hanselmann
  @param index: Disk index
1286 1c8addc6 Michael Hanselmann

1287 1c8addc6 Michael Hanselmann
  """
1288 1c8addc6 Michael Hanselmann
  def fn(_, inst):
1289 1c8addc6 Michael Hanselmann
    """Get size of a disk.
1290 1c8addc6 Michael Hanselmann

1291 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1292 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1293 1c8addc6 Michael Hanselmann

1294 1c8addc6 Michael Hanselmann
    """
1295 1c8addc6 Michael Hanselmann
    try:
1296 e2d188cc Iustin Pop
      return inst.disks[index].size
1297 1c8addc6 Michael Hanselmann
    except IndexError:
1298 e2d188cc Iustin Pop
      return _FS_UNAVAIL
1299 1c8addc6 Michael Hanselmann
1300 1c8addc6 Michael Hanselmann
  return fn
1301 1c8addc6 Michael Hanselmann
1302 1c8addc6 Michael Hanselmann
1303 1c8addc6 Michael Hanselmann
def _GetInstNic(index, cb):
1304 1c8addc6 Michael Hanselmann
  """Build function for calling another function with an instance NIC.
1305 1c8addc6 Michael Hanselmann

1306 1c8addc6 Michael Hanselmann
  @type index: int
1307 1c8addc6 Michael Hanselmann
  @param index: NIC index
1308 1c8addc6 Michael Hanselmann
  @type cb: callable
1309 1c8addc6 Michael Hanselmann
  @param cb: Callback
1310 1c8addc6 Michael Hanselmann

1311 1c8addc6 Michael Hanselmann
  """
1312 1c8addc6 Michael Hanselmann
  def fn(ctx, inst):
1313 1c8addc6 Michael Hanselmann
    """Call helper function with instance NIC.
1314 1c8addc6 Michael Hanselmann

1315 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1316 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1317 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1318 1c8addc6 Michael Hanselmann

1319 1c8addc6 Michael Hanselmann
    """
1320 1c8addc6 Michael Hanselmann
    try:
1321 1c8addc6 Michael Hanselmann
      nic = inst.nics[index]
1322 1c8addc6 Michael Hanselmann
    except IndexError:
1323 e2d188cc Iustin Pop
      return _FS_UNAVAIL
1324 1c8addc6 Michael Hanselmann
1325 1c8addc6 Michael Hanselmann
    return cb(ctx, index, nic)
1326 1c8addc6 Michael Hanselmann
1327 1c8addc6 Michael Hanselmann
  return fn
1328 1c8addc6 Michael Hanselmann
1329 1c8addc6 Michael Hanselmann
1330 1c8addc6 Michael Hanselmann
def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
1331 1c8addc6 Michael Hanselmann
  """Get a NIC's IP address.
1332 1c8addc6 Michael Hanselmann

1333 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1334 1c8addc6 Michael Hanselmann
  @type nic: L{objects.NIC}
1335 1c8addc6 Michael Hanselmann
  @param nic: NIC object
1336 1c8addc6 Michael Hanselmann

1337 1c8addc6 Michael Hanselmann
  """
1338 1c8addc6 Michael Hanselmann
  if nic.ip is None:
1339 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1340 1c8addc6 Michael Hanselmann
  else:
1341 e2d188cc Iustin Pop
    return nic.ip
1342 1c8addc6 Michael Hanselmann
1343 1c8addc6 Michael Hanselmann
1344 1c8addc6 Michael Hanselmann
def _GetInstNicBridge(ctx, index, _):
1345 1c8addc6 Michael Hanselmann
  """Get a NIC's bridge.
1346 1c8addc6 Michael Hanselmann

1347 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1348 1c8addc6 Michael Hanselmann
  @type index: int
1349 1c8addc6 Michael Hanselmann
  @param index: NIC index
1350 1c8addc6 Michael Hanselmann

1351 1c8addc6 Michael Hanselmann
  """
1352 1c8addc6 Michael Hanselmann
  assert len(ctx.inst_nicparams) >= index
1353 1c8addc6 Michael Hanselmann
1354 1c8addc6 Michael Hanselmann
  nicparams = ctx.inst_nicparams[index]
1355 1c8addc6 Michael Hanselmann
1356 1c8addc6 Michael Hanselmann
  if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1357 e2d188cc Iustin Pop
    return nicparams[constants.NIC_LINK]
1358 1c8addc6 Michael Hanselmann
  else:
1359 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1360 1c8addc6 Michael Hanselmann
1361 1c8addc6 Michael Hanselmann
1362 1c8addc6 Michael Hanselmann
def _GetInstAllNicBridges(ctx, inst):
1363 1c8addc6 Michael Hanselmann
  """Get all network bridges for an instance.
1364 1c8addc6 Michael Hanselmann

1365 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1366 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1367 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1368 1c8addc6 Michael Hanselmann

1369 1c8addc6 Michael Hanselmann
  """
1370 1c8addc6 Michael Hanselmann
  assert len(ctx.inst_nicparams) == len(inst.nics)
1371 1c8addc6 Michael Hanselmann
1372 1c8addc6 Michael Hanselmann
  result = []
1373 1c8addc6 Michael Hanselmann
1374 1c8addc6 Michael Hanselmann
  for nicp in ctx.inst_nicparams:
1375 1c8addc6 Michael Hanselmann
    if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1376 1c8addc6 Michael Hanselmann
      result.append(nicp[constants.NIC_LINK])
1377 1c8addc6 Michael Hanselmann
    else:
1378 1c8addc6 Michael Hanselmann
      result.append(None)
1379 1c8addc6 Michael Hanselmann
1380 1c8addc6 Michael Hanselmann
  assert len(result) == len(inst.nics)
1381 1c8addc6 Michael Hanselmann
1382 e2d188cc Iustin Pop
  return result
1383 1c8addc6 Michael Hanselmann
1384 1c8addc6 Michael Hanselmann
1385 1c8addc6 Michael Hanselmann
def _GetInstNicParam(name):
1386 1c8addc6 Michael Hanselmann
  """Build function for retrieving a NIC parameter.
1387 1c8addc6 Michael Hanselmann

1388 1c8addc6 Michael Hanselmann
  @type name: string
1389 1c8addc6 Michael Hanselmann
  @param name: Parameter name
1390 1c8addc6 Michael Hanselmann

1391 1c8addc6 Michael Hanselmann
  """
1392 1c8addc6 Michael Hanselmann
  def fn(ctx, index, _):
1393 1c8addc6 Michael Hanselmann
    """Get a NIC's bridge.
1394 1c8addc6 Michael Hanselmann

1395 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1396 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1397 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1398 1c8addc6 Michael Hanselmann
    @type nic: L{objects.NIC}
1399 1c8addc6 Michael Hanselmann
    @param nic: NIC object
1400 1c8addc6 Michael Hanselmann

1401 1c8addc6 Michael Hanselmann
    """
1402 1c8addc6 Michael Hanselmann
    assert len(ctx.inst_nicparams) >= index
1403 e2d188cc Iustin Pop
    return ctx.inst_nicparams[index][name]
1404 1c8addc6 Michael Hanselmann
1405 1c8addc6 Michael Hanselmann
  return fn
1406 1c8addc6 Michael Hanselmann
1407 1c8addc6 Michael Hanselmann
1408 1c8addc6 Michael Hanselmann
def _GetInstanceNetworkFields():
1409 1c8addc6 Michael Hanselmann
  """Get instance fields involving network interfaces.
1410 1c8addc6 Michael Hanselmann

1411 4cc4d1fa Michael Hanselmann
  @return: Tuple containing list of field definitions used as input for
1412 4cc4d1fa Michael Hanselmann
    L{_PrepareFieldList} and a list of aliases
1413 1c8addc6 Michael Hanselmann

1414 1c8addc6 Michael Hanselmann
  """
1415 e2d188cc Iustin Pop
  nic_mac_fn = lambda ctx, _, nic: nic.mac
1416 1c8addc6 Michael Hanselmann
  nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
1417 1c8addc6 Michael Hanselmann
  nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
1418 1c8addc6 Michael Hanselmann
1419 1c8addc6 Michael Hanselmann
  fields = [
1420 1c8addc6 Michael Hanselmann
    # All NICs
1421 79b2ca83 Michael Hanselmann
    (_MakeField("nic.count", "NICs", QFT_NUMBER,
1422 79b2ca83 Michael Hanselmann
                "Number of network interfaces"),
1423 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: len(inst.nics)),
1424 79b2ca83 Michael Hanselmann
    (_MakeField("nic.macs", "NIC_MACs", QFT_OTHER,
1425 79b2ca83 Michael Hanselmann
                "List containing each network interface's MAC address"),
1426 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [nic.mac for nic in inst.nics]),
1427 79b2ca83 Michael Hanselmann
    (_MakeField("nic.ips", "NIC_IPs", QFT_OTHER,
1428 79b2ca83 Michael Hanselmann
                "List containing each network interface's IP address"),
1429 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [nic.ip for nic in inst.nics]),
1430 79b2ca83 Michael Hanselmann
    (_MakeField("nic.modes", "NIC_modes", QFT_OTHER,
1431 111bf531 Michael Hanselmann
                "List containing each network interface's mode"), IQ_CONFIG, 0,
1432 e2d188cc Iustin Pop
     lambda ctx, inst: [nicp[constants.NIC_MODE]
1433 e2d188cc Iustin Pop
                        for nicp in ctx.inst_nicparams]),
1434 79b2ca83 Michael Hanselmann
    (_MakeField("nic.links", "NIC_links", QFT_OTHER,
1435 111bf531 Michael Hanselmann
                "List containing each network interface's link"), IQ_CONFIG, 0,
1436 e2d188cc Iustin Pop
     lambda ctx, inst: [nicp[constants.NIC_LINK]
1437 e2d188cc Iustin Pop
                        for nicp in ctx.inst_nicparams]),
1438 79b2ca83 Michael Hanselmann
    (_MakeField("nic.bridges", "NIC_bridges", QFT_OTHER,
1439 111bf531 Michael Hanselmann
                "List containing each network interface's bridge"),
1440 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstAllNicBridges),
1441 1c8addc6 Michael Hanselmann
    ]
1442 1c8addc6 Michael Hanselmann
1443 1c8addc6 Michael Hanselmann
  # NICs by number
1444 1c8addc6 Michael Hanselmann
  for i in range(constants.MAX_NICS):
1445 79b2ca83 Michael Hanselmann
    numtext = utils.FormatOrdinal(i + 1)
1446 1c8addc6 Michael Hanselmann
    fields.extend([
1447 79b2ca83 Michael Hanselmann
      (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, QFT_TEXT,
1448 79b2ca83 Michael Hanselmann
                  "IP address of %s network interface" % numtext),
1449 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicIp)),
1450 79b2ca83 Michael Hanselmann
      (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, QFT_TEXT,
1451 79b2ca83 Michael Hanselmann
                  "MAC address of %s network interface" % numtext),
1452 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_mac_fn)),
1453 79b2ca83 Michael Hanselmann
      (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, QFT_TEXT,
1454 79b2ca83 Michael Hanselmann
                  "Mode of %s network interface" % numtext),
1455 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_mode_fn)),
1456 79b2ca83 Michael Hanselmann
      (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, QFT_TEXT,
1457 79b2ca83 Michael Hanselmann
                  "Link of %s network interface" % numtext),
1458 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_link_fn)),
1459 79b2ca83 Michael Hanselmann
      (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, QFT_TEXT,
1460 79b2ca83 Michael Hanselmann
                  "Bridge of %s network interface" % numtext),
1461 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicBridge)),
1462 1c8addc6 Michael Hanselmann
      ])
1463 1c8addc6 Michael Hanselmann
1464 4cc4d1fa Michael Hanselmann
  aliases = [
1465 4cc4d1fa Michael Hanselmann
    # Legacy fields for first NIC
1466 4cc4d1fa Michael Hanselmann
    ("ip", "nic.ip/0"),
1467 4cc4d1fa Michael Hanselmann
    ("mac", "nic.mac/0"),
1468 4cc4d1fa Michael Hanselmann
    ("bridge", "nic.bridge/0"),
1469 4cc4d1fa Michael Hanselmann
    ("nic_mode", "nic.mode/0"),
1470 4cc4d1fa Michael Hanselmann
    ("nic_link", "nic.link/0"),
1471 4cc4d1fa Michael Hanselmann
    ]
1472 4cc4d1fa Michael Hanselmann
1473 4cc4d1fa Michael Hanselmann
  return (fields, aliases)
1474 1c8addc6 Michael Hanselmann
1475 1c8addc6 Michael Hanselmann
1476 1c8addc6 Michael Hanselmann
def _GetInstDiskUsage(ctx, inst):
1477 1c8addc6 Michael Hanselmann
  """Get disk usage for an instance.
1478 1c8addc6 Michael Hanselmann

1479 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1480 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1481 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1482 1c8addc6 Michael Hanselmann

1483 1c8addc6 Michael Hanselmann
  """
1484 1c8addc6 Michael Hanselmann
  usage = ctx.disk_usage[inst.name]
1485 1c8addc6 Michael Hanselmann
1486 1c8addc6 Michael Hanselmann
  if usage is None:
1487 1c8addc6 Michael Hanselmann
    usage = 0
1488 1c8addc6 Michael Hanselmann
1489 e2d188cc Iustin Pop
  return usage
1490 1c8addc6 Michael Hanselmann
1491 1c8addc6 Michael Hanselmann
1492 5d28cb6f Michael Hanselmann
def _GetInstanceConsole(ctx, inst):
1493 5d28cb6f Michael Hanselmann
  """Get console information for instance.
1494 5d28cb6f Michael Hanselmann

1495 5d28cb6f Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1496 5d28cb6f Michael Hanselmann
  @type inst: L{objects.Instance}
1497 5d28cb6f Michael Hanselmann
  @param inst: Instance object
1498 5d28cb6f Michael Hanselmann

1499 5d28cb6f Michael Hanselmann
  """
1500 5d28cb6f Michael Hanselmann
  consinfo = ctx.console[inst.name]
1501 5d28cb6f Michael Hanselmann
1502 5d28cb6f Michael Hanselmann
  if consinfo is None:
1503 5d28cb6f Michael Hanselmann
    return _FS_UNAVAIL
1504 5d28cb6f Michael Hanselmann
1505 5d28cb6f Michael Hanselmann
  return consinfo
1506 5d28cb6f Michael Hanselmann
1507 5d28cb6f Michael Hanselmann
1508 1c8addc6 Michael Hanselmann
def _GetInstanceDiskFields():
1509 1c8addc6 Michael Hanselmann
  """Get instance fields involving disks.
1510 1c8addc6 Michael Hanselmann

1511 1c8addc6 Michael Hanselmann
  @return: List of field definitions used as input for L{_PrepareFieldList}
1512 1c8addc6 Michael Hanselmann

1513 1c8addc6 Michael Hanselmann
  """
1514 1c8addc6 Michael Hanselmann
  fields = [
1515 79b2ca83 Michael Hanselmann
    (_MakeField("disk_usage", "DiskUsage", QFT_UNIT,
1516 79b2ca83 Michael Hanselmann
                "Total disk space used by instance on each of its nodes;"
1517 79b2ca83 Michael Hanselmann
                " this is not the disk size visible to the instance, but"
1518 79b2ca83 Michael Hanselmann
                " the usage on the node"),
1519 111bf531 Michael Hanselmann
     IQ_DISKUSAGE, 0, _GetInstDiskUsage),
1520 79b2ca83 Michael Hanselmann
    (_MakeField("disk.count", "Disks", QFT_NUMBER, "Number of disks"),
1521 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: len(inst.disks)),
1522 79b2ca83 Michael Hanselmann
    (_MakeField("disk.sizes", "Disk_sizes", QFT_OTHER, "List of disk sizes"),
1523 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [disk.size for disk in inst.disks]),
1524 1c8addc6 Michael Hanselmann
    ]
1525 1c8addc6 Michael Hanselmann
1526 1c8addc6 Michael Hanselmann
  # Disks by number
1527 1c8addc6 Michael Hanselmann
  fields.extend([
1528 79b2ca83 Michael Hanselmann
    (_MakeField("disk.size/%s" % i, "Disk/%s" % i, QFT_UNIT,
1529 79b2ca83 Michael Hanselmann
                "Disk size of %s disk" % utils.FormatOrdinal(i + 1)),
1530 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstDiskSize(i))
1531 1c8addc6 Michael Hanselmann
    for i in range(constants.MAX_DISKS)
1532 1c8addc6 Michael Hanselmann
    ])
1533 1c8addc6 Michael Hanselmann
1534 1c8addc6 Michael Hanselmann
  return fields
1535 1c8addc6 Michael Hanselmann
1536 1c8addc6 Michael Hanselmann
1537 1c8addc6 Michael Hanselmann
def _GetInstanceParameterFields():
1538 1c8addc6 Michael Hanselmann
  """Get instance fields involving parameters.
1539 1c8addc6 Michael Hanselmann

1540 1c8addc6 Michael Hanselmann
  @return: List of field definitions used as input for L{_PrepareFieldList}
1541 1c8addc6 Michael Hanselmann

1542 1c8addc6 Michael Hanselmann
  """
1543 1c8addc6 Michael Hanselmann
  # TODO: Consider moving titles closer to constants
1544 1c8addc6 Michael Hanselmann
  be_title = {
1545 1c8addc6 Michael Hanselmann
    constants.BE_AUTO_BALANCE: "Auto_balance",
1546 0ca7e384 Iustin Pop
    constants.BE_MEMORY: "ConfigMemory",
1547 0ca7e384 Iustin Pop
    constants.BE_VCPUS: "ConfigVCPUs",
1548 1c8addc6 Michael Hanselmann
    }
1549 1c8addc6 Michael Hanselmann
1550 1c8addc6 Michael Hanselmann
  hv_title = {
1551 1c8addc6 Michael Hanselmann
    constants.HV_ACPI: "ACPI",
1552 1c8addc6 Michael Hanselmann
    constants.HV_BOOT_ORDER: "Boot_order",
1553 1c8addc6 Michael Hanselmann
    constants.HV_CDROM_IMAGE_PATH: "CDROM_image_path",
1554 1c8addc6 Michael Hanselmann
    constants.HV_DISK_TYPE: "Disk_type",
1555 1c8addc6 Michael Hanselmann
    constants.HV_INITRD_PATH: "Initrd_path",
1556 1c8addc6 Michael Hanselmann
    constants.HV_KERNEL_PATH: "Kernel_path",
1557 1c8addc6 Michael Hanselmann
    constants.HV_NIC_TYPE: "NIC_type",
1558 1c8addc6 Michael Hanselmann
    constants.HV_PAE: "PAE",
1559 1c8addc6 Michael Hanselmann
    constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
1560 1c8addc6 Michael Hanselmann
    }
1561 1c8addc6 Michael Hanselmann
1562 1c8addc6 Michael Hanselmann
  fields = [
1563 1c8addc6 Michael Hanselmann
    # Filled parameters
1564 79b2ca83 Michael Hanselmann
    (_MakeField("hvparams", "HypervisorParameters", QFT_OTHER,
1565 79b2ca83 Michael Hanselmann
                "Hypervisor parameters"),
1566 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, _: ctx.inst_hvparams),
1567 79b2ca83 Michael Hanselmann
    (_MakeField("beparams", "BackendParameters", QFT_OTHER,
1568 79b2ca83 Michael Hanselmann
                "Backend parameters"),
1569 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, _: ctx.inst_beparams),
1570 1c8addc6 Michael Hanselmann
1571 1c8addc6 Michael Hanselmann
    # Unfilled parameters
1572 79b2ca83 Michael Hanselmann
    (_MakeField("custom_hvparams", "CustomHypervisorParameters", QFT_OTHER,
1573 79b2ca83 Michael Hanselmann
                "Custom hypervisor parameters"),
1574 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetItemAttr("hvparams")),
1575 79b2ca83 Michael Hanselmann
    (_MakeField("custom_beparams", "CustomBackendParameters", QFT_OTHER,
1576 79b2ca83 Michael Hanselmann
                "Custom backend parameters",),
1577 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetItemAttr("beparams")),
1578 79b2ca83 Michael Hanselmann
    (_MakeField("custom_nicparams", "CustomNicParameters", QFT_OTHER,
1579 79b2ca83 Michael Hanselmann
                "Custom network interface parameters"),
1580 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [nic.nicparams for nic in inst.nics]),
1581 1c8addc6 Michael Hanselmann
    ]
1582 1c8addc6 Michael Hanselmann
1583 1c8addc6 Michael Hanselmann
  # HV params
1584 1c8addc6 Michael Hanselmann
  def _GetInstHvParam(name):
1585 ff4cd4d2 Iustin Pop
    return lambda ctx, _: ctx.inst_hvparams.get(name, _FS_UNAVAIL)
1586 1c8addc6 Michael Hanselmann
1587 1c8addc6 Michael Hanselmann
  fields.extend([
1588 af58707c Iustin Pop
    (_MakeField("hv/%s" % name, hv_title.get(name, "hv/%s" % name),
1589 79b2ca83 Michael Hanselmann
                _VTToQFT[kind], "The \"%s\" hypervisor parameter" % name),
1590 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstHvParam(name))
1591 af58707c Iustin Pop
    for name, kind in constants.HVS_PARAMETER_TYPES.items()
1592 1c8addc6 Michael Hanselmann
    if name not in constants.HVC_GLOBALS
1593 1c8addc6 Michael Hanselmann
    ])
1594 1c8addc6 Michael Hanselmann
1595 1c8addc6 Michael Hanselmann
  # BE params
1596 1c8addc6 Michael Hanselmann
  def _GetInstBeParam(name):
1597 e2d188cc Iustin Pop
    return lambda ctx, _: ctx.inst_beparams.get(name, None)
1598 1c8addc6 Michael Hanselmann
1599 1c8addc6 Michael Hanselmann
  fields.extend([
1600 af58707c Iustin Pop
    (_MakeField("be/%s" % name, be_title.get(name, "be/%s" % name),
1601 79b2ca83 Michael Hanselmann
                _VTToQFT[kind], "The \"%s\" backend parameter" % name),
1602 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstBeParam(name))
1603 af58707c Iustin Pop
    for name, kind in constants.BES_PARAMETER_TYPES.items()
1604 1c8addc6 Michael Hanselmann
    ])
1605 1c8addc6 Michael Hanselmann
1606 1c8addc6 Michael Hanselmann
  return fields
1607 1c8addc6 Michael Hanselmann
1608 1c8addc6 Michael Hanselmann
1609 1c8addc6 Michael Hanselmann
_INST_SIMPLE_FIELDS = {
1610 111bf531 Michael Hanselmann
  "disk_template": ("Disk_template", QFT_TEXT, 0, "Instance disk template"),
1611 111bf531 Michael Hanselmann
  "hypervisor": ("Hypervisor", QFT_TEXT, 0, "Hypervisor name"),
1612 111bf531 Michael Hanselmann
  "name": ("Instance", QFT_TEXT, QFF_HOSTNAME, "Instance name"),
1613 1c8addc6 Michael Hanselmann
  # Depending on the hypervisor, the port can be None
1614 111bf531 Michael Hanselmann
  "network_port": ("Network_port", QFT_OTHER, 0,
1615 79b2ca83 Michael Hanselmann
                   "Instance network port if available (e.g. for VNC console)"),
1616 111bf531 Michael Hanselmann
  "os": ("OS", QFT_TEXT, 0, "Operating system"),
1617 111bf531 Michael Hanselmann
  "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Instance"),
1618 111bf531 Michael Hanselmann
  "uuid": ("UUID", QFT_TEXT, 0, "Instance UUID"),
1619 1c8addc6 Michael Hanselmann
  }
1620 1c8addc6 Michael Hanselmann
1621 1c8addc6 Michael Hanselmann
1622 1c8addc6 Michael Hanselmann
def _BuildInstanceFields():
1623 1c8addc6 Michael Hanselmann
  """Builds list of fields for instance queries.
1624 1c8addc6 Michael Hanselmann

1625 1c8addc6 Michael Hanselmann
  """
1626 1c8addc6 Michael Hanselmann
  fields = [
1627 111bf531 Michael Hanselmann
    (_MakeField("pnode", "Primary_node", QFT_TEXT, "Primary node"),
1628 111bf531 Michael Hanselmann
     IQ_CONFIG, QFF_HOSTNAME, _GetItemAttr("primary_node")),
1629 111bf531 Michael Hanselmann
    # TODO: Allow filtering by secondary node as hostname
1630 79b2ca83 Michael Hanselmann
    (_MakeField("snodes", "Secondary_Nodes", QFT_OTHER,
1631 79b2ca83 Michael Hanselmann
                "Secondary nodes; usually this will just be one node"),
1632 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: list(inst.secondary_nodes)),
1633 79b2ca83 Michael Hanselmann
    (_MakeField("admin_state", "Autostart", QFT_BOOL,
1634 79b2ca83 Michael Hanselmann
                "Desired state of instance (if set, the instance should be"
1635 79b2ca83 Michael Hanselmann
                " up)"),
1636 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetItemAttr("admin_up")),
1637 111bf531 Michael Hanselmann
    (_MakeField("tags", "Tags", QFT_OTHER, "Tags"), IQ_CONFIG, 0,
1638 e2d188cc Iustin Pop
     lambda ctx, inst: list(inst.GetTags())),
1639 79b2ca83 Michael Hanselmann
    (_MakeField("console", "Console", QFT_OTHER,
1640 111bf531 Michael Hanselmann
                "Instance console information"), IQ_CONSOLE, 0,
1641 5d28cb6f Michael Hanselmann
     _GetInstanceConsole),
1642 1c8addc6 Michael Hanselmann
    ]
1643 1c8addc6 Michael Hanselmann
1644 1c8addc6 Michael Hanselmann
  # Add simple fields
1645 111bf531 Michael Hanselmann
  fields.extend([
1646 111bf531 Michael Hanselmann
    (_MakeField(name, title, kind, doc), IQ_CONFIG, flags, _GetItemAttr(name))
1647 111bf531 Michael Hanselmann
    for (name, (title, kind, flags, doc)) in _INST_SIMPLE_FIELDS.items()
1648 111bf531 Michael Hanselmann
    ])
1649 1c8addc6 Michael Hanselmann
1650 1c8addc6 Michael Hanselmann
  # Fields requiring talking to the node
1651 1c8addc6 Michael Hanselmann
  fields.extend([
1652 79b2ca83 Michael Hanselmann
    (_MakeField("oper_state", "Running", QFT_BOOL, "Actual state of instance"),
1653 111bf531 Michael Hanselmann
     IQ_LIVE, 0, _GetInstOperState),
1654 79b2ca83 Michael Hanselmann
    (_MakeField("oper_ram", "Memory", QFT_UNIT,
1655 79b2ca83 Michael Hanselmann
                "Actual memory usage as seen by hypervisor"),
1656 111bf531 Michael Hanselmann
     IQ_LIVE, 0, _GetInstLiveData("memory")),
1657 79b2ca83 Michael Hanselmann
    (_MakeField("oper_vcpus", "VCPUs", QFT_NUMBER,
1658 79b2ca83 Michael Hanselmann
                "Actual number of VCPUs as seen by hypervisor"),
1659 111bf531 Michael Hanselmann
     IQ_LIVE, 0, _GetInstLiveData("vcpus")),
1660 1c8addc6 Michael Hanselmann
    ])
1661 1c8addc6 Michael Hanselmann
1662 79b2ca83 Michael Hanselmann
  # Status field
1663 79b2ca83 Michael Hanselmann
  status_values = (constants.INSTST_RUNNING, constants.INSTST_ADMINDOWN,
1664 79b2ca83 Michael Hanselmann
                   constants.INSTST_WRONGNODE, constants.INSTST_ERRORUP,
1665 79b2ca83 Michael Hanselmann
                   constants.INSTST_ERRORDOWN, constants.INSTST_NODEDOWN,
1666 79b2ca83 Michael Hanselmann
                   constants.INSTST_NODEOFFLINE)
1667 79b2ca83 Michael Hanselmann
  status_doc = ("Instance status; \"%s\" if instance is set to be running"
1668 79b2ca83 Michael Hanselmann
                " and actually is, \"%s\" if instance is stopped and"
1669 79b2ca83 Michael Hanselmann
                " is not running, \"%s\" if instance running, but not on its"
1670 79b2ca83 Michael Hanselmann
                " designated primary node, \"%s\" if instance should be"
1671 79b2ca83 Michael Hanselmann
                " stopped, but is actually running, \"%s\" if instance should"
1672 79b2ca83 Michael Hanselmann
                " run, but doesn't, \"%s\" if instance's primary node is down,"
1673 79b2ca83 Michael Hanselmann
                " \"%s\" if instance's primary node is marked offline" %
1674 79b2ca83 Michael Hanselmann
                status_values)
1675 79b2ca83 Michael Hanselmann
  fields.append((_MakeField("status", "Status", QFT_TEXT, status_doc),
1676 111bf531 Michael Hanselmann
                 IQ_LIVE, 0, _GetInstStatus))
1677 79b2ca83 Michael Hanselmann
  assert set(status_values) == constants.INSTST_ALL, \
1678 79b2ca83 Michael Hanselmann
         "Status documentation mismatch"
1679 79b2ca83 Michael Hanselmann
1680 4cc4d1fa Michael Hanselmann
  (network_fields, network_aliases) = _GetInstanceNetworkFields()
1681 4cc4d1fa Michael Hanselmann
1682 4cc4d1fa Michael Hanselmann
  fields.extend(network_fields)
1683 1c8addc6 Michael Hanselmann
  fields.extend(_GetInstanceParameterFields())
1684 1c8addc6 Michael Hanselmann
  fields.extend(_GetInstanceDiskFields())
1685 145bea54 Michael Hanselmann
  fields.extend(_GetItemTimestampFields(IQ_CONFIG))
1686 1c8addc6 Michael Hanselmann
1687 e7e8037b Iustin Pop
  aliases = [
1688 e7e8037b Iustin Pop
    ("vcpus", "be/vcpus"),
1689 e7e8037b Iustin Pop
    ("sda_size", "disk.size/0"),
1690 e7e8037b Iustin Pop
    ("sdb_size", "disk.size/1"),
1691 4cc4d1fa Michael Hanselmann
    ] + network_aliases
1692 e7e8037b Iustin Pop
1693 e7e8037b Iustin Pop
  return _PrepareFieldList(fields, aliases)
1694 1c8addc6 Michael Hanselmann
1695 1c8addc6 Michael Hanselmann
1696 24d16f76 Michael Hanselmann
class LockQueryData:
1697 24d16f76 Michael Hanselmann
  """Data container for lock data queries.
1698 24d16f76 Michael Hanselmann

1699 24d16f76 Michael Hanselmann
  """
1700 24d16f76 Michael Hanselmann
  def __init__(self, lockdata):
1701 24d16f76 Michael Hanselmann
    """Initializes this class.
1702 24d16f76 Michael Hanselmann

1703 24d16f76 Michael Hanselmann
    """
1704 24d16f76 Michael Hanselmann
    self.lockdata = lockdata
1705 24d16f76 Michael Hanselmann
1706 24d16f76 Michael Hanselmann
  def __iter__(self):
1707 24d16f76 Michael Hanselmann
    """Iterate over all locks.
1708 24d16f76 Michael Hanselmann

1709 24d16f76 Michael Hanselmann
    """
1710 24d16f76 Michael Hanselmann
    return iter(self.lockdata)
1711 24d16f76 Michael Hanselmann
1712 24d16f76 Michael Hanselmann
1713 24d16f76 Michael Hanselmann
def _GetLockOwners(_, data):
1714 24d16f76 Michael Hanselmann
  """Returns a sorted list of a lock's current owners.
1715 24d16f76 Michael Hanselmann

1716 24d16f76 Michael Hanselmann
  """
1717 24d16f76 Michael Hanselmann
  (_, _, owners, _) = data
1718 24d16f76 Michael Hanselmann
1719 24d16f76 Michael Hanselmann
  if owners:
1720 24d16f76 Michael Hanselmann
    owners = utils.NiceSort(owners)
1721 24d16f76 Michael Hanselmann
1722 e2d188cc Iustin Pop
  return owners
1723 24d16f76 Michael Hanselmann
1724 24d16f76 Michael Hanselmann
1725 24d16f76 Michael Hanselmann
def _GetLockPending(_, data):
1726 24d16f76 Michael Hanselmann
  """Returns a sorted list of a lock's pending acquires.
1727 24d16f76 Michael Hanselmann

1728 24d16f76 Michael Hanselmann
  """
1729 24d16f76 Michael Hanselmann
  (_, _, _, pending) = data
1730 24d16f76 Michael Hanselmann
1731 24d16f76 Michael Hanselmann
  if pending:
1732 24d16f76 Michael Hanselmann
    pending = [(mode, utils.NiceSort(names))
1733 24d16f76 Michael Hanselmann
               for (mode, names) in pending]
1734 24d16f76 Michael Hanselmann
1735 e2d188cc Iustin Pop
  return pending
1736 24d16f76 Michael Hanselmann
1737 24d16f76 Michael Hanselmann
1738 24d16f76 Michael Hanselmann
def _BuildLockFields():
1739 24d16f76 Michael Hanselmann
  """Builds list of fields for lock queries.
1740 24d16f76 Michael Hanselmann

1741 24d16f76 Michael Hanselmann
  """
1742 24d16f76 Michael Hanselmann
  return _PrepareFieldList([
1743 111bf531 Michael Hanselmann
    # TODO: Lock names are not always hostnames. Should QFF_HOSTNAME be used?
1744 111bf531 Michael Hanselmann
    (_MakeField("name", "Name", QFT_TEXT, "Lock name"), None, 0,
1745 e2d188cc Iustin Pop
     lambda ctx, (name, mode, owners, pending): name),
1746 79b2ca83 Michael Hanselmann
    (_MakeField("mode", "Mode", QFT_OTHER,
1747 79b2ca83 Michael Hanselmann
                "Mode in which the lock is currently acquired"
1748 79b2ca83 Michael Hanselmann
                " (exclusive or shared)"),
1749 111bf531 Michael Hanselmann
     LQ_MODE, 0, lambda ctx, (name, mode, owners, pending): mode),
1750 79b2ca83 Michael Hanselmann
    (_MakeField("owner", "Owner", QFT_OTHER, "Current lock owner(s)"),
1751 111bf531 Michael Hanselmann
     LQ_OWNER, 0, _GetLockOwners),
1752 79b2ca83 Michael Hanselmann
    (_MakeField("pending", "Pending", QFT_OTHER,
1753 79b2ca83 Michael Hanselmann
                "Threads waiting for the lock"),
1754 111bf531 Michael Hanselmann
     LQ_PENDING, 0, _GetLockPending),
1755 d63bd540 Iustin Pop
    ], [])
1756 24d16f76 Michael Hanselmann
1757 24d16f76 Michael Hanselmann
1758 8e21cfc0 Adeodato Simo
class GroupQueryData:
1759 8e21cfc0 Adeodato Simo
  """Data container for node group data queries.
1760 8e21cfc0 Adeodato Simo

1761 8e21cfc0 Adeodato Simo
  """
1762 8e21cfc0 Adeodato Simo
  def __init__(self, groups, group_to_nodes, group_to_instances):
1763 8e21cfc0 Adeodato Simo
    """Initializes this class.
1764 8e21cfc0 Adeodato Simo

1765 8e21cfc0 Adeodato Simo
    @param groups: List of node group objects
1766 8e21cfc0 Adeodato Simo
    @type group_to_nodes: dict; group UUID as key
1767 8e21cfc0 Adeodato Simo
    @param group_to_nodes: Per-group list of nodes
1768 8e21cfc0 Adeodato Simo
    @type group_to_instances: dict; group UUID as key
1769 8e21cfc0 Adeodato Simo
    @param group_to_instances: Per-group list of (primary) instances
1770 8e21cfc0 Adeodato Simo

1771 8e21cfc0 Adeodato Simo
    """
1772 8e21cfc0 Adeodato Simo
    self.groups = groups
1773 8e21cfc0 Adeodato Simo
    self.group_to_nodes = group_to_nodes
1774 8e21cfc0 Adeodato Simo
    self.group_to_instances = group_to_instances
1775 8e21cfc0 Adeodato Simo
1776 8e21cfc0 Adeodato Simo
  def __iter__(self):
1777 8e21cfc0 Adeodato Simo
    """Iterate over all node groups.
1778 8e21cfc0 Adeodato Simo

1779 8e21cfc0 Adeodato Simo
    """
1780 8e21cfc0 Adeodato Simo
    return iter(self.groups)
1781 8e21cfc0 Adeodato Simo
1782 8e21cfc0 Adeodato Simo
1783 8e21cfc0 Adeodato Simo
_GROUP_SIMPLE_FIELDS = {
1784 79b2ca83 Michael Hanselmann
  "alloc_policy": ("AllocPolicy", QFT_TEXT, "Allocation policy for group"),
1785 79b2ca83 Michael Hanselmann
  "name": ("Group", QFT_TEXT, "Group name"),
1786 79b2ca83 Michael Hanselmann
  "serial_no": ("SerialNo", QFT_NUMBER, _SERIAL_NO_DOC % "Group"),
1787 79b2ca83 Michael Hanselmann
  "uuid": ("UUID", QFT_TEXT, "Group UUID"),
1788 79b2ca83 Michael Hanselmann
  "ndparams": ("NDParams", QFT_OTHER, "Node parameters"),
1789 8e21cfc0 Adeodato Simo
  }
1790 8e21cfc0 Adeodato Simo
1791 8e21cfc0 Adeodato Simo
1792 8e21cfc0 Adeodato Simo
def _BuildGroupFields():
1793 8e21cfc0 Adeodato Simo
  """Builds list of fields for node group queries.
1794 8e21cfc0 Adeodato Simo

1795 8e21cfc0 Adeodato Simo
  """
1796 8e21cfc0 Adeodato Simo
  # Add simple fields
1797 111bf531 Michael Hanselmann
  fields = [(_MakeField(name, title, kind, doc), GQ_CONFIG, 0,
1798 111bf531 Michael Hanselmann
             _GetItemAttr(name))
1799 79b2ca83 Michael Hanselmann
            for (name, (title, kind, doc)) in _GROUP_SIMPLE_FIELDS.items()]
1800 8e21cfc0 Adeodato Simo
1801 8e21cfc0 Adeodato Simo
  def _GetLength(getter):
1802 e2d188cc Iustin Pop
    return lambda ctx, group: len(getter(ctx)[group.uuid])
1803 8e21cfc0 Adeodato Simo
1804 8e21cfc0 Adeodato Simo
  def _GetSortedList(getter):
1805 e2d188cc Iustin Pop
    return lambda ctx, group: utils.NiceSort(getter(ctx)[group.uuid])
1806 8e21cfc0 Adeodato Simo
1807 8e21cfc0 Adeodato Simo
  group_to_nodes = operator.attrgetter("group_to_nodes")
1808 8e21cfc0 Adeodato Simo
  group_to_instances = operator.attrgetter("group_to_instances")
1809 8e21cfc0 Adeodato Simo
1810 8e21cfc0 Adeodato Simo
  # Add fields for nodes
1811 8e21cfc0 Adeodato Simo
  fields.extend([
1812 79b2ca83 Michael Hanselmann
    (_MakeField("node_cnt", "Nodes", QFT_NUMBER, "Number of nodes"),
1813 111bf531 Michael Hanselmann
     GQ_NODE, 0, _GetLength(group_to_nodes)),
1814 79b2ca83 Michael Hanselmann
    (_MakeField("node_list", "NodeList", QFT_OTHER, "List of nodes"),
1815 111bf531 Michael Hanselmann
     GQ_NODE, 0, _GetSortedList(group_to_nodes)),
1816 8e21cfc0 Adeodato Simo
    ])
1817 8e21cfc0 Adeodato Simo
1818 8e21cfc0 Adeodato Simo
  # Add fields for instances
1819 8e21cfc0 Adeodato Simo
  fields.extend([
1820 79b2ca83 Michael Hanselmann
    (_MakeField("pinst_cnt", "Instances", QFT_NUMBER,
1821 79b2ca83 Michael Hanselmann
                "Number of primary instances"),
1822 111bf531 Michael Hanselmann
     GQ_INST, 0, _GetLength(group_to_instances)),
1823 79b2ca83 Michael Hanselmann
    (_MakeField("pinst_list", "InstanceList", QFT_OTHER,
1824 79b2ca83 Michael Hanselmann
                "List of primary instances"),
1825 111bf531 Michael Hanselmann
     GQ_INST, 0, _GetSortedList(group_to_instances)),
1826 8e21cfc0 Adeodato Simo
    ])
1827 8e21cfc0 Adeodato Simo
1828 8e21cfc0 Adeodato Simo
  fields.extend(_GetItemTimestampFields(GQ_CONFIG))
1829 8e21cfc0 Adeodato Simo
1830 d63bd540 Iustin Pop
  return _PrepareFieldList(fields, [])
1831 8e21cfc0 Adeodato Simo
1832 8e21cfc0 Adeodato Simo
1833 8235fe04 Michael Hanselmann
#: Fields available for node queries
1834 8235fe04 Michael Hanselmann
NODE_FIELDS = _BuildNodeFields()
1835 1c8addc6 Michael Hanselmann
1836 1c8addc6 Michael Hanselmann
#: Fields available for instance queries
1837 1c8addc6 Michael Hanselmann
INSTANCE_FIELDS = _BuildInstanceFields()
1838 24d16f76 Michael Hanselmann
1839 24d16f76 Michael Hanselmann
#: Fields available for lock queries
1840 24d16f76 Michael Hanselmann
LOCK_FIELDS = _BuildLockFields()
1841 e571ee44 Adeodato Simo
1842 8e21cfc0 Adeodato Simo
#: Fields available for node group queries
1843 8e21cfc0 Adeodato Simo
GROUP_FIELDS = _BuildGroupFields()
1844 8e21cfc0 Adeodato Simo
1845 95eb4188 Michael Hanselmann
#: All available resources
1846 95eb4188 Michael Hanselmann
ALL_FIELDS = {
1847 95eb4188 Michael Hanselmann
  constants.QR_INSTANCE: INSTANCE_FIELDS,
1848 95eb4188 Michael Hanselmann
  constants.QR_NODE: NODE_FIELDS,
1849 95eb4188 Michael Hanselmann
  constants.QR_LOCK: LOCK_FIELDS,
1850 95eb4188 Michael Hanselmann
  constants.QR_GROUP: GROUP_FIELDS,
1851 95eb4188 Michael Hanselmann
  }
1852 95eb4188 Michael Hanselmann
1853 e571ee44 Adeodato Simo
#: All available field lists
1854 95eb4188 Michael Hanselmann
ALL_FIELD_LISTS = ALL_FIELDS.values()