Statistics
| Branch: | Tag: | Revision:

root / lib / confd / server.py @ 7fe23d47

History | View | Annotate | Download (5.4 kB)

1 d73ef63f Michael Hanselmann
#
2 71f27d19 Guido Trotter
#
3 71f27d19 Guido Trotter
4 71f27d19 Guido Trotter
# Copyright (C) 2009, Google Inc.
5 71f27d19 Guido Trotter
#
6 71f27d19 Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 71f27d19 Guido Trotter
# it under the terms of the GNU General Public License as published by
8 71f27d19 Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 71f27d19 Guido Trotter
# (at your option) any later version.
10 71f27d19 Guido Trotter
#
11 71f27d19 Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 71f27d19 Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 71f27d19 Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 71f27d19 Guido Trotter
# General Public License for more details.
15 71f27d19 Guido Trotter
#
16 71f27d19 Guido Trotter
# You should have received a copy of the GNU General Public License
17 71f27d19 Guido Trotter
# along with this program; if not, write to the Free Software
18 71f27d19 Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 71f27d19 Guido Trotter
# 02110-1301, USA.
20 71f27d19 Guido Trotter
21 71f27d19 Guido Trotter
22 71f27d19 Guido Trotter
"""Ganeti configuration daemon server library.
23 71f27d19 Guido Trotter

24 71f27d19 Guido Trotter
Ganeti-confd is a daemon to query master candidates for configuration values.
25 71f27d19 Guido Trotter
It uses UDP+HMAC for authentication with a global cluster key.
26 71f27d19 Guido Trotter

27 71f27d19 Guido Trotter
"""
28 71f27d19 Guido Trotter
29 71f27d19 Guido Trotter
import logging
30 71f27d19 Guido Trotter
import time
31 71f27d19 Guido Trotter
32 71f27d19 Guido Trotter
from ganeti import constants
33 71f27d19 Guido Trotter
from ganeti import objects
34 71f27d19 Guido Trotter
from ganeti import errors
35 71f27d19 Guido Trotter
from ganeti import utils
36 71f27d19 Guido Trotter
from ganeti import serializer
37 05f1ebf3 Guido Trotter
from ganeti import ssconf
38 71f27d19 Guido Trotter
39 e16e4824 Guido Trotter
from ganeti.confd import querylib
40 e16e4824 Guido Trotter
41 71f27d19 Guido Trotter
42 71f27d19 Guido Trotter
class ConfdProcessor(object):
43 71f27d19 Guido Trotter
  """A processor for confd requests.
44 71f27d19 Guido Trotter

45 05f1ebf3 Guido Trotter
  @ivar reader: confd SimpleConfigReader
46 e369f21d Guido Trotter
  @ivar disabled: whether confd serving is disabled
47 05f1ebf3 Guido Trotter

48 71f27d19 Guido Trotter
  """
49 71f27d19 Guido Trotter
  DISPATCH_TABLE = {
50 d73ef63f Michael Hanselmann
    constants.CONFD_REQ_PING: querylib.PingQuery,
51 d73ef63f Michael Hanselmann
    constants.CONFD_REQ_NODE_ROLE_BYNAME: querylib.NodeRoleQuery,
52 d73ef63f Michael Hanselmann
    constants.CONFD_REQ_NODE_PIP_BY_INSTANCE_IP:
53 d73ef63f Michael Hanselmann
      querylib.InstanceIpToNodePrimaryIpQuery,
54 d73ef63f Michael Hanselmann
    constants.CONFD_REQ_CLUSTER_MASTER: querylib.ClusterMasterQuery,
55 efbb4fd2 Luca Bigliardi
    constants.CONFD_REQ_NODE_PIP_LIST: querylib.NodesPipsQuery,
56 efbb4fd2 Luca Bigliardi
    constants.CONFD_REQ_MC_PIP_LIST: querylib.MasterCandidatesPipsQuery,
57 d01ae714 Luca Bigliardi
    constants.CONFD_REQ_INSTANCES_IPS_LIST: querylib.InstancesIpsQuery,
58 d73ef63f Michael Hanselmann
    }
59 71f27d19 Guido Trotter
60 05f1ebf3 Guido Trotter
  def __init__(self):
61 12ce965f Guido Trotter
    """Constructor for ConfdProcessor
62 71f27d19 Guido Trotter

63 71f27d19 Guido Trotter
    """
64 e369f21d Guido Trotter
    self.disabled = True
65 6b7d5878 Michael Hanselmann
    self.hmac_key = utils.ReadFile(constants.CONFD_HMAC_KEY)
66 e369f21d Guido Trotter
    self.reader = None
67 d21eda27 Guido Trotter
    assert \
68 d21eda27 Guido Trotter
      not constants.CONFD_REQS.symmetric_difference(self.DISPATCH_TABLE), \
69 d21eda27 Guido Trotter
      "DISPATCH_TABLE is unaligned with CONFD_REQS"
70 71f27d19 Guido Trotter
71 e369f21d Guido Trotter
  def Enable(self):
72 e369f21d Guido Trotter
    try:
73 e369f21d Guido Trotter
      self.reader = ssconf.SimpleConfigReader()
74 e369f21d Guido Trotter
      self.disabled = False
75 e369f21d Guido Trotter
    except errors.ConfigurationError:
76 e369f21d Guido Trotter
      self.disabled = True
77 e369f21d Guido Trotter
      raise
78 e369f21d Guido Trotter
79 e369f21d Guido Trotter
  def Disable(self):
80 e369f21d Guido Trotter
    self.disabled = True
81 e369f21d Guido Trotter
    self.reader = None
82 e369f21d Guido Trotter
83 71f27d19 Guido Trotter
  def ExecQuery(self, payload_in, ip, port):
84 71f27d19 Guido Trotter
    """Process a single UDP request from a client.
85 71f27d19 Guido Trotter

86 71f27d19 Guido Trotter
    @type payload_in: string
87 71f27d19 Guido Trotter
    @param payload_in: request raw data
88 71f27d19 Guido Trotter
    @type ip: string
89 71f27d19 Guido Trotter
    @param ip: source ip address
90 71f27d19 Guido Trotter
    @param port: integer
91 71f27d19 Guido Trotter
    @type port: source port
92 71f27d19 Guido Trotter

93 71f27d19 Guido Trotter
    """
94 e369f21d Guido Trotter
    if self.disabled:
95 e369f21d Guido Trotter
      logging.debug('Confd is disabled. Ignoring query.')
96 e369f21d Guido Trotter
      return
97 71f27d19 Guido Trotter
    try:
98 71f27d19 Guido Trotter
      request = self.ExtractRequest(payload_in)
99 71f27d19 Guido Trotter
      reply, rsalt = self.ProcessRequest(request)
100 71f27d19 Guido Trotter
      payload_out = self.PackReply(reply, rsalt)
101 71f27d19 Guido Trotter
      return payload_out
102 71f27d19 Guido Trotter
    except errors.ConfdRequestError, err:
103 07b8a2b5 Iustin Pop
      logging.info('Ignoring broken query from %s:%d: %s', ip, port, err)
104 71f27d19 Guido Trotter
      return None
105 71f27d19 Guido Trotter
106 71f27d19 Guido Trotter
  def ExtractRequest(self, payload):
107 71f27d19 Guido Trotter
    """Extracts a ConfdRequest object from a serialized hmac signed string.
108 71f27d19 Guido Trotter

109 71f27d19 Guido Trotter
    This functions also performs signature/timestamp validation.
110 71f27d19 Guido Trotter

111 71f27d19 Guido Trotter
    """
112 71f27d19 Guido Trotter
    current_time = time.time()
113 07b8a2b5 Iustin Pop
    logging.debug("Extracting request with size: %d", len(payload))
114 71f27d19 Guido Trotter
    try:
115 71f27d19 Guido Trotter
      (message, salt) = serializer.LoadSigned(payload, self.hmac_key)
116 71f27d19 Guido Trotter
    except errors.SignatureError, err:
117 71f27d19 Guido Trotter
      msg = "invalid signature: %s" % err
118 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
119 71f27d19 Guido Trotter
    try:
120 71f27d19 Guido Trotter
      message_timestamp = int(salt)
121 71f27d19 Guido Trotter
    except (ValueError, TypeError):
122 71f27d19 Guido Trotter
      msg = "non-integer timestamp: %s" % salt
123 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
124 71f27d19 Guido Trotter
125 71f27d19 Guido Trotter
    skew = abs(current_time - message_timestamp)
126 71f27d19 Guido Trotter
    if skew > constants.CONFD_MAX_CLOCK_SKEW:
127 71f27d19 Guido Trotter
      msg = "outside time range (skew: %d)" % skew
128 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
129 71f27d19 Guido Trotter
130 71f27d19 Guido Trotter
    try:
131 71f27d19 Guido Trotter
      request = objects.ConfdRequest.FromDict(message)
132 71f27d19 Guido Trotter
    except AttributeError, err:
133 71f27d19 Guido Trotter
      raise errors.ConfdRequestError('%s' % err)
134 71f27d19 Guido Trotter
135 71f27d19 Guido Trotter
    return request
136 71f27d19 Guido Trotter
137 71f27d19 Guido Trotter
  def ProcessRequest(self, request):
138 71f27d19 Guido Trotter
    """Process one ConfdRequest request, and produce an answer
139 71f27d19 Guido Trotter

140 71f27d19 Guido Trotter
    @type request: L{objects.ConfdRequest}
141 71f27d19 Guido Trotter
    @rtype: (L{objects.ConfdReply}, string)
142 71f27d19 Guido Trotter
    @return: tuple of reply and salt to add to the signature
143 71f27d19 Guido Trotter

144 71f27d19 Guido Trotter
    """
145 07b8a2b5 Iustin Pop
    logging.debug("Processing request: %s", request)
146 71f27d19 Guido Trotter
    if request.protocol != constants.CONFD_PROTOCOL_VERSION:
147 71f27d19 Guido Trotter
      msg = "wrong protocol version %d" % request.protocol
148 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
149 71f27d19 Guido Trotter
150 71f27d19 Guido Trotter
    if request.type not in constants.CONFD_REQS:
151 71f27d19 Guido Trotter
      msg = "wrong request type %d" % request.type
152 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
153 71f27d19 Guido Trotter
154 71f27d19 Guido Trotter
    rsalt = request.rsalt
155 71f27d19 Guido Trotter
    if not rsalt:
156 71f27d19 Guido Trotter
      msg = "missing requested salt"
157 71f27d19 Guido Trotter
      raise errors.ConfdRequestError(msg)
158 71f27d19 Guido Trotter
159 e16e4824 Guido Trotter
    query_object = self.DISPATCH_TABLE[request.type](self.reader)
160 e16e4824 Guido Trotter
    status, answer = query_object.Exec(request.query)
161 e16e4824 Guido Trotter
    reply = objects.ConfdReply(
162 e16e4824 Guido Trotter
              protocol=constants.CONFD_PROTOCOL_VERSION,
163 e16e4824 Guido Trotter
              status=status,
164 e16e4824 Guido Trotter
              answer=answer,
165 e16e4824 Guido Trotter
              serial=self.reader.GetConfigSerialNo(),
166 e16e4824 Guido Trotter
              )
167 71f27d19 Guido Trotter
168 07b8a2b5 Iustin Pop
    logging.debug("Sending reply: %s", reply)
169 71f27d19 Guido Trotter
170 71f27d19 Guido Trotter
    return (reply, rsalt)
171 71f27d19 Guido Trotter
172 71f27d19 Guido Trotter
  def PackReply(self, reply, rsalt):
173 71f27d19 Guido Trotter
    """Serialize and sign the given reply, with salt rsalt
174 71f27d19 Guido Trotter

175 71f27d19 Guido Trotter
    @type reply: L{objects.ConfdReply}
176 71f27d19 Guido Trotter
    @type rsalt: string
177 71f27d19 Guido Trotter

178 71f27d19 Guido Trotter
    """
179 71f27d19 Guido Trotter
    return serializer.DumpSigned(reply.ToDict(), self.hmac_key, rsalt)