Package ganeti :: Package confd :: Module querylib
[hide private]
[frames] | no frames]

Source Code for Module ganeti.confd.querylib

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2009, Google Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, but 
 12  # WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  # General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the Free Software 
 18  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 19  # 02110-1301, USA. 
 20   
 21   
 22  """Ganeti configuration daemon queries library. 
 23   
 24  """ 
 25   
 26  import logging 
 27   
 28  from ganeti import constants 
 29   
 30   
 31  # constants for some common errors to return from a query 
 32  QUERY_UNKNOWN_ENTRY_ERROR = (constants.CONFD_REPL_STATUS_ERROR, 
 33                               constants.CONFD_ERROR_UNKNOWN_ENTRY) 
 34  QUERY_INTERNAL_ERROR = (constants.CONFD_REPL_STATUS_ERROR, 
 35                          constants.CONFD_ERROR_INTERNAL) 
 36  QUERY_ARGUMENT_ERROR = (constants.CONFD_REPL_STATUS_ERROR, 
 37                          constants.CONFD_ERROR_ARGUMENT) 
 38   
 39   
40 -class ConfdQuery(object):
41 """Confd Query base class. 42 43 """
44 - def __init__(self, reader):
45 """Constructor for Confd Query 46 47 @type reader: L{ssconf.SimpleConfigReader} 48 @param reader: ConfigReader to use to access the config 49 50 """ 51 self.reader = reader
52
53 - def Exec(self, query): # pylint: disable-msg=R0201,W0613
54 """Process a single UDP request from a client. 55 56 Different queries should override this function, which by defaults returns 57 a "non-implemented" answer. 58 59 @type query: (undefined) 60 @param query: ConfdRequest 'query' field 61 @rtype: (integer, undefined) 62 @return: status and answer to give to the client 63 64 """ 65 status = constants.CONFD_REPL_STATUS_NOTIMPLEMENTED 66 answer = 'not implemented' 67 return status, answer
68 69
70 -class PingQuery(ConfdQuery):
71 """An empty confd query. 72 73 It will return success on an empty argument, and an error on any other 74 argument. 75 76 """
77 - def Exec(self, query):
78 """PingQuery main execution. 79 80 """ 81 if query is None: 82 status = constants.CONFD_REPL_STATUS_OK 83 answer = 'ok' 84 else: 85 status = constants.CONFD_REPL_STATUS_ERROR 86 answer = 'non-empty ping query' 87 88 return status, answer
89 90
91 -class ClusterMasterQuery(ConfdQuery):
92 """Cluster master query. 93 94 It accepts no arguments, and returns the current cluster master. 95 96 """
97 - def _GetMasterNode(self):
98 return self.reader.GetMasterNode()
99
100 - def Exec(self, query):
101 """ClusterMasterQuery main execution 102 103 """ 104 if isinstance(query, dict): 105 if constants.CONFD_REQQ_FIELDS in query: 106 status = constants.CONFD_REPL_STATUS_OK 107 req_fields = query[constants.CONFD_REQQ_FIELDS] 108 if not isinstance(req_fields, (list, tuple)): 109 logging.debug("FIELDS request should be a list") 110 return QUERY_ARGUMENT_ERROR 111 112 answer = [] 113 for field in req_fields: 114 if field == constants.CONFD_REQFIELD_NAME: 115 answer.append(self._GetMasterNode()) 116 elif field == constants.CONFD_REQFIELD_IP: 117 answer.append(self.reader.GetMasterIP()) 118 elif field == constants.CONFD_REQFIELD_MNODE_PIP: 119 answer.append(self.reader.GetNodePrimaryIp(self._GetMasterNode())) 120 else: 121 logging.debug("missing FIELDS in query dict") 122 return QUERY_ARGUMENT_ERROR 123 elif not query: 124 status = constants.CONFD_REPL_STATUS_OK 125 answer = self.reader.GetMasterNode() 126 else: 127 logging.debug("Invalid master query argument: not dict or empty") 128 return QUERY_ARGUMENT_ERROR 129 130 return status, answer
131 132
133 -class NodeRoleQuery(ConfdQuery):
134 """A query for the role of a node. 135 136 It will return one of CONFD_NODE_ROLE_*, or an error for non-existing nodes. 137 138 """
139 - def Exec(self, query):
140 """EmptyQuery main execution 141 142 """ 143 node = query 144 if self.reader.GetMasterNode() == node: 145 status = constants.CONFD_REPL_STATUS_OK 146 answer = constants.CONFD_NODE_ROLE_MASTER 147 return status, answer 148 flags = self.reader.GetNodeStatusFlags(node) 149 if flags is None: 150 return QUERY_UNKNOWN_ENTRY_ERROR 151 152 master_candidate, drained, offline = flags 153 if master_candidate: 154 answer = constants.CONFD_NODE_ROLE_CANDIDATE 155 elif drained: 156 answer = constants.CONFD_NODE_ROLE_DRAINED 157 elif offline: 158 answer = constants.CONFD_NODE_ROLE_OFFLINE 159 else: 160 answer = constants.CONFD_NODE_ROLE_REGULAR 161 162 return constants.CONFD_REPL_STATUS_OK, answer
163 164
165 -class InstanceIpToNodePrimaryIpQuery(ConfdQuery):
166 """A query for the location of one or more instance's ips. 167 168 """
169 - def Exec(self, query):
170 """InstanceIpToNodePrimaryIpQuery main execution. 171 172 @type query: string or dict 173 @param query: instance ip or dict containing: 174 constants.CONFD_REQQ_LINK: nic link (optional) 175 constants.CONFD_REQQ_IPLIST: list of ips 176 constants.CONFD_REQQ_IP: single ip 177 (one IP type request is mandatory) 178 @rtype: (integer, ...) 179 @return: ((status, answer) or (success, [(status, answer)...]) 180 181 """ 182 if isinstance(query, dict): 183 if constants.CONFD_REQQ_IP in query: 184 instances_list = [query[constants.CONFD_REQQ_IP]] 185 mode = constants.CONFD_REQQ_IP 186 elif constants.CONFD_REQQ_IPLIST in query: 187 instances_list = query[constants.CONFD_REQQ_IPLIST] 188 mode = constants.CONFD_REQQ_IPLIST 189 else: 190 logging.debug("missing IP or IPLIST in query dict") 191 return QUERY_ARGUMENT_ERROR 192 193 if constants.CONFD_REQQ_LINK in query: 194 network_link = query[constants.CONFD_REQQ_LINK] 195 else: 196 network_link = None # default will be used 197 elif isinstance(query, basestring): 198 # 2.1 beta1 and beta2 mode, to be deprecated for 2.2 199 instances_list = [query] 200 network_link = None 201 mode = constants.CONFD_REQQ_IP 202 else: 203 logging.debug("Invalid query argument type for: %s", query) 204 return QUERY_ARGUMENT_ERROR 205 206 pnodes_list = [] 207 208 for instance_ip in instances_list: 209 if not isinstance(instance_ip, basestring): 210 logging.debug("Invalid IP type for: %s", instance_ip) 211 return QUERY_ARGUMENT_ERROR 212 213 instance = self.reader.GetInstanceByLinkIp(instance_ip, network_link) 214 if not instance: 215 logging.debug("Unknown instance IP: %s", instance_ip) 216 pnodes_list.append(QUERY_UNKNOWN_ENTRY_ERROR) 217 continue 218 219 pnode = self.reader.GetInstancePrimaryNode(instance) 220 if not pnode: 221 logging.error("Instance '%s' doesn't have an associated primary" 222 " node", instance) 223 pnodes_list.append(QUERY_INTERNAL_ERROR) 224 continue 225 226 pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode) 227 if not pnode_primary_ip: 228 logging.error("Primary node '%s' doesn't have an associated" 229 " primary IP", pnode) 230 pnodes_list.append(QUERY_INTERNAL_ERROR) 231 continue 232 233 pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip)) 234 235 # If a single ip was requested, return a single answer, otherwise 236 # the whole list, with a success status (since each entry has its 237 # own success/failure) 238 if mode == constants.CONFD_REQQ_IP: 239 return pnodes_list[0] 240 241 return constants.CONFD_REPL_STATUS_OK, pnodes_list
242 243
244 -class NodesPipsQuery(ConfdQuery):
245 """A query for nodes primary IPs. 246 247 It returns the list of nodes primary IPs. 248 249 """
250 - def Exec(self, query):
251 """NodesPipsQuery main execution. 252 253 """ 254 if query is None: 255 status = constants.CONFD_REPL_STATUS_OK 256 answer = self.reader.GetNodesPrimaryIps() 257 else: 258 status = constants.CONFD_REPL_STATUS_ERROR 259 answer = "non-empty node primary IPs query" 260 261 return status, answer
262 263
264 -class MasterCandidatesPipsQuery(ConfdQuery):
265 """A query for master candidates primary IPs. 266 267 It returns the list of master candidates primary IPs. 268 269 """
270 - def Exec(self, query):
271 """MasterCandidatesPipsQuery main execution. 272 273 """ 274 if query is None: 275 status = constants.CONFD_REPL_STATUS_OK 276 answer = self.reader.GetMasterCandidatesPrimaryIps() 277 else: 278 status = constants.CONFD_REPL_STATUS_ERROR 279 answer = "non-empty master candidates primary IPs query" 280 281 return status, answer
282 283
284 -class InstancesIpsQuery(ConfdQuery):
285 """A query for instances IPs. 286 287 It returns the list of IPs of NICs connected to the requested link or all the 288 instances IPs if no link is submitted. 289 290 """
291 - def Exec(self, query):
292 """InstancesIpsQuery main execution. 293 294 """ 295 link = query 296 status = constants.CONFD_REPL_STATUS_OK 297 answer = self.reader.GetInstancesIps(link) 298 299 return status, answer
300