1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Ganeti configuration daemon server library.
23
24 Ganeti-confd is a daemon to query master candidates for configuration values.
25 It uses UDP+HMAC for authentication with a global cluster key.
26
27 """
28
29 import logging
30 import time
31
32 from ganeti import constants
33 from ganeti import objects
34 from ganeti import errors
35 from ganeti import utils
36 from ganeti import serializer
37 from ganeti import ssconf
38
39 from ganeti.confd import querylib
40
41
43 """A processor for confd requests.
44
45 @ivar reader: confd SimpleConfigReader
46 @ivar disabled: whether confd serving is disabled
47
48 """
49 DISPATCH_TABLE = {
50 constants.CONFD_REQ_PING: querylib.PingQuery,
51 constants.CONFD_REQ_NODE_ROLE_BYNAME: querylib.NodeRoleQuery,
52 constants.CONFD_REQ_NODE_PIP_BY_INSTANCE_IP:
53 querylib.InstanceIpToNodePrimaryIpQuery,
54 constants.CONFD_REQ_CLUSTER_MASTER: querylib.ClusterMasterQuery,
55 constants.CONFD_REQ_NODE_PIP_LIST: querylib.NodesPipsQuery,
56 constants.CONFD_REQ_MC_PIP_LIST: querylib.MasterCandidatesPipsQuery,
57 constants.CONFD_REQ_INSTANCES_IPS_LIST: querylib.InstancesIpsQuery,
58 constants.CONFD_REQ_NODE_DRBD: querylib.NodeDrbdQuery,
59 }
60
71
79
81 self.disabled = True
82 self.reader = None
83
85 """Process a single UDP request from a client.
86
87 @type payload_in: string
88 @param payload_in: request raw data
89 @type ip: string
90 @param ip: source ip address
91 @param port: integer
92 @type port: source port
93
94 """
95 if self.disabled:
96 logging.debug("Confd is disabled. Ignoring query.")
97 return
98 try:
99 request = self.ExtractRequest(payload_in)
100 reply, rsalt = self.ProcessRequest(request)
101 payload_out = self.PackReply(reply, rsalt)
102 return payload_out
103 except errors.ConfdRequestError, err:
104 logging.info("Ignoring broken query from %s:%d: %s", ip, port, err)
105 return None
106
108 """Extracts a ConfdRequest object from a serialized hmac signed string.
109
110 This functions also performs signature/timestamp validation.
111
112 """
113 current_time = time.time()
114 logging.debug("Extracting request with size: %d", len(payload))
115 try:
116 (message, salt) = serializer.LoadSigned(payload, self.hmac_key)
117 except errors.SignatureError, err:
118 msg = "invalid signature: %s" % err
119 raise errors.ConfdRequestError(msg)
120 try:
121 message_timestamp = int(salt)
122 except (ValueError, TypeError):
123 msg = "non-integer timestamp: %s" % salt
124 raise errors.ConfdRequestError(msg)
125
126 skew = abs(current_time - message_timestamp)
127 if skew > constants.CONFD_MAX_CLOCK_SKEW:
128 msg = "outside time range (skew: %d)" % skew
129 raise errors.ConfdRequestError(msg)
130
131 try:
132 request = objects.ConfdRequest.FromDict(message)
133 except AttributeError, err:
134 raise errors.ConfdRequestError(str(err))
135
136 return request
137
139 """Process one ConfdRequest request, and produce an answer
140
141 @type request: L{objects.ConfdRequest}
142 @rtype: (L{objects.ConfdReply}, string)
143 @return: tuple of reply and salt to add to the signature
144
145 """
146 logging.debug("Processing request: %s", request)
147 if request.protocol != constants.CONFD_PROTOCOL_VERSION:
148 msg = "wrong protocol version %d" % request.protocol
149 raise errors.ConfdRequestError(msg)
150
151 if request.type not in constants.CONFD_REQS:
152 msg = "wrong request type %d" % request.type
153 raise errors.ConfdRequestError(msg)
154
155 rsalt = request.rsalt
156 if not rsalt:
157 msg = "missing requested salt"
158 raise errors.ConfdRequestError(msg)
159
160 query_object = self.DISPATCH_TABLE[request.type](self.reader)
161 status, answer = query_object.Exec(request.query)
162 reply = objects.ConfdReply(
163 protocol=constants.CONFD_PROTOCOL_VERSION,
164 status=status,
165 answer=answer,
166 serial=self.reader.GetConfigSerialNo(),
167 )
168
169 logging.debug("Sending reply: %s", reply)
170
171 return (reply, rsalt)
172
174 """Serialize and sign the given reply, with salt rsalt
175
176 @type reply: L{objects.ConfdReply}
177 @type rsalt: string
178
179 """
180 return serializer.DumpSigned(reply.ToDict(), self.hmac_key, rsalt)
181