Confd: add primary IPs queries
[ganeti-local] / lib / confd / querylib.py
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
37
38 class ConfdQuery(object):
39   """Confd Query base class.
40
41   """
42   def __init__(self, reader):
43     """Constructor for Confd Query
44
45     @type reader: L{ssconf.SimpleConfigReader}
46     @param reader: ConfigReader to use to access the config
47
48     """
49     self.reader = reader
50
51   def Exec(self, query):
52     """Process a single UDP request from a client.
53
54     Different queries should override this function, which by defaults returns
55     a "non-implemented" answer.
56
57     @type query: (undefined)
58     @param query: ConfdRequest 'query' field
59     @rtype: (integer, undefined)
60     @return: status and answer to give to the client
61
62     """
63     status = constants.CONFD_REPL_STATUS_NOTIMPLEMENTED
64     answer = 'not implemented'
65     return status, answer
66
67
68 class PingQuery(ConfdQuery):
69   """An empty confd query.
70
71   It will return success on an empty argument, and an error on any other
72   argument.
73
74   """
75   def Exec(self, query):
76     """PingQuery main execution.
77
78     """
79     if query is None:
80       status = constants.CONFD_REPL_STATUS_OK
81       answer = 'ok'
82     else:
83       status = constants.CONFD_REPL_STATUS_ERROR
84       answer = 'non-empty ping query'
85
86     return status, answer
87
88
89 class ClusterMasterQuery(ConfdQuery):
90   """Cluster master query.
91
92   It accepts no arguments, and returns the current cluster master.
93
94   """
95   def Exec(self, query):
96     """ClusterMasterQuery main execution
97
98     """
99     if query is None:
100       status = constants.CONFD_REPL_STATUS_OK
101       answer = self.reader.GetMasterNode()
102     else:
103       status = constants.CONFD_REPL_STATUS_ERROR
104       answer = 'master query accepts no query argument'
105
106     return status, answer
107
108
109 class NodeRoleQuery(ConfdQuery):
110   """A query for the role of a node.
111
112   It will return one of CONFD_NODE_ROLE_*, or an error for non-existing nodes.
113
114   """
115   def Exec(self, query):
116     """EmptyQuery main execution
117
118     """
119     node = query
120     if self.reader.GetMasterNode() == node:
121       status = constants.CONFD_REPL_STATUS_OK
122       answer = constants.CONFD_NODE_ROLE_MASTER
123       return status, answer
124     flags = self.reader.GetNodeStatusFlags(node)
125     if flags is None:
126       return QUERY_UNKNOWN_ENTRY_ERROR
127
128     master_candidate, drained, offline = flags
129     if master_candidate:
130       answer = constants.CONFD_NODE_ROLE_CANDIDATE
131     elif drained:
132       answer = constants.CONFD_NODE_ROLE_DRAINED
133     elif offline:
134       answer = constants.CONFD_NODE_ROLE_OFFLINE
135     else:
136       answer = constants.CONFD_NODE_ROLE_REGULAR
137
138     return constants.CONFD_REPL_STATUS_OK, answer
139
140
141 class InstanceIpToNodePrimaryIpQuery(ConfdQuery):
142   """A query for the location of an instance's ip.
143
144   It returns the primary ip of the node hosting the instance having the
145   requested ip address, or an error if no such address is known.
146
147   """
148   def Exec(self, query):
149     """InstanceIpToNodePrimaryIpQuery main execution.
150
151     """
152     instance_ip = query
153     instance = self.reader.GetInstanceByIp(instance_ip)
154     if instance is None:
155       return QUERY_UNKNOWN_ENTRY_ERROR
156
157     pnode = self.reader.GetInstancePrimaryNode(instance)
158     if pnode is None:
159       # this shouldn't happen
160       logging.error("Internal configuration inconsistent (instance-to-pnode)")
161       return QUERY_INTERNAL_ERROR
162
163     pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode)
164     if pnode_primary_ip is None:
165       # this shouldn't happen
166       logging.error("Internal configuration inconsistent (node-to-primary-ip)")
167       return QUERY_INTERNAL_ERROR
168
169     return constants.CONFD_REPL_STATUS_OK, pnode_primary_ip
170
171
172 class NodesPipsQuery(ConfdQuery):
173   """A query for nodes primary IPs.
174
175   It returns the list of nodes primary IPs.
176
177   """
178   def Exec(self, query):
179     """NodesPipsQuery main execution.
180
181     """
182     if query is None:
183       status = constants.CONFD_REPL_STATUS_OK
184       answer = self.reader.GetNodesPrimaryIps()
185     else:
186       status = constants.CONFD_REPL_STATUS_ERROR
187       answer = "non-empty node primary IPs query"
188
189     return status, answer
190
191
192 class MasterCandidatesPipsQuery(ConfdQuery):
193   """A query for master candidates primary IPs.
194
195   It returns the list of master candidates primary IPs.
196
197   """
198   def Exec(self, query):
199     """MasterCandidatesPipsQuery main execution.
200
201     """
202     if query is None:
203       status = constants.CONFD_REPL_STATUS_OK
204       answer = self.reader.GetMasterCandidatesPrimaryIps()
205     else:
206       status = constants.CONFD_REPL_STATUS_ERROR
207       answer = "non-empty master candidates primary IPs query"
208
209     return status, answer
210