Statistics
| Branch: | Tag: | Revision:

root / lib / confd / querylib.py @ 250554a9

History | View | Annotate | Download (8.6 kB)

1 d73ef63f Michael Hanselmann
#
2 e16e4824 Guido Trotter
#
3 e16e4824 Guido Trotter
4 e16e4824 Guido Trotter
# 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 e16e4824 Guido Trotter
  def Exec(self, query):
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 e16e4824 Guido Trotter
    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 e16e4824 Guido Trotter
      answer = 'ok'
84 e16e4824 Guido Trotter
    else:
85 e16e4824 Guido Trotter
      status = constants.CONFD_REPL_STATUS_ERROR
86 e16e4824 Guido Trotter
      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 48166551 Guido Trotter
  def Exec(self, query):
98 48166551 Guido Trotter
    """ClusterMasterQuery main execution
99 48166551 Guido Trotter

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

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

133 6daf26a0 Guido Trotter
  """
134 6daf26a0 Guido Trotter
  def Exec(self, query):
135 6daf26a0 Guido Trotter
    """EmptyQuery main execution
136 6daf26a0 Guido Trotter

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

163 53bd7366 Guido Trotter
  """
164 53bd7366 Guido Trotter
  def Exec(self, query):
165 0bc8432b Guido Trotter
    """InstanceIpToNodePrimaryIpQuery main execution.
166 53bd7366 Guido Trotter

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

176 53bd7366 Guido Trotter
    """
177 19351457 Guido Trotter
    if isinstance(query, dict):
178 19351457 Guido Trotter
      if constants.CONFD_REQQ_IP in query:
179 19351457 Guido Trotter
        instances_list = [query[constants.CONFD_REQQ_IP]]
180 19351457 Guido Trotter
        mode = constants.CONFD_REQQ_IP
181 19351457 Guido Trotter
      elif constants.CONFD_REQQ_IPLIST in query:
182 19351457 Guido Trotter
        instances_list = query[constants.CONFD_REQQ_IPLIST]
183 19351457 Guido Trotter
        mode = constants.CONFD_REQQ_IPLIST
184 19351457 Guido Trotter
      else:
185 19351457 Guido Trotter
        status = constants.CONFD_REPL_STATUS_ERROR
186 19351457 Guido Trotter
        logging.debug("missing IP or IPLIST in query dict")
187 19351457 Guido Trotter
        return QUERY_ARGUMENT_ERROR
188 19351457 Guido Trotter
189 19351457 Guido Trotter
      if constants.CONFD_REQQ_LINK in query:
190 19351457 Guido Trotter
        network_link = query[constants.CONFD_REQQ_LINK]
191 19351457 Guido Trotter
      else:
192 19351457 Guido Trotter
        network_link = None # default will be used
193 19351457 Guido Trotter
    elif isinstance(query, basestring):
194 19351457 Guido Trotter
      # 2.1 beta1 and beta2 mode, to be deprecated for 2.2
195 95b487bb Flavio Silvestrow
      instances_list = [query]
196 19351457 Guido Trotter
      network_link = None
197 19351457 Guido Trotter
      mode = constants.CONFD_REQQ_IP
198 19351457 Guido Trotter
    else:
199 19351457 Guido Trotter
      logging.debug("Invalid query argument type for: %s" % query)
200 19351457 Guido Trotter
      return QUERY_ARGUMENT_ERROR
201 19351457 Guido Trotter
202 95b487bb Flavio Silvestrow
    pnodes_list = []
203 95b487bb Flavio Silvestrow
204 95b487bb Flavio Silvestrow
    for instance_ip in instances_list:
205 19351457 Guido Trotter
      if not isinstance(instance_ip, basestring):
206 19351457 Guido Trotter
        logging.debug("Invalid IP type for: %s" % instance_ip)
207 19351457 Guido Trotter
        return QUERY_ARGUMENT_ERROR
208 19351457 Guido Trotter
209 19351457 Guido Trotter
      instance = self.reader.GetInstanceByLinkIp(instance_ip, network_link)
210 95b487bb Flavio Silvestrow
      if not instance:
211 19351457 Guido Trotter
        logging.debug("Unknown instance IP: %s" % instance_ip)
212 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_UNKNOWN_ENTRY_ERROR)
213 95b487bb Flavio Silvestrow
        continue
214 53bd7366 Guido Trotter
215 95b487bb Flavio Silvestrow
      pnode = self.reader.GetInstancePrimaryNode(instance)
216 95b487bb Flavio Silvestrow
      if not pnode:
217 95b487bb Flavio Silvestrow
        logging.error("Instance '%s' doesn't have an associated primary"
218 95b487bb Flavio Silvestrow
                      " node" % instance)
219 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_INTERNAL_ERROR)
220 95b487bb Flavio Silvestrow
        continue
221 53bd7366 Guido Trotter
222 95b487bb Flavio Silvestrow
      pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode)
223 95b487bb Flavio Silvestrow
      if not pnode_primary_ip:
224 95b487bb Flavio Silvestrow
        logging.error("Primary node '%s' doesn't have an associated"
225 95b487bb Flavio Silvestrow
                      " primary IP" % pnode)
226 95b487bb Flavio Silvestrow
        pnodes_list.append(QUERY_INTERNAL_ERROR)
227 95b487bb Flavio Silvestrow
        continue
228 53bd7366 Guido Trotter
229 95b487bb Flavio Silvestrow
      pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip))
230 95b487bb Flavio Silvestrow
231 19351457 Guido Trotter
    # If a single ip was requested, return a single answer, otherwise the whole
232 19351457 Guido Trotter
    # list, with a success status (since each entry has its 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