Statistics
| Branch: | Tag: | Revision:

root / lib / confd / querylib.py @ 7142485a

History | View | Annotate | Download (8.6 kB)

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

24 e16e4824 Guido Trotter
"""
25 e16e4824 Guido Trotter
26 53bd7366 Guido Trotter
import logging
27 53bd7366 Guido Trotter
28 e16e4824 Guido Trotter
from ganeti import constants
29 e16e4824 Guido Trotter
30 d73ef63f Michael Hanselmann
31 7189e790 Guido Trotter
# constants for some common errors to return from a query
32 7189e790 Guido Trotter
QUERY_UNKNOWN_ENTRY_ERROR = (constants.CONFD_REPL_STATUS_ERROR,
33 7189e790 Guido Trotter
                             constants.CONFD_ERROR_UNKNOWN_ENTRY)
34 7189e790 Guido Trotter
QUERY_INTERNAL_ERROR = (constants.CONFD_REPL_STATUS_ERROR,
35 7189e790 Guido Trotter
                        constants.CONFD_ERROR_INTERNAL)
36 19351457 Guido Trotter
QUERY_ARGUMENT_ERROR = (constants.CONFD_REPL_STATUS_ERROR,
37 19351457 Guido Trotter
                        constants.CONFD_ERROR_ARGUMENT)
38 e16e4824 Guido Trotter
39 d73ef63f Michael Hanselmann
40 e16e4824 Guido Trotter
class ConfdQuery(object):
41 e16e4824 Guido Trotter
  """Confd Query base class.
42 e16e4824 Guido Trotter

43 e16e4824 Guido Trotter
  """
44 e16e4824 Guido Trotter
  def __init__(self, reader):
45 e16e4824 Guido Trotter
    """Constructor for Confd Query
46 e16e4824 Guido Trotter

47 e16e4824 Guido Trotter
    @type reader: L{ssconf.SimpleConfigReader}
48 e16e4824 Guido Trotter
    @param reader: ConfigReader to use to access the config
49 e16e4824 Guido Trotter

50 e16e4824 Guido Trotter
    """
51 e16e4824 Guido Trotter
    self.reader = reader
52 e16e4824 Guido Trotter
53 b459a848 Andrea Spadaccini
  def Exec(self, query): # pylint: disable=R0201,W0613
54 e16e4824 Guido Trotter
    """Process a single UDP request from a client.
55 e16e4824 Guido Trotter

56 e16e4824 Guido Trotter
    Different queries should override this function, which by defaults returns
57 e16e4824 Guido Trotter
    a "non-implemented" answer.
58 e16e4824 Guido Trotter

59 e16e4824 Guido Trotter
    @type query: (undefined)
60 e16e4824 Guido Trotter
    @param query: ConfdRequest 'query' field
61 e16e4824 Guido Trotter
    @rtype: (integer, undefined)
62 e16e4824 Guido Trotter
    @return: status and answer to give to the client
63 e16e4824 Guido Trotter

64 e16e4824 Guido Trotter
    """
65 e16e4824 Guido Trotter
    status = constants.CONFD_REPL_STATUS_NOTIMPLEMENTED
66 3ccb3a64 Michael Hanselmann
    answer = "not implemented"
67 e16e4824 Guido Trotter
    return status, answer
68 e16e4824 Guido Trotter
69 e16e4824 Guido Trotter
70 e16e4824 Guido Trotter
class PingQuery(ConfdQuery):
71 e16e4824 Guido Trotter
  """An empty confd query.
72 e16e4824 Guido Trotter

73 4d4a651d Michael Hanselmann
  It will return success on an empty argument, and an error on any other
74 4d4a651d Michael Hanselmann
  argument.
75 e16e4824 Guido Trotter

76 e16e4824 Guido Trotter
  """
77 e16e4824 Guido Trotter
  def Exec(self, query):
78 0bc8432b Guido Trotter
    """PingQuery main execution.
79 e16e4824 Guido Trotter

80 e16e4824 Guido Trotter
    """
81 e16e4824 Guido Trotter
    if query is None:
82 e16e4824 Guido Trotter
      status = constants.CONFD_REPL_STATUS_OK
83 3ccb3a64 Michael Hanselmann
      answer = "ok"
84 e16e4824 Guido Trotter
    else:
85 e16e4824 Guido Trotter
      status = constants.CONFD_REPL_STATUS_ERROR
86 3ccb3a64 Michael Hanselmann
      answer = "non-empty ping query"
87 e16e4824 Guido Trotter
88 e16e4824 Guido Trotter
    return status, answer
89 e16e4824 Guido Trotter
90 d73ef63f Michael Hanselmann
91 48166551 Guido Trotter
class ClusterMasterQuery(ConfdQuery):
92 48166551 Guido Trotter
  """Cluster master query.
93 48166551 Guido Trotter

94 48166551 Guido Trotter
  It accepts no arguments, and returns the current cluster master.
95 48166551 Guido Trotter

96 48166551 Guido Trotter
  """
97 43dc8496 Guido Trotter
  def _GetMasterNode(self):
98 43dc8496 Guido Trotter
    return self.reader.GetMasterNode()
99 43dc8496 Guido Trotter
100 48166551 Guido Trotter
  def Exec(self, query):
101 48166551 Guido Trotter
    """ClusterMasterQuery main execution
102 48166551 Guido Trotter

103 48166551 Guido Trotter
    """
104 250554a9 Guido Trotter
    if isinstance(query, dict):
105 250554a9 Guido Trotter
      if constants.CONFD_REQQ_FIELDS in query:
106 250554a9 Guido Trotter
        status = constants.CONFD_REPL_STATUS_OK
107 250554a9 Guido Trotter
        req_fields = query[constants.CONFD_REQQ_FIELDS]
108 250554a9 Guido Trotter
        if not isinstance(req_fields, (list, tuple)):
109 250554a9 Guido Trotter
          logging.debug("FIELDS request should be a list")
110 250554a9 Guido Trotter
          return QUERY_ARGUMENT_ERROR
111 250554a9 Guido Trotter
112 250554a9 Guido Trotter
        answer = []
113 250554a9 Guido Trotter
        for field in req_fields:
114 250554a9 Guido Trotter
          if field == constants.CONFD_REQFIELD_NAME:
115 43dc8496 Guido Trotter
            answer.append(self._GetMasterNode())
116 250554a9 Guido Trotter
          elif field == constants.CONFD_REQFIELD_IP:
117 250554a9 Guido Trotter
            answer.append(self.reader.GetMasterIP())
118 43dc8496 Guido Trotter
          elif field == constants.CONFD_REQFIELD_MNODE_PIP:
119 43dc8496 Guido Trotter
            answer.append(self.reader.GetNodePrimaryIp(self._GetMasterNode()))
120 250554a9 Guido Trotter
      else:
121 250554a9 Guido Trotter
        logging.debug("missing FIELDS in query dict")
122 250554a9 Guido Trotter
        return QUERY_ARGUMENT_ERROR
123 250554a9 Guido Trotter
    elif not query:
124 48166551 Guido Trotter
      status = constants.CONFD_REPL_STATUS_OK
125 48166551 Guido Trotter
      answer = self.reader.GetMasterNode()
126 48166551 Guido Trotter
    else:
127 250554a9 Guido Trotter
      logging.debug("Invalid master query argument: not dict or empty")
128 250554a9 Guido Trotter
      return QUERY_ARGUMENT_ERROR
129 48166551 Guido Trotter
130 48166551 Guido Trotter
    return status, answer
131 48166551 Guido Trotter
132 6daf26a0 Guido Trotter
133 6daf26a0 Guido Trotter
class NodeRoleQuery(ConfdQuery):
134 0bc8432b Guido Trotter
  """A query for the role of a node.
135 6daf26a0 Guido Trotter

136 0bc8432b Guido Trotter
  It will return one of CONFD_NODE_ROLE_*, or an error for non-existing nodes.
137 6daf26a0 Guido Trotter

138 6daf26a0 Guido Trotter
  """
139 6daf26a0 Guido Trotter
  def Exec(self, query):
140 6daf26a0 Guido Trotter
    """EmptyQuery main execution
141 6daf26a0 Guido Trotter

142 6daf26a0 Guido Trotter
    """
143 6daf26a0 Guido Trotter
    node = query
144 6daf26a0 Guido Trotter
    if self.reader.GetMasterNode() == node:
145 6daf26a0 Guido Trotter
      status = constants.CONFD_REPL_STATUS_OK
146 6daf26a0 Guido Trotter
      answer = constants.CONFD_NODE_ROLE_MASTER
147 6daf26a0 Guido Trotter
      return status, answer
148 6daf26a0 Guido Trotter
    flags = self.reader.GetNodeStatusFlags(node)
149 6daf26a0 Guido Trotter
    if flags is None:
150 7189e790 Guido Trotter
      return QUERY_UNKNOWN_ENTRY_ERROR
151 6daf26a0 Guido Trotter
152 6daf26a0 Guido Trotter
    master_candidate, drained, offline = flags
153 6daf26a0 Guido Trotter
    if master_candidate:
154 6daf26a0 Guido Trotter
      answer = constants.CONFD_NODE_ROLE_CANDIDATE
155 6daf26a0 Guido Trotter
    elif drained:
156 6daf26a0 Guido Trotter
      answer = constants.CONFD_NODE_ROLE_DRAINED
157 6daf26a0 Guido Trotter
    elif offline:
158 6daf26a0 Guido Trotter
      answer = constants.CONFD_NODE_ROLE_OFFLINE
159 6daf26a0 Guido Trotter
    else:
160 6daf26a0 Guido Trotter
      answer = constants.CONFD_NODE_ROLE_REGULAR
161 6daf26a0 Guido Trotter
162 6daf26a0 Guido Trotter
    return constants.CONFD_REPL_STATUS_OK, answer
163 6daf26a0 Guido Trotter
164 53bd7366 Guido Trotter
165 53bd7366 Guido Trotter
class InstanceIpToNodePrimaryIpQuery(ConfdQuery):
166 95b487bb Flavio Silvestrow
  """A query for the location of one or more instance's ips.
167 53bd7366 Guido Trotter

168 53bd7366 Guido Trotter
  """
169 53bd7366 Guido Trotter
  def Exec(self, query):
170 0bc8432b Guido Trotter
    """InstanceIpToNodePrimaryIpQuery main execution.
171 53bd7366 Guido Trotter

172 23057d29 Michael Hanselmann
    @type query: string or dict
173 23057d29 Michael Hanselmann
    @param query: instance ip or dict containing:
174 23057d29 Michael Hanselmann
                  constants.CONFD_REQQ_LINK: nic link (optional)
175 23057d29 Michael Hanselmann
                  constants.CONFD_REQQ_IPLIST: list of ips
176 23057d29 Michael Hanselmann
                  constants.CONFD_REQQ_IP: single ip
177 23057d29 Michael Hanselmann
                  (one IP type request is mandatory)
178 23057d29 Michael Hanselmann
    @rtype: (integer, ...)
179 23057d29 Michael Hanselmann
    @return: ((status, answer) or (success, [(status, answer)...])
180 23057d29 Michael Hanselmann

181 53bd7366 Guido Trotter
    """
182 19351457 Guido Trotter
    if isinstance(query, dict):
183 19351457 Guido Trotter
      if constants.CONFD_REQQ_IP in query:
184 19351457 Guido Trotter
        instances_list = [query[constants.CONFD_REQQ_IP]]
185 19351457 Guido Trotter
        mode = constants.CONFD_REQQ_IP
186 19351457 Guido Trotter
      elif constants.CONFD_REQQ_IPLIST in query:
187 19351457 Guido Trotter
        instances_list = query[constants.CONFD_REQQ_IPLIST]
188 19351457 Guido Trotter
        mode = constants.CONFD_REQQ_IPLIST
189 19351457 Guido Trotter
      else:
190 19351457 Guido Trotter
        logging.debug("missing IP or IPLIST in query dict")
191 19351457 Guido Trotter
        return QUERY_ARGUMENT_ERROR
192 19351457 Guido Trotter
193 19351457 Guido Trotter
      if constants.CONFD_REQQ_LINK in query:
194 19351457 Guido Trotter
        network_link = query[constants.CONFD_REQQ_LINK]
195 19351457 Guido Trotter
      else:
196 19351457 Guido Trotter
        network_link = None # default will be used
197 19351457 Guido Trotter
    else:
198 07b8a2b5 Iustin Pop
      logging.debug("Invalid query argument type for: %s", query)
199 19351457 Guido Trotter
      return QUERY_ARGUMENT_ERROR
200 19351457 Guido Trotter
201 95b487bb Flavio Silvestrow
    pnodes_list = []
202 95b487bb Flavio Silvestrow
203 95b487bb Flavio Silvestrow
    for instance_ip in instances_list:
204 19351457 Guido Trotter
      if not isinstance(instance_ip, basestring):
205 07b8a2b5 Iustin Pop
        logging.debug("Invalid IP type for: %s", instance_ip)
206 19351457 Guido Trotter
        return QUERY_ARGUMENT_ERROR
207 19351457 Guido Trotter
208 19351457 Guido Trotter
      instance = self.reader.GetInstanceByLinkIp(instance_ip, network_link)
209 95b487bb Flavio Silvestrow
      if not instance:
210 07b8a2b5 Iustin Pop
        logging.debug("Unknown instance IP: %s", instance_ip)
211 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_UNKNOWN_ENTRY_ERROR)
212 95b487bb Flavio Silvestrow
        continue
213 53bd7366 Guido Trotter
214 95b487bb Flavio Silvestrow
      pnode = self.reader.GetInstancePrimaryNode(instance)
215 95b487bb Flavio Silvestrow
      if not pnode:
216 95b487bb Flavio Silvestrow
        logging.error("Instance '%s' doesn't have an associated primary"
217 07b8a2b5 Iustin Pop
                      " node", instance)
218 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_INTERNAL_ERROR)
219 95b487bb Flavio Silvestrow
        continue
220 53bd7366 Guido Trotter
221 95b487bb Flavio Silvestrow
      pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode)
222 95b487bb Flavio Silvestrow
      if not pnode_primary_ip:
223 95b487bb Flavio Silvestrow
        logging.error("Primary node '%s' doesn't have an associated"
224 07b8a2b5 Iustin Pop
                      " primary IP", pnode)
225 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_INTERNAL_ERROR)
226 95b487bb Flavio Silvestrow
        continue
227 53bd7366 Guido Trotter
228 95b487bb Flavio Silvestrow
      pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip))
229 95b487bb Flavio Silvestrow
230 07b8a2b5 Iustin Pop
    # If a single ip was requested, return a single answer, otherwise
231 07b8a2b5 Iustin Pop
    # the whole list, with a success status (since each entry has its
232 07b8a2b5 Iustin Pop
    # own success/failure)
233 19351457 Guido Trotter
    if mode == constants.CONFD_REQQ_IP:
234 95b487bb Flavio Silvestrow
      return pnodes_list[0]
235 95b487bb Flavio Silvestrow
236 95b487bb Flavio Silvestrow
    return constants.CONFD_REPL_STATUS_OK, pnodes_list
237 efbb4fd2 Luca Bigliardi
238 efbb4fd2 Luca Bigliardi
239 efbb4fd2 Luca Bigliardi
class NodesPipsQuery(ConfdQuery):
240 efbb4fd2 Luca Bigliardi
  """A query for nodes primary IPs.
241 efbb4fd2 Luca Bigliardi

242 efbb4fd2 Luca Bigliardi
  It returns the list of nodes primary IPs.
243 efbb4fd2 Luca Bigliardi

244 efbb4fd2 Luca Bigliardi
  """
245 efbb4fd2 Luca Bigliardi
  def Exec(self, query):
246 efbb4fd2 Luca Bigliardi
    """NodesPipsQuery main execution.
247 efbb4fd2 Luca Bigliardi

248 efbb4fd2 Luca Bigliardi
    """
249 efbb4fd2 Luca Bigliardi
    if query is None:
250 efbb4fd2 Luca Bigliardi
      status = constants.CONFD_REPL_STATUS_OK
251 efbb4fd2 Luca Bigliardi
      answer = self.reader.GetNodesPrimaryIps()
252 efbb4fd2 Luca Bigliardi
    else:
253 efbb4fd2 Luca Bigliardi
      status = constants.CONFD_REPL_STATUS_ERROR
254 efbb4fd2 Luca Bigliardi
      answer = "non-empty node primary IPs query"
255 efbb4fd2 Luca Bigliardi
256 efbb4fd2 Luca Bigliardi
    return status, answer
257 efbb4fd2 Luca Bigliardi
258 efbb4fd2 Luca Bigliardi
259 efbb4fd2 Luca Bigliardi
class MasterCandidatesPipsQuery(ConfdQuery):
260 efbb4fd2 Luca Bigliardi
  """A query for master candidates primary IPs.
261 efbb4fd2 Luca Bigliardi

262 efbb4fd2 Luca Bigliardi
  It returns the list of master candidates primary IPs.
263 efbb4fd2 Luca Bigliardi

264 efbb4fd2 Luca Bigliardi
  """
265 efbb4fd2 Luca Bigliardi
  def Exec(self, query):
266 efbb4fd2 Luca Bigliardi
    """MasterCandidatesPipsQuery main execution.
267 efbb4fd2 Luca Bigliardi

268 efbb4fd2 Luca Bigliardi
    """
269 efbb4fd2 Luca Bigliardi
    if query is None:
270 efbb4fd2 Luca Bigliardi
      status = constants.CONFD_REPL_STATUS_OK
271 efbb4fd2 Luca Bigliardi
      answer = self.reader.GetMasterCandidatesPrimaryIps()
272 efbb4fd2 Luca Bigliardi
    else:
273 efbb4fd2 Luca Bigliardi
      status = constants.CONFD_REPL_STATUS_ERROR
274 efbb4fd2 Luca Bigliardi
      answer = "non-empty master candidates primary IPs query"
275 efbb4fd2 Luca Bigliardi
276 efbb4fd2 Luca Bigliardi
    return status, answer
277 efbb4fd2 Luca Bigliardi
278 d01ae714 Luca Bigliardi
279 d01ae714 Luca Bigliardi
class InstancesIpsQuery(ConfdQuery):
280 d01ae714 Luca Bigliardi
  """A query for instances IPs.
281 d01ae714 Luca Bigliardi

282 23824641 Luca Bigliardi
  It returns the list of IPs of NICs connected to the requested link or all the
283 23824641 Luca Bigliardi
  instances IPs if no link is submitted.
284 d01ae714 Luca Bigliardi

285 d01ae714 Luca Bigliardi
  """
286 d01ae714 Luca Bigliardi
  def Exec(self, query):
287 d01ae714 Luca Bigliardi
    """InstancesIpsQuery main execution.
288 d01ae714 Luca Bigliardi

289 d01ae714 Luca Bigliardi
    """
290 23824641 Luca Bigliardi
    link = query
291 23824641 Luca Bigliardi
    status = constants.CONFD_REPL_STATUS_OK
292 23824641 Luca Bigliardi
    answer = self.reader.GetInstancesIps(link)
293 d01ae714 Luca Bigliardi
294 d01ae714 Luca Bigliardi
    return status, answer