Statistics
| Branch: | Tag: | Revision:

root / lib / query.py @ 3b877f08

History | View | Annotate | Download (54.6 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 3b877f08 Michael Hanselmann
    - C{_OPTYPE_UNARY}: Always C{None}; details handled by L{_HandleUnaryOp}
361 fb0be379 Michael Hanselmann
    - C{_OPTYPE_BINARY}: Callable taking exactly two parameters, the left- and
362 fb0be379 Michael Hanselmann
      right-hand side of the operator, used by L{_HandleBinaryOp}
363 fb0be379 Michael Hanselmann

364 fb0be379 Michael Hanselmann
  """
365 fb0be379 Michael Hanselmann
  _OPS = {
366 fb0be379 Michael Hanselmann
    # Logic operators
367 fb0be379 Michael Hanselmann
    qlang.OP_OR: (_OPTYPE_LOGIC, compat.any),
368 fb0be379 Michael Hanselmann
    qlang.OP_AND: (_OPTYPE_LOGIC, compat.all),
369 fb0be379 Michael Hanselmann
370 fb0be379 Michael Hanselmann
    # Unary operators
371 3b877f08 Michael Hanselmann
    qlang.OP_NOT: (_OPTYPE_UNARY, None),
372 3b877f08 Michael Hanselmann
    qlang.OP_TRUE: (_OPTYPE_UNARY, None),
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 3b877f08 Michael Hanselmann
  def _LookupField(self, name):
453 3b877f08 Michael Hanselmann
    """Returns a field definition by name.
454 3b877f08 Michael Hanselmann

455 3b877f08 Michael Hanselmann
    """
456 3b877f08 Michael Hanselmann
    try:
457 3b877f08 Michael Hanselmann
      return self._fields[name]
458 3b877f08 Michael Hanselmann
    except KeyError:
459 3b877f08 Michael Hanselmann
      raise errors.ParameterError("Unknown field '%s'" % name)
460 3b877f08 Michael Hanselmann
461 fb0be379 Michael Hanselmann
  def _HandleLogicOp(self, hints_fn, level, op, op_fn, operands):
462 fb0be379 Michael Hanselmann
    """Handles logic operators.
463 fb0be379 Michael Hanselmann

464 fb0be379 Michael Hanselmann
    @type hints_fn: callable
465 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
466 fb0be379 Michael Hanselmann
    @type level: integer
467 fb0be379 Michael Hanselmann
    @param level: Current depth
468 fb0be379 Michael Hanselmann
    @type op: string
469 fb0be379 Michael Hanselmann
    @param op: Operator
470 fb0be379 Michael Hanselmann
    @type op_fn: callable
471 fb0be379 Michael Hanselmann
    @param op_fn: Function implementing operator
472 fb0be379 Michael Hanselmann
    @type operands: list
473 fb0be379 Michael Hanselmann
    @param operands: List of operands
474 fb0be379 Michael Hanselmann

475 fb0be379 Michael Hanselmann
    """
476 fb0be379 Michael Hanselmann
    if hints_fn:
477 fb0be379 Michael Hanselmann
      hints_fn(op)
478 fb0be379 Michael Hanselmann
479 fb0be379 Michael Hanselmann
    return compat.partial(_WrapLogicOp, op_fn,
480 fb0be379 Michael Hanselmann
                          [self._Compile(op, level + 1) for op in operands])
481 fb0be379 Michael Hanselmann
482 fb0be379 Michael Hanselmann
  def _HandleUnaryOp(self, hints_fn, level, op, op_fn, operands):
483 fb0be379 Michael Hanselmann
    """Handles unary operators.
484 fb0be379 Michael Hanselmann

485 fb0be379 Michael Hanselmann
    @type hints_fn: callable
486 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
487 fb0be379 Michael Hanselmann
    @type level: integer
488 fb0be379 Michael Hanselmann
    @param level: Current depth
489 fb0be379 Michael Hanselmann
    @type op: string
490 fb0be379 Michael Hanselmann
    @param op: Operator
491 fb0be379 Michael Hanselmann
    @type op_fn: callable
492 fb0be379 Michael Hanselmann
    @param op_fn: Function implementing operator
493 fb0be379 Michael Hanselmann
    @type operands: list
494 fb0be379 Michael Hanselmann
    @param operands: List of operands
495 fb0be379 Michael Hanselmann

496 fb0be379 Michael Hanselmann
    """
497 3b877f08 Michael Hanselmann
    assert op_fn is None
498 3b877f08 Michael Hanselmann
499 fb0be379 Michael Hanselmann
    if hints_fn:
500 fb0be379 Michael Hanselmann
      hints_fn(op)
501 fb0be379 Michael Hanselmann
502 fb0be379 Michael Hanselmann
    if len(operands) != 1:
503 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unary operator '%s' expects exactly one"
504 fb0be379 Michael Hanselmann
                                  " operand" % op)
505 fb0be379 Michael Hanselmann
506 3b877f08 Michael Hanselmann
    if op == qlang.OP_TRUE:
507 3b877f08 Michael Hanselmann
      (_, _, _, retrieval_fn) = self._LookupField(operands[0])
508 3b877f08 Michael Hanselmann
509 3b877f08 Michael Hanselmann
      op_fn = operator.truth
510 3b877f08 Michael Hanselmann
      arg = retrieval_fn
511 3b877f08 Michael Hanselmann
    elif op == qlang.OP_NOT:
512 3b877f08 Michael Hanselmann
      op_fn = operator.not_
513 3b877f08 Michael Hanselmann
      arg = self._Compile(operands[0], level + 1)
514 3b877f08 Michael Hanselmann
    else:
515 3b877f08 Michael Hanselmann
      raise errors.ProgrammerError("Can't handle operator '%s'" % op)
516 3b877f08 Michael Hanselmann
517 3b877f08 Michael Hanselmann
    return compat.partial(_WrapUnaryOp, op_fn, arg)
518 fb0be379 Michael Hanselmann
519 fb0be379 Michael Hanselmann
  def _HandleBinaryOp(self, hints_fn, level, op, op_data, operands):
520 fb0be379 Michael Hanselmann
    """Handles binary operators.
521 fb0be379 Michael Hanselmann

522 fb0be379 Michael Hanselmann
    @type hints_fn: callable
523 fb0be379 Michael Hanselmann
    @param hints_fn: Callback doing some analysis on the filter
524 fb0be379 Michael Hanselmann
    @type level: integer
525 fb0be379 Michael Hanselmann
    @param level: Current depth
526 fb0be379 Michael Hanselmann
    @type op: string
527 fb0be379 Michael Hanselmann
    @param op: Operator
528 fb0be379 Michael Hanselmann
    @param op_data: Functions implementing operators
529 fb0be379 Michael Hanselmann
    @type operands: list
530 fb0be379 Michael Hanselmann
    @param operands: List of operands
531 fb0be379 Michael Hanselmann

532 fb0be379 Michael Hanselmann
    """
533 fb0be379 Michael Hanselmann
    # Unused arguments, pylint: disable-msg=W0613
534 fb0be379 Michael Hanselmann
    try:
535 fb0be379 Michael Hanselmann
      (name, value) = operands
536 fb0be379 Michael Hanselmann
    except (ValueError, TypeError):
537 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Invalid binary operator, expected exactly"
538 fb0be379 Michael Hanselmann
                                  " two operands")
539 fb0be379 Michael Hanselmann
540 3b877f08 Michael Hanselmann
    (fdef, datakind, field_flags, retrieval_fn) = self._LookupField(name)
541 fb0be379 Michael Hanselmann
542 fb0be379 Michael Hanselmann
    assert fdef.kind != QFT_UNKNOWN
543 fb0be379 Michael Hanselmann
544 fb0be379 Michael Hanselmann
    # TODO: Type conversions?
545 fb0be379 Michael Hanselmann
546 fb0be379 Michael Hanselmann
    verify_fn = _VERIFY_FN[fdef.kind]
547 fb0be379 Michael Hanselmann
    if not verify_fn(value):
548 fb0be379 Michael Hanselmann
      raise errors.ParameterError("Unable to compare field '%s' (type '%s')"
549 fb0be379 Michael Hanselmann
                                  " with '%s', expected %s" %
550 fb0be379 Michael Hanselmann
                                  (name, fdef.kind, value.__class__.__name__,
551 fb0be379 Michael Hanselmann
                                   verify_fn))
552 fb0be379 Michael Hanselmann
553 fb0be379 Michael Hanselmann
    if hints_fn:
554 fb0be379 Michael Hanselmann
      hints_fn(op, datakind, name, value)
555 fb0be379 Michael Hanselmann
556 fb0be379 Michael Hanselmann
    for (fn_flags, fn) in op_data:
557 fb0be379 Michael Hanselmann
      if fn_flags is None or fn_flags & field_flags:
558 fb0be379 Michael Hanselmann
        return compat.partial(_WrapBinaryOp, fn, retrieval_fn, value)
559 fb0be379 Michael Hanselmann
560 fb0be379 Michael Hanselmann
    raise errors.ProgrammerError("Unable to find operator implementation"
561 fb0be379 Michael Hanselmann
                                 " (op '%s', flags %s)" % (op, field_flags))
562 fb0be379 Michael Hanselmann
563 fb0be379 Michael Hanselmann
564 fb0be379 Michael Hanselmann
def _CompileFilter(fields, hints, filter_):
565 fb0be379 Michael Hanselmann
  """Converts a query filter into a callable function.
566 fb0be379 Michael Hanselmann

567 fb0be379 Michael Hanselmann
  See L{_FilterCompilerHelper} for details.
568 fb0be379 Michael Hanselmann

569 fb0be379 Michael Hanselmann
  @rtype: callable
570 fb0be379 Michael Hanselmann

571 fb0be379 Michael Hanselmann
  """
572 fb0be379 Michael Hanselmann
  return _FilterCompilerHelper(fields)(hints, filter_)
573 fb0be379 Michael Hanselmann
574 fb0be379 Michael Hanselmann
575 4ca96421 Michael Hanselmann
class Query:
576 fb0be379 Michael Hanselmann
  def __init__(self, fieldlist, selected, filter_=None, namefield=None):
577 4ca96421 Michael Hanselmann
    """Initializes this class.
578 4ca96421 Michael Hanselmann

579 4ca96421 Michael Hanselmann
    The field definition is a dictionary with the field's name as a key and a
580 4ca96421 Michael Hanselmann
    tuple containing, in order, the field definition object
581 4ca96421 Michael Hanselmann
    (L{objects.QueryFieldDefinition}, the data kind to help calling code
582 4ca96421 Michael Hanselmann
    collect data and a retrieval function. The retrieval function is called
583 4ca96421 Michael Hanselmann
    with two parameters, in order, the data container and the item in container
584 4ca96421 Michael Hanselmann
    (see L{Query.Query}).
585 4ca96421 Michael Hanselmann

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

589 4ca96421 Michael Hanselmann
    @type fieldlist: dictionary
590 4ca96421 Michael Hanselmann
    @param fieldlist: Field definitions
591 4ca96421 Michael Hanselmann
    @type selected: list of strings
592 4ca96421 Michael Hanselmann
    @param selected: List of selected fields
593 4ca96421 Michael Hanselmann

594 4ca96421 Michael Hanselmann
    """
595 fb0be379 Michael Hanselmann
    assert namefield is None or namefield in fieldlist
596 fb0be379 Michael Hanselmann
597 4ca96421 Michael Hanselmann
    self._fields = _GetQueryFields(fieldlist, selected)
598 4ca96421 Michael Hanselmann
599 fb0be379 Michael Hanselmann
    self._filter_fn = None
600 fb0be379 Michael Hanselmann
    self._requested_names = None
601 fb0be379 Michael Hanselmann
    self._filter_datakinds = frozenset()
602 fb0be379 Michael Hanselmann
603 fb0be379 Michael Hanselmann
    if filter_ is not None:
604 fb0be379 Michael Hanselmann
      # Collect requested names if wanted
605 fb0be379 Michael Hanselmann
      if namefield:
606 fb0be379 Michael Hanselmann
        hints = _FilterHints(namefield)
607 fb0be379 Michael Hanselmann
      else:
608 fb0be379 Michael Hanselmann
        hints = None
609 fb0be379 Michael Hanselmann
610 fb0be379 Michael Hanselmann
      # Build filter function
611 fb0be379 Michael Hanselmann
      self._filter_fn = _CompileFilter(fieldlist, hints, filter_)
612 fb0be379 Michael Hanselmann
      if hints:
613 fb0be379 Michael Hanselmann
        self._requested_names = hints.RequestedNames()
614 fb0be379 Michael Hanselmann
        self._filter_datakinds = hints.ReferencedData()
615 fb0be379 Michael Hanselmann
616 fb0be379 Michael Hanselmann
    if namefield is None:
617 fb0be379 Michael Hanselmann
      self._name_fn = None
618 fb0be379 Michael Hanselmann
    else:
619 fb0be379 Michael Hanselmann
      (_, _, _, self._name_fn) = fieldlist[namefield]
620 fb0be379 Michael Hanselmann
621 fb0be379 Michael Hanselmann
  def RequestedNames(self):
622 fb0be379 Michael Hanselmann
    """Returns all names referenced in the filter.
623 fb0be379 Michael Hanselmann

624 fb0be379 Michael Hanselmann
    If there is no filter or operators are preventing determining the exact
625 fb0be379 Michael Hanselmann
    names, C{None} is returned.
626 fb0be379 Michael Hanselmann

627 fb0be379 Michael Hanselmann
    """
628 fb0be379 Michael Hanselmann
    return self._requested_names
629 fb0be379 Michael Hanselmann
630 4ca96421 Michael Hanselmann
  def RequestedData(self):
631 4ca96421 Michael Hanselmann
    """Gets requested kinds of data.
632 4ca96421 Michael Hanselmann

633 4ca96421 Michael Hanselmann
    @rtype: frozenset
634 4ca96421 Michael Hanselmann

635 4ca96421 Michael Hanselmann
    """
636 fb0be379 Michael Hanselmann
    return (self._filter_datakinds |
637 fb0be379 Michael Hanselmann
            frozenset(datakind for (_, datakind, _, _) in self._fields
638 fb0be379 Michael Hanselmann
                      if datakind is not None))
639 4ca96421 Michael Hanselmann
640 4ca96421 Michael Hanselmann
  def GetFields(self):
641 4ca96421 Michael Hanselmann
    """Returns the list of fields for this query.
642 4ca96421 Michael Hanselmann

643 4ca96421 Michael Hanselmann
    Includes unknown fields.
644 4ca96421 Michael Hanselmann

645 4ca96421 Michael Hanselmann
    @rtype: List of L{objects.QueryFieldDefinition}
646 4ca96421 Michael Hanselmann

647 4ca96421 Michael Hanselmann
    """
648 4ca96421 Michael Hanselmann
    return GetAllFields(self._fields)
649 4ca96421 Michael Hanselmann
650 fbc263a9 Michael Hanselmann
  def Query(self, ctx, sort_by_name=True):
651 4ca96421 Michael Hanselmann
    """Execute a query.
652 4ca96421 Michael Hanselmann

653 4ca96421 Michael Hanselmann
    @param ctx: Data container passed to field retrieval functions, must
654 4ca96421 Michael Hanselmann
      support iteration using C{__iter__}
655 fbc263a9 Michael Hanselmann
    @type sort_by_name: boolean
656 fbc263a9 Michael Hanselmann
    @param sort_by_name: Whether to sort by name or keep the input data's
657 fbc263a9 Michael Hanselmann
      ordering
658 4ca96421 Michael Hanselmann

659 4ca96421 Michael Hanselmann
    """
660 fbc263a9 Michael Hanselmann
    sort = (self._name_fn and sort_by_name)
661 fbc263a9 Michael Hanselmann
662 fb0be379 Michael Hanselmann
    result = []
663 fb0be379 Michael Hanselmann
664 fb0be379 Michael Hanselmann
    for idx, item in enumerate(ctx):
665 fb0be379 Michael Hanselmann
      if not (self._filter_fn is None or self._filter_fn(ctx, item)):
666 fb0be379 Michael Hanselmann
        continue
667 4ca96421 Michael Hanselmann
668 fb0be379 Michael Hanselmann
      row = [_ProcessResult(fn(ctx, item)) for (_, _, _, fn) in self._fields]
669 fb0be379 Michael Hanselmann
670 fb0be379 Michael Hanselmann
      # Verify result
671 fb0be379 Michael Hanselmann
      if __debug__:
672 d1c3c3b3 Iustin Pop
        _VerifyResultRow(self._fields, row)
673 4ca96421 Michael Hanselmann
674 fbc263a9 Michael Hanselmann
      if sort:
675 fb0be379 Michael Hanselmann
        (status, name) = _ProcessResult(self._name_fn(ctx, item))
676 fb0be379 Michael Hanselmann
        assert status == constants.RS_NORMAL
677 fb0be379 Michael Hanselmann
        # TODO: Are there cases where we wouldn't want to use NiceSort?
678 fbc263a9 Michael Hanselmann
        result.append((utils.NiceSortKey(name), idx, row))
679 fb0be379 Michael Hanselmann
      else:
680 fbc263a9 Michael Hanselmann
        result.append(row)
681 fb0be379 Michael Hanselmann
682 fbc263a9 Michael Hanselmann
    if not sort:
683 fbc263a9 Michael Hanselmann
      return result
684 fb0be379 Michael Hanselmann
685 fb0be379 Michael Hanselmann
    # TODO: Would "heapq" be more efficient than sorting?
686 fb0be379 Michael Hanselmann
687 fb0be379 Michael Hanselmann
    # Sorting in-place instead of using "sorted()"
688 fb0be379 Michael Hanselmann
    result.sort()
689 fb0be379 Michael Hanselmann
690 fb0be379 Michael Hanselmann
    assert not result or (len(result[0]) == 3 and len(result[-1]) == 3)
691 fb0be379 Michael Hanselmann
692 fb0be379 Michael Hanselmann
    return map(operator.itemgetter(2), result)
693 4ca96421 Michael Hanselmann
694 fbc263a9 Michael Hanselmann
  def OldStyleQuery(self, ctx, sort_by_name=True):
695 4ca96421 Michael Hanselmann
    """Query with "old" query result format.
696 4ca96421 Michael Hanselmann

697 4ca96421 Michael Hanselmann
    See L{Query.Query} for arguments.
698 4ca96421 Michael Hanselmann

699 4ca96421 Michael Hanselmann
    """
700 111bf531 Michael Hanselmann
    unknown = set(fdef.name for (fdef, _, _, _) in self._fields
701 111bf531 Michael Hanselmann
                  if fdef.kind == QFT_UNKNOWN)
702 4ca96421 Michael Hanselmann
    if unknown:
703 4ca96421 Michael Hanselmann
      raise errors.OpPrereqError("Unknown output fields selected: %s" %
704 4ca96421 Michael Hanselmann
                                 (utils.CommaJoin(unknown), ),
705 4ca96421 Michael Hanselmann
                                 errors.ECODE_INVAL)
706 4ca96421 Michael Hanselmann
707 4ca96421 Michael Hanselmann
    return [[value for (_, value) in row]
708 fbc263a9 Michael Hanselmann
            for row in self.Query(ctx, sort_by_name=sort_by_name)]
709 4ca96421 Michael Hanselmann
710 4ca96421 Michael Hanselmann
711 e2d188cc Iustin Pop
def _ProcessResult(value):
712 e2d188cc Iustin Pop
  """Converts result values into externally-visible ones.
713 e2d188cc Iustin Pop

714 e2d188cc Iustin Pop
  """
715 e2d188cc Iustin Pop
  if value is _FS_UNKNOWN:
716 cfb084ae René Nussbaumer
    return (RS_UNKNOWN, None)
717 e2d188cc Iustin Pop
  elif value is _FS_NODATA:
718 cfb084ae René Nussbaumer
    return (RS_NODATA, None)
719 e2d188cc Iustin Pop
  elif value is _FS_UNAVAIL:
720 cfb084ae René Nussbaumer
    return (RS_UNAVAIL, None)
721 e2d188cc Iustin Pop
  elif value is _FS_OFFLINE:
722 cfb084ae René Nussbaumer
    return (RS_OFFLINE, None)
723 e2d188cc Iustin Pop
  else:
724 cfb084ae René Nussbaumer
    return (RS_NORMAL, value)
725 e2d188cc Iustin Pop
726 e2d188cc Iustin Pop
727 4ca96421 Michael Hanselmann
def _VerifyResultRow(fields, row):
728 4ca96421 Michael Hanselmann
  """Verifies the contents of a query result row.
729 4ca96421 Michael Hanselmann

730 4ca96421 Michael Hanselmann
  @type fields: list
731 4ca96421 Michael Hanselmann
  @param fields: Field definitions for result
732 4ca96421 Michael Hanselmann
  @type row: list of tuples
733 4ca96421 Michael Hanselmann
  @param row: Row data
734 4ca96421 Michael Hanselmann

735 4ca96421 Michael Hanselmann
  """
736 d1c3c3b3 Iustin Pop
  assert len(row) == len(fields)
737 d1c3c3b3 Iustin Pop
  errs = []
738 111bf531 Michael Hanselmann
  for ((status, value), (fdef, _, _, _)) in zip(row, fields):
739 cfb084ae René Nussbaumer
    if status == RS_NORMAL:
740 d1c3c3b3 Iustin Pop
      if not _VERIFY_FN[fdef.kind](value):
741 d1c3c3b3 Iustin Pop
        errs.append("normal field %s fails validation (value is %s)" %
742 d1c3c3b3 Iustin Pop
                    (fdef.name, value))
743 d1c3c3b3 Iustin Pop
    elif value is not None:
744 d1c3c3b3 Iustin Pop
      errs.append("abnormal field %s has a non-None value" % fdef.name)
745 d1c3c3b3 Iustin Pop
  assert not errs, ("Failed validation: %s in row %s" %
746 d1c3c3b3 Iustin Pop
                    (utils.CommaJoin(errors), row))
747 4ca96421 Michael Hanselmann
748 4ca96421 Michael Hanselmann
749 d63bd540 Iustin Pop
def _PrepareFieldList(fields, aliases):
750 4ca96421 Michael Hanselmann
  """Prepares field list for use by L{Query}.
751 4ca96421 Michael Hanselmann

752 4ca96421 Michael Hanselmann
  Converts the list to a dictionary and does some verification.
753 4ca96421 Michael Hanselmann

754 d63bd540 Iustin Pop
  @type fields: list of tuples; (L{objects.QueryFieldDefinition}, data
755 d63bd540 Iustin Pop
      kind, retrieval function)
756 d63bd540 Iustin Pop
  @param fields: List of fields, see L{Query.__init__} for a better
757 d63bd540 Iustin Pop
      description
758 d63bd540 Iustin Pop
  @type aliases: list of tuples; (alias, target)
759 d63bd540 Iustin Pop
  @param aliases: list of tuples containing aliases; for each
760 d63bd540 Iustin Pop
      alias/target pair, a duplicate will be created in the field list
761 4ca96421 Michael Hanselmann
  @rtype: dict
762 4ca96421 Michael Hanselmann
  @return: Field dictionary for L{Query}
763 4ca96421 Michael Hanselmann

764 4ca96421 Michael Hanselmann
  """
765 89ce4acc Michael Hanselmann
  if __debug__:
766 89ce4acc Michael Hanselmann
    duplicates = utils.FindDuplicates(fdef.title.lower()
767 111bf531 Michael Hanselmann
                                      for (fdef, _, _, _) in fields)
768 89ce4acc Michael Hanselmann
    assert not duplicates, "Duplicate title(s) found: %r" % duplicates
769 4ca96421 Michael Hanselmann
770 4ca96421 Michael Hanselmann
  result = {}
771 4ca96421 Michael Hanselmann
772 4ca96421 Michael Hanselmann
  for field in fields:
773 111bf531 Michael Hanselmann
    (fdef, _, flags, fn) = field
774 4ca96421 Michael Hanselmann
775 4ca96421 Michael Hanselmann
    assert fdef.name and fdef.title, "Name and title are required"
776 4ca96421 Michael Hanselmann
    assert FIELD_NAME_RE.match(fdef.name)
777 4ca96421 Michael Hanselmann
    assert TITLE_RE.match(fdef.title)
778 79b2ca83 Michael Hanselmann
    assert (DOC_RE.match(fdef.doc) and len(fdef.doc.splitlines()) == 1 and
779 79b2ca83 Michael Hanselmann
            fdef.doc.strip() == fdef.doc), \
780 79b2ca83 Michael Hanselmann
           "Invalid description for field '%s'" % fdef.name
781 4ca96421 Michael Hanselmann
    assert callable(fn)
782 89ce4acc Michael Hanselmann
    assert fdef.name not in result, \
783 89ce4acc Michael Hanselmann
           "Duplicate field name '%s' found" % fdef.name
784 111bf531 Michael Hanselmann
    assert (flags & ~QFF_ALL) == 0, "Unknown flags for field '%s'" % fdef.name
785 4ca96421 Michael Hanselmann
786 4ca96421 Michael Hanselmann
    result[fdef.name] = field
787 4ca96421 Michael Hanselmann
788 d63bd540 Iustin Pop
  for alias, target in aliases:
789 d63bd540 Iustin Pop
    assert alias not in result, "Alias %s overrides an existing field" % alias
790 d63bd540 Iustin Pop
    assert target in result, "Missing target %s for alias %s" % (target, alias)
791 111bf531 Michael Hanselmann
    (fdef, k, flags, fn) = result[target]
792 d63bd540 Iustin Pop
    fdef = fdef.Copy()
793 d63bd540 Iustin Pop
    fdef.name = alias
794 111bf531 Michael Hanselmann
    result[alias] = (fdef, k, flags, fn)
795 d63bd540 Iustin Pop
796 d63bd540 Iustin Pop
  assert len(result) == len(fields) + len(aliases)
797 4ca96421 Michael Hanselmann
  assert compat.all(name == fdef.name
798 111bf531 Michael Hanselmann
                    for (name, (fdef, _, _, _)) in result.items())
799 4ca96421 Michael Hanselmann
800 4ca96421 Michael Hanselmann
  return result
801 4ca96421 Michael Hanselmann
802 4ca96421 Michael Hanselmann
803 fbc263a9 Michael Hanselmann
def GetQueryResponse(query, ctx, sort_by_name=True):
804 b60fcb6f Michael Hanselmann
  """Prepares the response for a query.
805 b60fcb6f Michael Hanselmann

806 b60fcb6f Michael Hanselmann
  @type query: L{Query}
807 b60fcb6f Michael Hanselmann
  @param ctx: Data container, see L{Query.Query}
808 fbc263a9 Michael Hanselmann
  @type sort_by_name: boolean
809 fbc263a9 Michael Hanselmann
  @param sort_by_name: Whether to sort by name or keep the input data's
810 fbc263a9 Michael Hanselmann
    ordering
811 b60fcb6f Michael Hanselmann

812 b60fcb6f Michael Hanselmann
  """
813 fbc263a9 Michael Hanselmann
  return objects.QueryResponse(data=query.Query(ctx, sort_by_name=sort_by_name),
814 b60fcb6f Michael Hanselmann
                               fields=query.GetFields()).ToDict()
815 b60fcb6f Michael Hanselmann
816 b60fcb6f Michael Hanselmann
817 aa29e95f Michael Hanselmann
def QueryFields(fielddefs, selected):
818 aa29e95f Michael Hanselmann
  """Returns list of available fields.
819 aa29e95f Michael Hanselmann

820 aa29e95f Michael Hanselmann
  @type fielddefs: dict
821 aa29e95f Michael Hanselmann
  @param fielddefs: Field definitions
822 aa29e95f Michael Hanselmann
  @type selected: list of strings
823 aa29e95f Michael Hanselmann
  @param selected: List of selected fields
824 aa29e95f Michael Hanselmann
  @return: List of L{objects.QueryFieldDefinition}
825 aa29e95f Michael Hanselmann

826 aa29e95f Michael Hanselmann
  """
827 aa29e95f Michael Hanselmann
  if selected is None:
828 aa29e95f Michael Hanselmann
    # Client requests all fields, sort by name
829 aa29e95f Michael Hanselmann
    fdefs = utils.NiceSort(GetAllFields(fielddefs.values()),
830 aa29e95f Michael Hanselmann
                           key=operator.attrgetter("name"))
831 aa29e95f Michael Hanselmann
  else:
832 aa29e95f Michael Hanselmann
    # Keep order as requested by client
833 aa29e95f Michael Hanselmann
    fdefs = Query(fielddefs, selected).GetFields()
834 aa29e95f Michael Hanselmann
835 aa29e95f Michael Hanselmann
  return objects.QueryFieldsResponse(fields=fdefs).ToDict()
836 aa29e95f Michael Hanselmann
837 aa29e95f Michael Hanselmann
838 79b2ca83 Michael Hanselmann
def _MakeField(name, title, kind, doc):
839 4ca96421 Michael Hanselmann
  """Wrapper for creating L{objects.QueryFieldDefinition} instances.
840 4ca96421 Michael Hanselmann

841 4ca96421 Michael Hanselmann
  @param name: Field name as a regular expression
842 4ca96421 Michael Hanselmann
  @param title: Human-readable title
843 4ca96421 Michael Hanselmann
  @param kind: Field type
844 1ae17369 Michael Hanselmann
  @param doc: Human-readable description
845 4ca96421 Michael Hanselmann

846 4ca96421 Michael Hanselmann
  """
847 1ae17369 Michael Hanselmann
  return objects.QueryFieldDefinition(name=name, title=title, kind=kind,
848 1ae17369 Michael Hanselmann
                                      doc=doc)
849 8235fe04 Michael Hanselmann
850 8235fe04 Michael Hanselmann
851 8235fe04 Michael Hanselmann
def _GetNodeRole(node, master_name):
852 8235fe04 Michael Hanselmann
  """Determine node role.
853 8235fe04 Michael Hanselmann

854 8235fe04 Michael Hanselmann
  @type node: L{objects.Node}
855 8235fe04 Michael Hanselmann
  @param node: Node object
856 8235fe04 Michael Hanselmann
  @type master_name: string
857 8235fe04 Michael Hanselmann
  @param master_name: Master node name
858 8235fe04 Michael Hanselmann

859 8235fe04 Michael Hanselmann
  """
860 8235fe04 Michael Hanselmann
  if node.name == master_name:
861 1e28e3b8 Michael Hanselmann
    return constants.NR_MASTER
862 8235fe04 Michael Hanselmann
  elif node.master_candidate:
863 1e28e3b8 Michael Hanselmann
    return constants.NR_MCANDIDATE
864 8235fe04 Michael Hanselmann
  elif node.drained:
865 1e28e3b8 Michael Hanselmann
    return constants.NR_DRAINED
866 8235fe04 Michael Hanselmann
  elif node.offline:
867 1e28e3b8 Michael Hanselmann
    return constants.NR_OFFLINE
868 8235fe04 Michael Hanselmann
  else:
869 1e28e3b8 Michael Hanselmann
    return constants.NR_REGULAR
870 8235fe04 Michael Hanselmann
871 8235fe04 Michael Hanselmann
872 8235fe04 Michael Hanselmann
def _GetItemAttr(attr):
873 8235fe04 Michael Hanselmann
  """Returns a field function to return an attribute of the item.
874 8235fe04 Michael Hanselmann

875 8235fe04 Michael Hanselmann
  @param attr: Attribute name
876 8235fe04 Michael Hanselmann

877 8235fe04 Michael Hanselmann
  """
878 8235fe04 Michael Hanselmann
  getter = operator.attrgetter(attr)
879 e2d188cc Iustin Pop
  return lambda _, item: getter(item)
880 8235fe04 Michael Hanselmann
881 8235fe04 Michael Hanselmann
882 145bea54 Michael Hanselmann
def _GetItemTimestamp(getter):
883 145bea54 Michael Hanselmann
  """Returns function for getting timestamp of item.
884 145bea54 Michael Hanselmann

885 145bea54 Michael Hanselmann
  @type getter: callable
886 145bea54 Michael Hanselmann
  @param getter: Function to retrieve timestamp attribute
887 145bea54 Michael Hanselmann

888 145bea54 Michael Hanselmann
  """
889 145bea54 Michael Hanselmann
  def fn(_, item):
890 145bea54 Michael Hanselmann
    """Returns a timestamp of item.
891 145bea54 Michael Hanselmann

892 145bea54 Michael Hanselmann
    """
893 145bea54 Michael Hanselmann
    timestamp = getter(item)
894 145bea54 Michael Hanselmann
    if timestamp is None:
895 145bea54 Michael Hanselmann
      # Old configs might not have all timestamps
896 e2d188cc Iustin Pop
      return _FS_UNAVAIL
897 145bea54 Michael Hanselmann
    else:
898 e2d188cc Iustin Pop
      return timestamp
899 145bea54 Michael Hanselmann
900 145bea54 Michael Hanselmann
  return fn
901 145bea54 Michael Hanselmann
902 145bea54 Michael Hanselmann
903 145bea54 Michael Hanselmann
def _GetItemTimestampFields(datatype):
904 145bea54 Michael Hanselmann
  """Returns common timestamp fields.
905 145bea54 Michael Hanselmann

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

908 145bea54 Michael Hanselmann
  """
909 145bea54 Michael Hanselmann
  return [
910 79b2ca83 Michael Hanselmann
    (_MakeField("ctime", "CTime", QFT_TIMESTAMP, "Creation timestamp"),
911 111bf531 Michael Hanselmann
     datatype, 0, _GetItemTimestamp(operator.attrgetter("ctime"))),
912 79b2ca83 Michael Hanselmann
    (_MakeField("mtime", "MTime", QFT_TIMESTAMP, "Modification timestamp"),
913 111bf531 Michael Hanselmann
     datatype, 0, _GetItemTimestamp(operator.attrgetter("mtime"))),
914 145bea54 Michael Hanselmann
    ]
915 145bea54 Michael Hanselmann
916 145bea54 Michael Hanselmann
917 8235fe04 Michael Hanselmann
class NodeQueryData:
918 8235fe04 Michael Hanselmann
  """Data container for node data queries.
919 8235fe04 Michael Hanselmann

920 8235fe04 Michael Hanselmann
  """
921 8235fe04 Michael Hanselmann
  def __init__(self, nodes, live_data, master_name, node_to_primary,
922 8572f1fe René Nussbaumer
               node_to_secondary, groups, oob_support, cluster):
923 8235fe04 Michael Hanselmann
    """Initializes this class.
924 8235fe04 Michael Hanselmann

925 8235fe04 Michael Hanselmann
    """
926 8235fe04 Michael Hanselmann
    self.nodes = nodes
927 8235fe04 Michael Hanselmann
    self.live_data = live_data
928 8235fe04 Michael Hanselmann
    self.master_name = master_name
929 8235fe04 Michael Hanselmann
    self.node_to_primary = node_to_primary
930 8235fe04 Michael Hanselmann
    self.node_to_secondary = node_to_secondary
931 8235fe04 Michael Hanselmann
    self.groups = groups
932 52b5d286 René Nussbaumer
    self.oob_support = oob_support
933 8572f1fe René Nussbaumer
    self.cluster = cluster
934 8235fe04 Michael Hanselmann
935 8235fe04 Michael Hanselmann
    # Used for individual rows
936 8235fe04 Michael Hanselmann
    self.curlive_data = None
937 8235fe04 Michael Hanselmann
938 8235fe04 Michael Hanselmann
  def __iter__(self):
939 8235fe04 Michael Hanselmann
    """Iterate over all nodes.
940 8235fe04 Michael Hanselmann

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

944 8235fe04 Michael Hanselmann
    """
945 8235fe04 Michael Hanselmann
    for node in self.nodes:
946 8235fe04 Michael Hanselmann
      if self.live_data:
947 8235fe04 Michael Hanselmann
        self.curlive_data = self.live_data.get(node.name, None)
948 8235fe04 Michael Hanselmann
      else:
949 8235fe04 Michael Hanselmann
        self.curlive_data = None
950 8235fe04 Michael Hanselmann
      yield node
951 8235fe04 Michael Hanselmann
952 8235fe04 Michael Hanselmann
953 8235fe04 Michael Hanselmann
#: Fields that are direct attributes of an L{objects.Node} object
954 8235fe04 Michael Hanselmann
_NODE_SIMPLE_FIELDS = {
955 111bf531 Michael Hanselmann
  "drained": ("Drained", QFT_BOOL, 0, "Whether node is drained"),
956 111bf531 Michael Hanselmann
  "master_candidate": ("MasterC", QFT_BOOL, 0,
957 79b2ca83 Michael Hanselmann
                       "Whether node is a master candidate"),
958 111bf531 Michael Hanselmann
  "master_capable": ("MasterCapable", QFT_BOOL, 0,
959 79b2ca83 Michael Hanselmann
                     "Whether node can become a master candidate"),
960 111bf531 Michael Hanselmann
  "name": ("Node", QFT_TEXT, QFF_HOSTNAME, "Node name"),
961 111bf531 Michael Hanselmann
  "offline": ("Offline", QFT_BOOL, 0, "Whether node is marked offline"),
962 111bf531 Michael Hanselmann
  "serial_no": ("SerialNo", QFT_NUMBER, 0, _SERIAL_NO_DOC % "Node"),
963 111bf531 Michael Hanselmann
  "uuid": ("UUID", QFT_TEXT, 0, "Node UUID"),
964 111bf531 Michael Hanselmann
  "vm_capable": ("VMCapable", QFT_BOOL, 0, "Whether node can host instances"),
965 8235fe04 Michael Hanselmann
  }
966 8235fe04 Michael Hanselmann
967 8235fe04 Michael Hanselmann
968 8235fe04 Michael Hanselmann
#: Fields requiring talking to the node
969 effab4ca Iustin Pop
# Note that none of these are available for non-vm_capable nodes
970 8235fe04 Michael Hanselmann
_NODE_LIVE_FIELDS = {
971 79b2ca83 Michael Hanselmann
  "bootid": ("BootID", QFT_TEXT, "bootid",
972 79b2ca83 Michael Hanselmann
             "Random UUID renewed for each system reboot, can be used"
973 79b2ca83 Michael Hanselmann
             " for detecting reboots by tracking changes"),
974 79b2ca83 Michael Hanselmann
  "cnodes": ("CNodes", QFT_NUMBER, "cpu_nodes",
975 79b2ca83 Michael Hanselmann
             "Number of NUMA domains on node (if exported by hypervisor)"),
976 79b2ca83 Michael Hanselmann
  "csockets": ("CSockets", QFT_NUMBER, "cpu_sockets",
977 79b2ca83 Michael Hanselmann
               "Number of physical CPU sockets (if exported by hypervisor)"),
978 79b2ca83 Michael Hanselmann
  "ctotal": ("CTotal", QFT_NUMBER, "cpu_total", "Number of logical processors"),
979 79b2ca83 Michael Hanselmann
  "dfree": ("DFree", QFT_UNIT, "vg_free",
980 79b2ca83 Michael Hanselmann
            "Available disk space in volume group"),
981 79b2ca83 Michael Hanselmann
  "dtotal": ("DTotal", QFT_UNIT, "vg_size",
982 79b2ca83 Michael Hanselmann
             "Total disk space in volume group used for instance disk"
983 79b2ca83 Michael Hanselmann
             " allocation"),
984 79b2ca83 Michael Hanselmann
  "mfree": ("MFree", QFT_UNIT, "memory_free",
985 79b2ca83 Michael Hanselmann
            "Memory available for instance allocations"),
986 79b2ca83 Michael Hanselmann
  "mnode": ("MNode", QFT_UNIT, "memory_dom0",
987 79b2ca83 Michael Hanselmann
            "Amount of memory used by node (dom0 for Xen)"),
988 79b2ca83 Michael Hanselmann
  "mtotal": ("MTotal", QFT_UNIT, "memory_total",
989 79b2ca83 Michael Hanselmann
             "Total amount of memory of physical machine"),
990 8235fe04 Michael Hanselmann
  }
991 8235fe04 Michael Hanselmann
992 8235fe04 Michael Hanselmann
993 8572f1fe René Nussbaumer
def _GetGroup(cb):
994 8572f1fe René Nussbaumer
  """Build function for calling another function with an node group.
995 8572f1fe René Nussbaumer

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

998 8572f1fe René Nussbaumer
  """
999 8572f1fe René Nussbaumer
  def fn(ctx, node):
1000 8572f1fe René Nussbaumer
    """Get group data for a node.
1001 8572f1fe René Nussbaumer

1002 8572f1fe René Nussbaumer
    @type ctx: L{NodeQueryData}
1003 8572f1fe René Nussbaumer
    @type inst: L{objects.Node}
1004 8572f1fe René Nussbaumer
    @param inst: Node object
1005 8572f1fe René Nussbaumer

1006 8572f1fe René Nussbaumer
    """
1007 8572f1fe René Nussbaumer
    ng = ctx.groups.get(node.group, None)
1008 8572f1fe René Nussbaumer
    if ng is None:
1009 8572f1fe René Nussbaumer
      # Nodes always have a group, or the configuration is corrupt
1010 e2d188cc Iustin Pop
      return _FS_UNAVAIL
1011 8572f1fe René Nussbaumer
1012 8572f1fe René Nussbaumer
    return cb(ctx, node, ng)
1013 8572f1fe René Nussbaumer
1014 8572f1fe René Nussbaumer
  return fn
1015 8572f1fe René Nussbaumer
1016 8572f1fe René Nussbaumer
1017 8572f1fe René Nussbaumer
def _GetNodeGroup(ctx, node, ng): # pylint: disable-msg=W0613
1018 8235fe04 Michael Hanselmann
  """Returns the name of a node's group.
1019 8235fe04 Michael Hanselmann

1020 8235fe04 Michael Hanselmann
  @type ctx: L{NodeQueryData}
1021 8235fe04 Michael Hanselmann
  @type node: L{objects.Node}
1022 8235fe04 Michael Hanselmann
  @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 8235fe04 Michael Hanselmann

1026 8235fe04 Michael Hanselmann
  """
1027 e2d188cc Iustin Pop
  return ng.name
1028 8235fe04 Michael Hanselmann
1029 8235fe04 Michael Hanselmann
1030 52b5d286 René Nussbaumer
def _GetNodePower(ctx, node):
1031 52b5d286 René Nussbaumer
  """Returns the node powered state
1032 52b5d286 René Nussbaumer

1033 52b5d286 René Nussbaumer
  @type ctx: L{NodeQueryData}
1034 52b5d286 René Nussbaumer
  @type node: L{objects.Node}
1035 52b5d286 René Nussbaumer
  @param node: Node object
1036 52b5d286 René Nussbaumer

1037 52b5d286 René Nussbaumer
  """
1038 52b5d286 René Nussbaumer
  if ctx.oob_support[node.name]:
1039 e2d188cc Iustin Pop
    return node.powered
1040 52b5d286 René Nussbaumer
1041 e2d188cc Iustin Pop
  return _FS_UNAVAIL
1042 52b5d286 René Nussbaumer
1043 52b5d286 René Nussbaumer
1044 8572f1fe René Nussbaumer
def _GetNdParams(ctx, node, ng):
1045 8572f1fe René Nussbaumer
  """Returns the ndparams for this node.
1046 8572f1fe René Nussbaumer

1047 8572f1fe René Nussbaumer
  @type ctx: L{NodeQueryData}
1048 8572f1fe René Nussbaumer
  @type node: L{objects.Node}
1049 8572f1fe René Nussbaumer
  @param node: Node object
1050 8572f1fe René Nussbaumer
  @type ng: L{objects.NodeGroup}
1051 8572f1fe René Nussbaumer
  @param ng: The node group this node belongs to
1052 8572f1fe René Nussbaumer

1053 8572f1fe René Nussbaumer
  """
1054 e2d188cc Iustin Pop
  return ctx.cluster.SimpleFillND(ng.FillND(node))
1055 8572f1fe René Nussbaumer
1056 8572f1fe René Nussbaumer
1057 a6070ef7 Michael Hanselmann
def _GetLiveNodeField(field, kind, ctx, node):
1058 8235fe04 Michael Hanselmann
  """Gets the value of a "live" field from L{NodeQueryData}.
1059 8235fe04 Michael Hanselmann

1060 8235fe04 Michael Hanselmann
  @param field: Live field name
1061 8235fe04 Michael Hanselmann
  @param kind: Data kind, one of L{constants.QFT_ALL}
1062 8235fe04 Michael Hanselmann
  @type ctx: L{NodeQueryData}
1063 a6070ef7 Michael Hanselmann
  @type node: L{objects.Node}
1064 a6070ef7 Michael Hanselmann
  @param node: Node object
1065 8235fe04 Michael Hanselmann

1066 8235fe04 Michael Hanselmann
  """
1067 a6070ef7 Michael Hanselmann
  if node.offline:
1068 e2d188cc Iustin Pop
    return _FS_OFFLINE
1069 a6070ef7 Michael Hanselmann
1070 effab4ca Iustin Pop
  if not node.vm_capable:
1071 effab4ca Iustin Pop
    return _FS_UNAVAIL
1072 effab4ca Iustin Pop
1073 8235fe04 Michael Hanselmann
  if not ctx.curlive_data:
1074 e2d188cc Iustin Pop
    return _FS_NODATA
1075 8235fe04 Michael Hanselmann
1076 8235fe04 Michael Hanselmann
  try:
1077 8235fe04 Michael Hanselmann
    value = ctx.curlive_data[field]
1078 8235fe04 Michael Hanselmann
  except KeyError:
1079 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1080 8235fe04 Michael Hanselmann
1081 82599b3e Iustin Pop
  if kind == QFT_TEXT:
1082 e2d188cc Iustin Pop
    return value
1083 8235fe04 Michael Hanselmann
1084 82599b3e Iustin Pop
  assert kind in (QFT_NUMBER, QFT_UNIT)
1085 8235fe04 Michael Hanselmann
1086 8235fe04 Michael Hanselmann
  # Try to convert into number
1087 8235fe04 Michael Hanselmann
  try:
1088 e2d188cc Iustin Pop
    return int(value)
1089 8235fe04 Michael Hanselmann
  except (ValueError, TypeError):
1090 8235fe04 Michael Hanselmann
    logging.exception("Failed to convert node field '%s' (value %r) to int",
1091 8235fe04 Michael Hanselmann
                      value, field)
1092 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1093 8235fe04 Michael Hanselmann
1094 8235fe04 Michael Hanselmann
1095 8235fe04 Michael Hanselmann
def _BuildNodeFields():
1096 8235fe04 Michael Hanselmann
  """Builds list of fields for node queries.
1097 8235fe04 Michael Hanselmann

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

1177 1c8addc6 Michael Hanselmann
  """
1178 1c8addc6 Michael Hanselmann
  def __init__(self, instances, cluster, disk_usage, offline_nodes, bad_nodes,
1179 5d28cb6f Michael Hanselmann
               live_data, wrongnode_inst, console):
1180 1c8addc6 Michael Hanselmann
    """Initializes this class.
1181 1c8addc6 Michael Hanselmann

1182 1c8addc6 Michael Hanselmann
    @param instances: List of instance objects
1183 1c8addc6 Michael Hanselmann
    @param cluster: Cluster object
1184 1c8addc6 Michael Hanselmann
    @type disk_usage: dict; instance name as key
1185 1c8addc6 Michael Hanselmann
    @param disk_usage: Per-instance disk usage
1186 1c8addc6 Michael Hanselmann
    @type offline_nodes: list of strings
1187 1c8addc6 Michael Hanselmann
    @param offline_nodes: List of offline nodes
1188 1c8addc6 Michael Hanselmann
    @type bad_nodes: list of strings
1189 1c8addc6 Michael Hanselmann
    @param bad_nodes: List of faulty nodes
1190 1c8addc6 Michael Hanselmann
    @type live_data: dict; instance name as key
1191 1c8addc6 Michael Hanselmann
    @param live_data: Per-instance live data
1192 e431074f René Nussbaumer
    @type wrongnode_inst: set
1193 e431074f René Nussbaumer
    @param wrongnode_inst: Set of instances running on wrong node(s)
1194 5d28cb6f Michael Hanselmann
    @type console: dict; instance name as key
1195 5d28cb6f Michael Hanselmann
    @param console: Per-instance console information
1196 1c8addc6 Michael Hanselmann

1197 1c8addc6 Michael Hanselmann
    """
1198 1c8addc6 Michael Hanselmann
    assert len(set(bad_nodes) & set(offline_nodes)) == len(offline_nodes), \
1199 1c8addc6 Michael Hanselmann
           "Offline nodes not included in bad nodes"
1200 1c8addc6 Michael Hanselmann
    assert not (set(live_data.keys()) & set(bad_nodes)), \
1201 1c8addc6 Michael Hanselmann
           "Found live data for bad or offline nodes"
1202 1c8addc6 Michael Hanselmann
1203 1c8addc6 Michael Hanselmann
    self.instances = instances
1204 1c8addc6 Michael Hanselmann
    self.cluster = cluster
1205 1c8addc6 Michael Hanselmann
    self.disk_usage = disk_usage
1206 1c8addc6 Michael Hanselmann
    self.offline_nodes = offline_nodes
1207 1c8addc6 Michael Hanselmann
    self.bad_nodes = bad_nodes
1208 1c8addc6 Michael Hanselmann
    self.live_data = live_data
1209 e431074f René Nussbaumer
    self.wrongnode_inst = wrongnode_inst
1210 5d28cb6f Michael Hanselmann
    self.console = console
1211 1c8addc6 Michael Hanselmann
1212 1c8addc6 Michael Hanselmann
    # Used for individual rows
1213 1c8addc6 Michael Hanselmann
    self.inst_hvparams = None
1214 1c8addc6 Michael Hanselmann
    self.inst_beparams = None
1215 1c8addc6 Michael Hanselmann
    self.inst_nicparams = None
1216 1c8addc6 Michael Hanselmann
1217 1c8addc6 Michael Hanselmann
  def __iter__(self):
1218 1c8addc6 Michael Hanselmann
    """Iterate over all instances.
1219 1c8addc6 Michael Hanselmann

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

1223 1c8addc6 Michael Hanselmann
    """
1224 1c8addc6 Michael Hanselmann
    for inst in self.instances:
1225 1c8addc6 Michael Hanselmann
      self.inst_hvparams = self.cluster.FillHV(inst, skip_globals=True)
1226 1c8addc6 Michael Hanselmann
      self.inst_beparams = self.cluster.FillBE(inst)
1227 1c8addc6 Michael Hanselmann
      self.inst_nicparams = [self.cluster.SimpleFillNIC(nic.nicparams)
1228 1c8addc6 Michael Hanselmann
                             for nic in inst.nics]
1229 1c8addc6 Michael Hanselmann
1230 1c8addc6 Michael Hanselmann
      yield inst
1231 1c8addc6 Michael Hanselmann
1232 1c8addc6 Michael Hanselmann
1233 1c8addc6 Michael Hanselmann
def _GetInstOperState(ctx, inst):
1234 1c8addc6 Michael Hanselmann
  """Get instance's operational status.
1235 1c8addc6 Michael Hanselmann

1236 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1237 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1238 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1239 1c8addc6 Michael Hanselmann

1240 1c8addc6 Michael Hanselmann
  """
1241 cfb084ae René Nussbaumer
  # Can't use RS_OFFLINE here as it would describe the instance to
1242 e2d188cc Iustin Pop
  # be offline when we actually don't know due to missing data
1243 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.bad_nodes:
1244 e2d188cc Iustin Pop
    return _FS_NODATA
1245 1c8addc6 Michael Hanselmann
  else:
1246 e2d188cc Iustin Pop
    return bool(ctx.live_data.get(inst.name))
1247 1c8addc6 Michael Hanselmann
1248 1c8addc6 Michael Hanselmann
1249 1c8addc6 Michael Hanselmann
def _GetInstLiveData(name):
1250 1c8addc6 Michael Hanselmann
  """Build function for retrieving live data.
1251 1c8addc6 Michael Hanselmann

1252 1c8addc6 Michael Hanselmann
  @type name: string
1253 1c8addc6 Michael Hanselmann
  @param name: Live data field name
1254 1c8addc6 Michael Hanselmann

1255 1c8addc6 Michael Hanselmann
  """
1256 1c8addc6 Michael Hanselmann
  def fn(ctx, inst):
1257 1c8addc6 Michael Hanselmann
    """Get live data for an instance.
1258 1c8addc6 Michael Hanselmann

1259 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1260 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1261 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1262 1c8addc6 Michael Hanselmann

1263 1c8addc6 Michael Hanselmann
    """
1264 1c8addc6 Michael Hanselmann
    if (inst.primary_node in ctx.bad_nodes or
1265 1c8addc6 Michael Hanselmann
        inst.primary_node in ctx.offline_nodes):
1266 cfb084ae René Nussbaumer
      # Can't use RS_OFFLINE here as it would describe the instance to be
1267 a6070ef7 Michael Hanselmann
      # offline when we actually don't know due to missing data
1268 e2d188cc Iustin Pop
      return _FS_NODATA
1269 1c8addc6 Michael Hanselmann
1270 1c8addc6 Michael Hanselmann
    if inst.name in ctx.live_data:
1271 1c8addc6 Michael Hanselmann
      data = ctx.live_data[inst.name]
1272 1c8addc6 Michael Hanselmann
      if name in data:
1273 e2d188cc Iustin Pop
        return data[name]
1274 1c8addc6 Michael Hanselmann
1275 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1276 1c8addc6 Michael Hanselmann
1277 1c8addc6 Michael Hanselmann
  return fn
1278 1c8addc6 Michael Hanselmann
1279 1c8addc6 Michael Hanselmann
1280 1c8addc6 Michael Hanselmann
def _GetInstStatus(ctx, inst):
1281 1c8addc6 Michael Hanselmann
  """Get instance status.
1282 1c8addc6 Michael Hanselmann

1283 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1284 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1285 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1286 1c8addc6 Michael Hanselmann

1287 1c8addc6 Michael Hanselmann
  """
1288 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.offline_nodes:
1289 61a980a9 Michael Hanselmann
    return constants.INSTST_NODEOFFLINE
1290 1c8addc6 Michael Hanselmann
1291 1c8addc6 Michael Hanselmann
  if inst.primary_node in ctx.bad_nodes:
1292 61a980a9 Michael Hanselmann
    return constants.INSTST_NODEDOWN
1293 1c8addc6 Michael Hanselmann
1294 1c8addc6 Michael Hanselmann
  if bool(ctx.live_data.get(inst.name)):
1295 e431074f René Nussbaumer
    if inst.name in ctx.wrongnode_inst:
1296 61a980a9 Michael Hanselmann
      return constants.INSTST_WRONGNODE
1297 e431074f René Nussbaumer
    elif inst.admin_up:
1298 61a980a9 Michael Hanselmann
      return constants.INSTST_RUNNING
1299 1c8addc6 Michael Hanselmann
    else:
1300 61a980a9 Michael Hanselmann
      return constants.INSTST_ERRORUP
1301 1c8addc6 Michael Hanselmann
1302 1c8addc6 Michael Hanselmann
  if inst.admin_up:
1303 61a980a9 Michael Hanselmann
    return constants.INSTST_ERRORDOWN
1304 1c8addc6 Michael Hanselmann
1305 61a980a9 Michael Hanselmann
  return constants.INSTST_ADMINDOWN
1306 1c8addc6 Michael Hanselmann
1307 1c8addc6 Michael Hanselmann
1308 1c8addc6 Michael Hanselmann
def _GetInstDiskSize(index):
1309 1c8addc6 Michael Hanselmann
  """Build function for retrieving disk size.
1310 1c8addc6 Michael Hanselmann

1311 1c8addc6 Michael Hanselmann
  @type index: int
1312 1c8addc6 Michael Hanselmann
  @param index: Disk index
1313 1c8addc6 Michael Hanselmann

1314 1c8addc6 Michael Hanselmann
  """
1315 1c8addc6 Michael Hanselmann
  def fn(_, inst):
1316 1c8addc6 Michael Hanselmann
    """Get size of a disk.
1317 1c8addc6 Michael Hanselmann

1318 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1319 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1320 1c8addc6 Michael Hanselmann

1321 1c8addc6 Michael Hanselmann
    """
1322 1c8addc6 Michael Hanselmann
    try:
1323 e2d188cc Iustin Pop
      return inst.disks[index].size
1324 1c8addc6 Michael Hanselmann
    except IndexError:
1325 e2d188cc Iustin Pop
      return _FS_UNAVAIL
1326 1c8addc6 Michael Hanselmann
1327 1c8addc6 Michael Hanselmann
  return fn
1328 1c8addc6 Michael Hanselmann
1329 1c8addc6 Michael Hanselmann
1330 1c8addc6 Michael Hanselmann
def _GetInstNic(index, cb):
1331 1c8addc6 Michael Hanselmann
  """Build function for calling another function with an instance NIC.
1332 1c8addc6 Michael Hanselmann

1333 1c8addc6 Michael Hanselmann
  @type index: int
1334 1c8addc6 Michael Hanselmann
  @param index: NIC index
1335 1c8addc6 Michael Hanselmann
  @type cb: callable
1336 1c8addc6 Michael Hanselmann
  @param cb: Callback
1337 1c8addc6 Michael Hanselmann

1338 1c8addc6 Michael Hanselmann
  """
1339 1c8addc6 Michael Hanselmann
  def fn(ctx, inst):
1340 1c8addc6 Michael Hanselmann
    """Call helper function with instance NIC.
1341 1c8addc6 Michael Hanselmann

1342 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1343 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1344 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1345 1c8addc6 Michael Hanselmann

1346 1c8addc6 Michael Hanselmann
    """
1347 1c8addc6 Michael Hanselmann
    try:
1348 1c8addc6 Michael Hanselmann
      nic = inst.nics[index]
1349 1c8addc6 Michael Hanselmann
    except IndexError:
1350 e2d188cc Iustin Pop
      return _FS_UNAVAIL
1351 1c8addc6 Michael Hanselmann
1352 1c8addc6 Michael Hanselmann
    return cb(ctx, index, nic)
1353 1c8addc6 Michael Hanselmann
1354 1c8addc6 Michael Hanselmann
  return fn
1355 1c8addc6 Michael Hanselmann
1356 1c8addc6 Michael Hanselmann
1357 1c8addc6 Michael Hanselmann
def _GetInstNicIp(ctx, _, nic): # pylint: disable-msg=W0613
1358 1c8addc6 Michael Hanselmann
  """Get a NIC's IP address.
1359 1c8addc6 Michael Hanselmann

1360 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1361 1c8addc6 Michael Hanselmann
  @type nic: L{objects.NIC}
1362 1c8addc6 Michael Hanselmann
  @param nic: NIC object
1363 1c8addc6 Michael Hanselmann

1364 1c8addc6 Michael Hanselmann
  """
1365 1c8addc6 Michael Hanselmann
  if nic.ip is None:
1366 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1367 1c8addc6 Michael Hanselmann
  else:
1368 e2d188cc Iustin Pop
    return nic.ip
1369 1c8addc6 Michael Hanselmann
1370 1c8addc6 Michael Hanselmann
1371 1c8addc6 Michael Hanselmann
def _GetInstNicBridge(ctx, index, _):
1372 1c8addc6 Michael Hanselmann
  """Get a NIC's bridge.
1373 1c8addc6 Michael Hanselmann

1374 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1375 1c8addc6 Michael Hanselmann
  @type index: int
1376 1c8addc6 Michael Hanselmann
  @param index: NIC index
1377 1c8addc6 Michael Hanselmann

1378 1c8addc6 Michael Hanselmann
  """
1379 1c8addc6 Michael Hanselmann
  assert len(ctx.inst_nicparams) >= index
1380 1c8addc6 Michael Hanselmann
1381 1c8addc6 Michael Hanselmann
  nicparams = ctx.inst_nicparams[index]
1382 1c8addc6 Michael Hanselmann
1383 1c8addc6 Michael Hanselmann
  if nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1384 e2d188cc Iustin Pop
    return nicparams[constants.NIC_LINK]
1385 1c8addc6 Michael Hanselmann
  else:
1386 e2d188cc Iustin Pop
    return _FS_UNAVAIL
1387 1c8addc6 Michael Hanselmann
1388 1c8addc6 Michael Hanselmann
1389 1c8addc6 Michael Hanselmann
def _GetInstAllNicBridges(ctx, inst):
1390 1c8addc6 Michael Hanselmann
  """Get all network bridges for an instance.
1391 1c8addc6 Michael Hanselmann

1392 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1393 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1394 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1395 1c8addc6 Michael Hanselmann

1396 1c8addc6 Michael Hanselmann
  """
1397 1c8addc6 Michael Hanselmann
  assert len(ctx.inst_nicparams) == len(inst.nics)
1398 1c8addc6 Michael Hanselmann
1399 1c8addc6 Michael Hanselmann
  result = []
1400 1c8addc6 Michael Hanselmann
1401 1c8addc6 Michael Hanselmann
  for nicp in ctx.inst_nicparams:
1402 1c8addc6 Michael Hanselmann
    if nicp[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED:
1403 1c8addc6 Michael Hanselmann
      result.append(nicp[constants.NIC_LINK])
1404 1c8addc6 Michael Hanselmann
    else:
1405 1c8addc6 Michael Hanselmann
      result.append(None)
1406 1c8addc6 Michael Hanselmann
1407 1c8addc6 Michael Hanselmann
  assert len(result) == len(inst.nics)
1408 1c8addc6 Michael Hanselmann
1409 e2d188cc Iustin Pop
  return result
1410 1c8addc6 Michael Hanselmann
1411 1c8addc6 Michael Hanselmann
1412 1c8addc6 Michael Hanselmann
def _GetInstNicParam(name):
1413 1c8addc6 Michael Hanselmann
  """Build function for retrieving a NIC parameter.
1414 1c8addc6 Michael Hanselmann

1415 1c8addc6 Michael Hanselmann
  @type name: string
1416 1c8addc6 Michael Hanselmann
  @param name: Parameter name
1417 1c8addc6 Michael Hanselmann

1418 1c8addc6 Michael Hanselmann
  """
1419 1c8addc6 Michael Hanselmann
  def fn(ctx, index, _):
1420 1c8addc6 Michael Hanselmann
    """Get a NIC's bridge.
1421 1c8addc6 Michael Hanselmann

1422 1c8addc6 Michael Hanselmann
    @type ctx: L{InstanceQueryData}
1423 1c8addc6 Michael Hanselmann
    @type inst: L{objects.Instance}
1424 1c8addc6 Michael Hanselmann
    @param inst: Instance object
1425 1c8addc6 Michael Hanselmann
    @type nic: L{objects.NIC}
1426 1c8addc6 Michael Hanselmann
    @param nic: NIC object
1427 1c8addc6 Michael Hanselmann

1428 1c8addc6 Michael Hanselmann
    """
1429 1c8addc6 Michael Hanselmann
    assert len(ctx.inst_nicparams) >= index
1430 e2d188cc Iustin Pop
    return ctx.inst_nicparams[index][name]
1431 1c8addc6 Michael Hanselmann
1432 1c8addc6 Michael Hanselmann
  return fn
1433 1c8addc6 Michael Hanselmann
1434 1c8addc6 Michael Hanselmann
1435 1c8addc6 Michael Hanselmann
def _GetInstanceNetworkFields():
1436 1c8addc6 Michael Hanselmann
  """Get instance fields involving network interfaces.
1437 1c8addc6 Michael Hanselmann

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

1441 1c8addc6 Michael Hanselmann
  """
1442 e2d188cc Iustin Pop
  nic_mac_fn = lambda ctx, _, nic: nic.mac
1443 1c8addc6 Michael Hanselmann
  nic_mode_fn = _GetInstNicParam(constants.NIC_MODE)
1444 1c8addc6 Michael Hanselmann
  nic_link_fn = _GetInstNicParam(constants.NIC_LINK)
1445 1c8addc6 Michael Hanselmann
1446 1c8addc6 Michael Hanselmann
  fields = [
1447 1c8addc6 Michael Hanselmann
    # All NICs
1448 79b2ca83 Michael Hanselmann
    (_MakeField("nic.count", "NICs", QFT_NUMBER,
1449 79b2ca83 Michael Hanselmann
                "Number of network interfaces"),
1450 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: len(inst.nics)),
1451 79b2ca83 Michael Hanselmann
    (_MakeField("nic.macs", "NIC_MACs", QFT_OTHER,
1452 79b2ca83 Michael Hanselmann
                "List containing each network interface's MAC address"),
1453 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [nic.mac for nic in inst.nics]),
1454 79b2ca83 Michael Hanselmann
    (_MakeField("nic.ips", "NIC_IPs", QFT_OTHER,
1455 79b2ca83 Michael Hanselmann
                "List containing each network interface's IP address"),
1456 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [nic.ip for nic in inst.nics]),
1457 79b2ca83 Michael Hanselmann
    (_MakeField("nic.modes", "NIC_modes", QFT_OTHER,
1458 111bf531 Michael Hanselmann
                "List containing each network interface's mode"), IQ_CONFIG, 0,
1459 e2d188cc Iustin Pop
     lambda ctx, inst: [nicp[constants.NIC_MODE]
1460 e2d188cc Iustin Pop
                        for nicp in ctx.inst_nicparams]),
1461 79b2ca83 Michael Hanselmann
    (_MakeField("nic.links", "NIC_links", QFT_OTHER,
1462 111bf531 Michael Hanselmann
                "List containing each network interface's link"), IQ_CONFIG, 0,
1463 e2d188cc Iustin Pop
     lambda ctx, inst: [nicp[constants.NIC_LINK]
1464 e2d188cc Iustin Pop
                        for nicp in ctx.inst_nicparams]),
1465 79b2ca83 Michael Hanselmann
    (_MakeField("nic.bridges", "NIC_bridges", QFT_OTHER,
1466 111bf531 Michael Hanselmann
                "List containing each network interface's bridge"),
1467 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstAllNicBridges),
1468 1c8addc6 Michael Hanselmann
    ]
1469 1c8addc6 Michael Hanselmann
1470 1c8addc6 Michael Hanselmann
  # NICs by number
1471 1c8addc6 Michael Hanselmann
  for i in range(constants.MAX_NICS):
1472 79b2ca83 Michael Hanselmann
    numtext = utils.FormatOrdinal(i + 1)
1473 1c8addc6 Michael Hanselmann
    fields.extend([
1474 79b2ca83 Michael Hanselmann
      (_MakeField("nic.ip/%s" % i, "NicIP/%s" % i, QFT_TEXT,
1475 79b2ca83 Michael Hanselmann
                  "IP address of %s network interface" % numtext),
1476 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicIp)),
1477 79b2ca83 Michael Hanselmann
      (_MakeField("nic.mac/%s" % i, "NicMAC/%s" % i, QFT_TEXT,
1478 79b2ca83 Michael Hanselmann
                  "MAC address of %s network interface" % numtext),
1479 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_mac_fn)),
1480 79b2ca83 Michael Hanselmann
      (_MakeField("nic.mode/%s" % i, "NicMode/%s" % i, QFT_TEXT,
1481 79b2ca83 Michael Hanselmann
                  "Mode of %s network interface" % numtext),
1482 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_mode_fn)),
1483 79b2ca83 Michael Hanselmann
      (_MakeField("nic.link/%s" % i, "NicLink/%s" % i, QFT_TEXT,
1484 79b2ca83 Michael Hanselmann
                  "Link of %s network interface" % numtext),
1485 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, nic_link_fn)),
1486 79b2ca83 Michael Hanselmann
      (_MakeField("nic.bridge/%s" % i, "NicBridge/%s" % i, QFT_TEXT,
1487 79b2ca83 Michael Hanselmann
                  "Bridge of %s network interface" % numtext),
1488 111bf531 Michael Hanselmann
       IQ_CONFIG, 0, _GetInstNic(i, _GetInstNicBridge)),
1489 1c8addc6 Michael Hanselmann
      ])
1490 1c8addc6 Michael Hanselmann
1491 4cc4d1fa Michael Hanselmann
  aliases = [
1492 4cc4d1fa Michael Hanselmann
    # Legacy fields for first NIC
1493 4cc4d1fa Michael Hanselmann
    ("ip", "nic.ip/0"),
1494 4cc4d1fa Michael Hanselmann
    ("mac", "nic.mac/0"),
1495 4cc4d1fa Michael Hanselmann
    ("bridge", "nic.bridge/0"),
1496 4cc4d1fa Michael Hanselmann
    ("nic_mode", "nic.mode/0"),
1497 4cc4d1fa Michael Hanselmann
    ("nic_link", "nic.link/0"),
1498 4cc4d1fa Michael Hanselmann
    ]
1499 4cc4d1fa Michael Hanselmann
1500 4cc4d1fa Michael Hanselmann
  return (fields, aliases)
1501 1c8addc6 Michael Hanselmann
1502 1c8addc6 Michael Hanselmann
1503 1c8addc6 Michael Hanselmann
def _GetInstDiskUsage(ctx, inst):
1504 1c8addc6 Michael Hanselmann
  """Get disk usage for an instance.
1505 1c8addc6 Michael Hanselmann

1506 1c8addc6 Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1507 1c8addc6 Michael Hanselmann
  @type inst: L{objects.Instance}
1508 1c8addc6 Michael Hanselmann
  @param inst: Instance object
1509 1c8addc6 Michael Hanselmann

1510 1c8addc6 Michael Hanselmann
  """
1511 1c8addc6 Michael Hanselmann
  usage = ctx.disk_usage[inst.name]
1512 1c8addc6 Michael Hanselmann
1513 1c8addc6 Michael Hanselmann
  if usage is None:
1514 1c8addc6 Michael Hanselmann
    usage = 0
1515 1c8addc6 Michael Hanselmann
1516 e2d188cc Iustin Pop
  return usage
1517 1c8addc6 Michael Hanselmann
1518 1c8addc6 Michael Hanselmann
1519 5d28cb6f Michael Hanselmann
def _GetInstanceConsole(ctx, inst):
1520 5d28cb6f Michael Hanselmann
  """Get console information for instance.
1521 5d28cb6f Michael Hanselmann

1522 5d28cb6f Michael Hanselmann
  @type ctx: L{InstanceQueryData}
1523 5d28cb6f Michael Hanselmann
  @type inst: L{objects.Instance}
1524 5d28cb6f Michael Hanselmann
  @param inst: Instance object
1525 5d28cb6f Michael Hanselmann

1526 5d28cb6f Michael Hanselmann
  """
1527 5d28cb6f Michael Hanselmann
  consinfo = ctx.console[inst.name]
1528 5d28cb6f Michael Hanselmann
1529 5d28cb6f Michael Hanselmann
  if consinfo is None:
1530 5d28cb6f Michael Hanselmann
    return _FS_UNAVAIL
1531 5d28cb6f Michael Hanselmann
1532 5d28cb6f Michael Hanselmann
  return consinfo
1533 5d28cb6f Michael Hanselmann
1534 5d28cb6f Michael Hanselmann
1535 1c8addc6 Michael Hanselmann
def _GetInstanceDiskFields():
1536 1c8addc6 Michael Hanselmann
  """Get instance fields involving disks.
1537 1c8addc6 Michael Hanselmann

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

1540 1c8addc6 Michael Hanselmann
  """
1541 1c8addc6 Michael Hanselmann
  fields = [
1542 79b2ca83 Michael Hanselmann
    (_MakeField("disk_usage", "DiskUsage", QFT_UNIT,
1543 79b2ca83 Michael Hanselmann
                "Total disk space used by instance on each of its nodes;"
1544 79b2ca83 Michael Hanselmann
                " this is not the disk size visible to the instance, but"
1545 79b2ca83 Michael Hanselmann
                " the usage on the node"),
1546 111bf531 Michael Hanselmann
     IQ_DISKUSAGE, 0, _GetInstDiskUsage),
1547 79b2ca83 Michael Hanselmann
    (_MakeField("disk.count", "Disks", QFT_NUMBER, "Number of disks"),
1548 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: len(inst.disks)),
1549 79b2ca83 Michael Hanselmann
    (_MakeField("disk.sizes", "Disk_sizes", QFT_OTHER, "List of disk sizes"),
1550 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, lambda ctx, inst: [disk.size for disk in inst.disks]),
1551 1c8addc6 Michael Hanselmann
    ]
1552 1c8addc6 Michael Hanselmann
1553 1c8addc6 Michael Hanselmann
  # Disks by number
1554 1c8addc6 Michael Hanselmann
  fields.extend([
1555 79b2ca83 Michael Hanselmann
    (_MakeField("disk.size/%s" % i, "Disk/%s" % i, QFT_UNIT,
1556 79b2ca83 Michael Hanselmann
                "Disk size of %s disk" % utils.FormatOrdinal(i + 1)),
1557 111bf531 Michael Hanselmann
     IQ_CONFIG, 0, _GetInstDiskSize(i))
1558 1c8addc6 Michael Hanselmann
    for i in range(constants.MAX_DISKS)
1559 1c8addc6 Michael Hanselmann
    ])
1560 1c8addc6 Michael Hanselmann
1561 1c8addc6 Michael Hanselmann
  return fields
1562 1c8addc6 Michael Hanselmann
1563 1c8addc6 Michael Hanselmann
1564 1c8addc6 Michael Hanselmann
def _GetInstanceParameterFields():
1565 1c8addc6 Michael Hanselmann
  """Get instance fields involving parameters.
1566 1c8addc6 Michael Hanselmann

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

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

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

1726 24d16f76 Michael Hanselmann
  """
1727 24d16f76 Michael Hanselmann
  def __init__(self, lockdata):
1728 24d16f76 Michael Hanselmann
    """Initializes this class.
1729 24d16f76 Michael Hanselmann

1730 24d16f76 Michael Hanselmann
    """
1731 24d16f76 Michael Hanselmann
    self.lockdata = lockdata
1732 24d16f76 Michael Hanselmann
1733 24d16f76 Michael Hanselmann
  def __iter__(self):
1734 24d16f76 Michael Hanselmann
    """Iterate over all locks.
1735 24d16f76 Michael Hanselmann

1736 24d16f76 Michael Hanselmann
    """
1737 24d16f76 Michael Hanselmann
    return iter(self.lockdata)
1738 24d16f76 Michael Hanselmann
1739 24d16f76 Michael Hanselmann
1740 24d16f76 Michael Hanselmann
def _GetLockOwners(_, data):
1741 24d16f76 Michael Hanselmann
  """Returns a sorted list of a lock's current owners.
1742 24d16f76 Michael Hanselmann

1743 24d16f76 Michael Hanselmann
  """
1744 24d16f76 Michael Hanselmann
  (_, _, owners, _) = data
1745 24d16f76 Michael Hanselmann
1746 24d16f76 Michael Hanselmann
  if owners:
1747 24d16f76 Michael Hanselmann
    owners = utils.NiceSort(owners)
1748 24d16f76 Michael Hanselmann
1749 e2d188cc Iustin Pop
  return owners
1750 24d16f76 Michael Hanselmann
1751 24d16f76 Michael Hanselmann
1752 24d16f76 Michael Hanselmann
def _GetLockPending(_, data):
1753 24d16f76 Michael Hanselmann
  """Returns a sorted list of a lock's pending acquires.
1754 24d16f76 Michael Hanselmann

1755 24d16f76 Michael Hanselmann
  """
1756 24d16f76 Michael Hanselmann
  (_, _, _, pending) = data
1757 24d16f76 Michael Hanselmann
1758 24d16f76 Michael Hanselmann
  if pending:
1759 24d16f76 Michael Hanselmann
    pending = [(mode, utils.NiceSort(names))
1760 24d16f76 Michael Hanselmann
               for (mode, names) in pending]
1761 24d16f76 Michael Hanselmann
1762 e2d188cc Iustin Pop
  return pending
1763 24d16f76 Michael Hanselmann
1764 24d16f76 Michael Hanselmann
1765 24d16f76 Michael Hanselmann
def _BuildLockFields():
1766 24d16f76 Michael Hanselmann
  """Builds list of fields for lock queries.
1767 24d16f76 Michael Hanselmann

1768 24d16f76 Michael Hanselmann
  """
1769 24d16f76 Michael Hanselmann
  return _PrepareFieldList([
1770 111bf531 Michael Hanselmann
    # TODO: Lock names are not always hostnames. Should QFF_HOSTNAME be used?
1771 111bf531 Michael Hanselmann
    (_MakeField("name", "Name", QFT_TEXT, "Lock name"), None, 0,
1772 e2d188cc Iustin Pop
     lambda ctx, (name, mode, owners, pending): name),
1773 79b2ca83 Michael Hanselmann
    (_MakeField("mode", "Mode", QFT_OTHER,
1774 79b2ca83 Michael Hanselmann
                "Mode in which the lock is currently acquired"
1775 79b2ca83 Michael Hanselmann
                " (exclusive or shared)"),
1776 111bf531 Michael Hanselmann
     LQ_MODE, 0, lambda ctx, (name, mode, owners, pending): mode),
1777 79b2ca83 Michael Hanselmann
    (_MakeField("owner", "Owner", QFT_OTHER, "Current lock owner(s)"),
1778 111bf531 Michael Hanselmann
     LQ_OWNER, 0, _GetLockOwners),
1779 79b2ca83 Michael Hanselmann
    (_MakeField("pending", "Pending", QFT_OTHER,
1780 79b2ca83 Michael Hanselmann
                "Threads waiting for the lock"),
1781 111bf531 Michael Hanselmann
     LQ_PENDING, 0, _GetLockPending),
1782 d63bd540 Iustin Pop
    ], [])
1783 24d16f76 Michael Hanselmann
1784 24d16f76 Michael Hanselmann
1785 8e21cfc0 Adeodato Simo
class GroupQueryData:
1786 8e21cfc0 Adeodato Simo
  """Data container for node group data queries.
1787 8e21cfc0 Adeodato Simo

1788 8e21cfc0 Adeodato Simo
  """
1789 8e21cfc0 Adeodato Simo
  def __init__(self, groups, group_to_nodes, group_to_instances):
1790 8e21cfc0 Adeodato Simo
    """Initializes this class.
1791 8e21cfc0 Adeodato Simo

1792 8e21cfc0 Adeodato Simo
    @param groups: List of node group objects
1793 8e21cfc0 Adeodato Simo
    @type group_to_nodes: dict; group UUID as key
1794 8e21cfc0 Adeodato Simo
    @param group_to_nodes: Per-group list of nodes
1795 8e21cfc0 Adeodato Simo
    @type group_to_instances: dict; group UUID as key
1796 8e21cfc0 Adeodato Simo
    @param group_to_instances: Per-group list of (primary) instances
1797 8e21cfc0 Adeodato Simo

1798 8e21cfc0 Adeodato Simo
    """
1799 8e21cfc0 Adeodato Simo
    self.groups = groups
1800 8e21cfc0 Adeodato Simo
    self.group_to_nodes = group_to_nodes
1801 8e21cfc0 Adeodato Simo
    self.group_to_instances = group_to_instances
1802 8e21cfc0 Adeodato Simo
1803 8e21cfc0 Adeodato Simo
  def __iter__(self):
1804 8e21cfc0 Adeodato Simo
    """Iterate over all node groups.
1805 8e21cfc0 Adeodato Simo

1806 8e21cfc0 Adeodato Simo
    """
1807 8e21cfc0 Adeodato Simo
    return iter(self.groups)
1808 8e21cfc0 Adeodato Simo
1809 8e21cfc0 Adeodato Simo
1810 8e21cfc0 Adeodato Simo
_GROUP_SIMPLE_FIELDS = {
1811 79b2ca83 Michael Hanselmann
  "alloc_policy": ("AllocPolicy", QFT_TEXT, "Allocation policy for group"),
1812 79b2ca83 Michael Hanselmann
  "name": ("Group", QFT_TEXT, "Group name"),
1813 79b2ca83 Michael Hanselmann
  "serial_no": ("SerialNo", QFT_NUMBER, _SERIAL_NO_DOC % "Group"),
1814 79b2ca83 Michael Hanselmann
  "uuid": ("UUID", QFT_TEXT, "Group UUID"),
1815 79b2ca83 Michael Hanselmann
  "ndparams": ("NDParams", QFT_OTHER, "Node parameters"),
1816 8e21cfc0 Adeodato Simo
  }
1817 8e21cfc0 Adeodato Simo
1818 8e21cfc0 Adeodato Simo
1819 8e21cfc0 Adeodato Simo
def _BuildGroupFields():
1820 8e21cfc0 Adeodato Simo
  """Builds list of fields for node group queries.
1821 8e21cfc0 Adeodato Simo

1822 8e21cfc0 Adeodato Simo
  """
1823 8e21cfc0 Adeodato Simo
  # Add simple fields
1824 111bf531 Michael Hanselmann
  fields = [(_MakeField(name, title, kind, doc), GQ_CONFIG, 0,
1825 111bf531 Michael Hanselmann
             _GetItemAttr(name))
1826 79b2ca83 Michael Hanselmann
            for (name, (title, kind, doc)) in _GROUP_SIMPLE_FIELDS.items()]
1827 8e21cfc0 Adeodato Simo
1828 8e21cfc0 Adeodato Simo
  def _GetLength(getter):
1829 e2d188cc Iustin Pop
    return lambda ctx, group: len(getter(ctx)[group.uuid])
1830 8e21cfc0 Adeodato Simo
1831 8e21cfc0 Adeodato Simo
  def _GetSortedList(getter):
1832 e2d188cc Iustin Pop
    return lambda ctx, group: utils.NiceSort(getter(ctx)[group.uuid])
1833 8e21cfc0 Adeodato Simo
1834 8e21cfc0 Adeodato Simo
  group_to_nodes = operator.attrgetter("group_to_nodes")
1835 8e21cfc0 Adeodato Simo
  group_to_instances = operator.attrgetter("group_to_instances")
1836 8e21cfc0 Adeodato Simo
1837 8e21cfc0 Adeodato Simo
  # Add fields for nodes
1838 8e21cfc0 Adeodato Simo
  fields.extend([
1839 79b2ca83 Michael Hanselmann
    (_MakeField("node_cnt", "Nodes", QFT_NUMBER, "Number of nodes"),
1840 111bf531 Michael Hanselmann
     GQ_NODE, 0, _GetLength(group_to_nodes)),
1841 79b2ca83 Michael Hanselmann
    (_MakeField("node_list", "NodeList", QFT_OTHER, "List of nodes"),
1842 111bf531 Michael Hanselmann
     GQ_NODE, 0, _GetSortedList(group_to_nodes)),
1843 8e21cfc0 Adeodato Simo
    ])
1844 8e21cfc0 Adeodato Simo
1845 8e21cfc0 Adeodato Simo
  # Add fields for instances
1846 8e21cfc0 Adeodato Simo
  fields.extend([
1847 79b2ca83 Michael Hanselmann
    (_MakeField("pinst_cnt", "Instances", QFT_NUMBER,
1848 79b2ca83 Michael Hanselmann
                "Number of primary instances"),
1849 111bf531 Michael Hanselmann
     GQ_INST, 0, _GetLength(group_to_instances)),
1850 79b2ca83 Michael Hanselmann
    (_MakeField("pinst_list", "InstanceList", QFT_OTHER,
1851 79b2ca83 Michael Hanselmann
                "List of primary instances"),
1852 111bf531 Michael Hanselmann
     GQ_INST, 0, _GetSortedList(group_to_instances)),
1853 8e21cfc0 Adeodato Simo
    ])
1854 8e21cfc0 Adeodato Simo
1855 8e21cfc0 Adeodato Simo
  fields.extend(_GetItemTimestampFields(GQ_CONFIG))
1856 8e21cfc0 Adeodato Simo
1857 d63bd540 Iustin Pop
  return _PrepareFieldList(fields, [])
1858 8e21cfc0 Adeodato Simo
1859 8e21cfc0 Adeodato Simo
1860 8235fe04 Michael Hanselmann
#: Fields available for node queries
1861 8235fe04 Michael Hanselmann
NODE_FIELDS = _BuildNodeFields()
1862 1c8addc6 Michael Hanselmann
1863 1c8addc6 Michael Hanselmann
#: Fields available for instance queries
1864 1c8addc6 Michael Hanselmann
INSTANCE_FIELDS = _BuildInstanceFields()
1865 24d16f76 Michael Hanselmann
1866 24d16f76 Michael Hanselmann
#: Fields available for lock queries
1867 24d16f76 Michael Hanselmann
LOCK_FIELDS = _BuildLockFields()
1868 e571ee44 Adeodato Simo
1869 8e21cfc0 Adeodato Simo
#: Fields available for node group queries
1870 8e21cfc0 Adeodato Simo
GROUP_FIELDS = _BuildGroupFields()
1871 8e21cfc0 Adeodato Simo
1872 95eb4188 Michael Hanselmann
#: All available resources
1873 95eb4188 Michael Hanselmann
ALL_FIELDS = {
1874 95eb4188 Michael Hanselmann
  constants.QR_INSTANCE: INSTANCE_FIELDS,
1875 95eb4188 Michael Hanselmann
  constants.QR_NODE: NODE_FIELDS,
1876 95eb4188 Michael Hanselmann
  constants.QR_LOCK: LOCK_FIELDS,
1877 95eb4188 Michael Hanselmann
  constants.QR_GROUP: GROUP_FIELDS,
1878 95eb4188 Michael Hanselmann
  }
1879 95eb4188 Michael Hanselmann
1880 e571ee44 Adeodato Simo
#: All available field lists
1881 95eb4188 Michael Hanselmann
ALL_FIELD_LISTS = ALL_FIELDS.values()