Statistics
| Branch: | Tag: | Revision:

root / lib / confd / querylib.py @ 48166551

History | View | Annotate | Download (4.6 kB)

1
#!/usr/bin/python
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
# constants for some common errors to return from a query
31
QUERY_UNKNOWN_ENTRY_ERROR = (constants.CONFD_REPL_STATUS_ERROR,
32
                             constants.CONFD_ERROR_UNKNOWN_ENTRY)
33
QUERY_INTERNAL_ERROR = (constants.CONFD_REPL_STATUS_ERROR,
34
                        constants.CONFD_ERROR_INTERNAL)
35

    
36
class ConfdQuery(object):
37
  """Confd Query base class.
38

39
  """
40
  def __init__(self, reader):
41
    """Constructor for Confd Query
42

43
    @type reader: L{ssconf.SimpleConfigReader}
44
    @param reader: ConfigReader to use to access the config
45

46
    """
47
    self.reader = reader
48

    
49
  def Exec(self, query):
50
    """Process a single UDP request from a client.
51

52
    Different queries should override this function, which by defaults returns
53
    a "non-implemented" answer.
54

55
    @type query: (undefined)
56
    @param query: ConfdRequest 'query' field
57
    @rtype: (integer, undefined)
58
    @return: status and answer to give to the client
59

60
    """
61
    status = constants.CONFD_REPL_STATUS_NOTIMPLEMENTED
62
    answer = 'not implemented'
63
    return status, answer
64

    
65

    
66
class PingQuery(ConfdQuery):
67
  """An empty confd query.
68

69
  It will return success on an empty argument, and an error on any other argument.
70

71
  """
72
  def Exec(self, query):
73
    """PingQuery main execution.
74

75
    """
76
    if query is None:
77
      status = constants.CONFD_REPL_STATUS_OK
78
      answer = 'ok'
79
    else:
80
      status = constants.CONFD_REPL_STATUS_ERROR
81
      answer = 'non-empty ping query'
82

    
83
    return status, answer
84

    
85
class ClusterMasterQuery(ConfdQuery):
86
  """Cluster master query.
87

88
  It accepts no arguments, and returns the current cluster master.
89

90
  """
91
  def Exec(self, query):
92
    """ClusterMasterQuery main execution
93

94
    """
95
    if query is None:
96
      status = constants.CONFD_REPL_STATUS_OK
97
      answer = self.reader.GetMasterNode()
98
    else:
99
      status = constants.CONFD_REPL_STATUS_ERROR
100
      answer = 'master query accepts no query argument'
101

    
102
    return status, answer
103

    
104

    
105
class NodeRoleQuery(ConfdQuery):
106
  """A query for the role of a node.
107

108
  It will return one of CONFD_NODE_ROLE_*, or an error for non-existing nodes.
109

110
  """
111
  def Exec(self, query):
112
    """EmptyQuery main execution
113

114
    """
115
    node = query
116
    if self.reader.GetMasterNode() == node:
117
      status = constants.CONFD_REPL_STATUS_OK
118
      answer = constants.CONFD_NODE_ROLE_MASTER
119
      return status, answer
120
    flags = self.reader.GetNodeStatusFlags(node)
121
    if flags is None:
122
      return QUERY_UNKNOWN_ENTRY_ERROR
123

    
124
    master_candidate, drained, offline = flags
125
    if master_candidate:
126
      answer = constants.CONFD_NODE_ROLE_CANDIDATE
127
    elif drained:
128
      answer = constants.CONFD_NODE_ROLE_DRAINED
129
    elif offline:
130
      answer = constants.CONFD_NODE_ROLE_OFFLINE
131
    else:
132
      answer = constants.CONFD_NODE_ROLE_REGULAR
133

    
134
    return constants.CONFD_REPL_STATUS_OK, answer
135

    
136

    
137
class InstanceIpToNodePrimaryIpQuery(ConfdQuery):
138
  """A query for the location of an instance's ip.
139

140
  It returns the primary ip of the node hosting the instance having the
141
  requested ip address, or an error if no such address is known.
142

143
  """
144
  def Exec(self, query):
145
    """InstanceIpToNodePrimaryIpQuery main execution.
146

147
    """
148
    instance_ip = query
149
    instance = self.reader.GetInstanceByIp(instance_ip)
150
    if instance is None:
151
      return QUERY_UNKNOWN_ENTRY_ERROR
152

    
153
    pnode = self.reader.GetInstancePrimaryNode(instance)
154
    if pnode is None:
155
      # this shouldn't happen
156
      logging.error("Internal configuration inconsistent (instance-to-pnode)")
157
      return QUERY_INTERNAL_ERROR
158

    
159
    pnode_primary_ip = self.reader.GetNodePrimaryIp(pnode)
160
    if pnode_primary_ip is None:
161
      # this shouldn't happen
162
      logging.error("Internal configuration inconsistent (node-to-primary-ip)")
163
      return QUERY_INTERNAL_ERROR
164

    
165
    return constants.CONFD_REPL_STATUS_OK, pnode_primary_ip
166