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=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 else: 198 logging.debug("Invalid query argument type for: %s", query) 199 return QUERY_ARGUMENT_ERROR 200 201 pnodes_list = [] 202 203 for instance_ip in instances_list: 204 if not isinstance(instance_ip, basestring): 205 logging.debug("Invalid IP type for: %s", instance_ip) 206 return QUERY_ARGUMENT_ERROR 207 208 instance = self.reader.GetInstanceByLinkIp(instance_ip, network_link) 209 if not instance: 210 logging.debug("Unknown instance IP: %s", instance_ip) 211 pnodes_list.append(QUERY_UNKNOWN_ENTRY_ERROR) 212 continue 213 214 pnode = self.reader.GetInstancePrimaryNode(instance) 215 if not pnode: 216 logging.error("Instance '%s' doesn't have an associated primary" 217 " node", instance) 218 pnodes_list.append(QUERY_INTERNAL_ERROR) 219 continue 220 221 pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode) 222 if not pnode_primary_ip: 223 logging.error("Primary node '%s' doesn't have an associated" 224 " primary IP", pnode) 225 pnodes_list.append(QUERY_INTERNAL_ERROR) 226 continue 227 228 pnodes_list.append((constants.CONFD_REPL_STATUS_OK, pnode_primary_ip)) 229 230 # If a single ip was requested, return a single answer, otherwise 231 # the whole list, with a success status (since each entry has its 232 # own success/failure) 233 if mode == constants.CONFD_REQQ_IP: 234 return pnodes_list[0] 235 236 return constants.CONFD_REPL_STATUS_OK, pnodes_list
237 238
239 -class NodesPipsQuery(ConfdQuery):
240 """A query for nodes primary IPs. 241 242 It returns the list of nodes primary IPs. 243 244 """
245 - def Exec(self, query):
246 """NodesPipsQuery main execution. 247 248 """ 249 if query is None: 250 status = constants.CONFD_REPL_STATUS_OK 251 answer = self.reader.GetNodesPrimaryIps() 252 else: 253 status = constants.CONFD_REPL_STATUS_ERROR 254 answer = "non-empty node primary IPs query" 255 256 return status, answer
257 258
259 -class MasterCandidatesPipsQuery(ConfdQuery):
260 """A query for master candidates primary IPs. 261 262 It returns the list of master candidates primary IPs. 263 264 """
265 - def Exec(self, query):
266 """MasterCandidatesPipsQuery main execution. 267 268 """ 269 if query is None: 270 status = constants.CONFD_REPL_STATUS_OK 271 answer = self.reader.GetMasterCandidatesPrimaryIps() 272 else: 273 status = constants.CONFD_REPL_STATUS_ERROR 274 answer = "non-empty master candidates primary IPs query" 275 276 return status, answer
277 278
279 -class InstancesIpsQuery(ConfdQuery):
280 """A query for instances IPs. 281 282 It returns the list of IPs of NICs connected to the requested link or all the 283 instances IPs if no link is submitted. 284 285 """
286 - def Exec(self, query):
287 """InstancesIpsQuery main execution. 288 289 """ 290 link = query 291 status = constants.CONFD_REPL_STATUS_OK 292 answer = self.reader.GetInstancesIps(link) 293 294 return status, answer
295