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 }
59
70
78
80 self.disabled = True
81 self.reader = None
82
84 """Process a single UDP request from a client.
85
86 @type payload_in: string
87 @param payload_in: request raw data
88 @type ip: string
89 @param ip: source ip address
90 @param port: integer
91 @type port: source port
92
93 """
94 if self.disabled:
95 logging.debug('Confd is disabled. Ignoring query.')
96 return
97 try:
98 request = self.ExtractRequest(payload_in)
99 reply, rsalt = self.ProcessRequest(request)
100 payload_out = self.PackReply(reply, rsalt)
101 return payload_out
102 except errors.ConfdRequestError, err:
103 logging.info('Ignoring broken query from %s:%d: %s', ip, port, err)
104 return None
105
107 """Extracts a ConfdRequest object from a serialized hmac signed string.
108
109 This functions also performs signature/timestamp validation.
110
111 """
112 current_time = time.time()
113 logging.debug("Extracting request with size: %d", len(payload))
114 try:
115 (message, salt) = serializer.LoadSigned(payload, self.hmac_key)
116 except errors.SignatureError, err:
117 msg = "invalid signature: %s" % err
118 raise errors.ConfdRequestError(msg)
119 try:
120 message_timestamp = int(salt)
121 except (ValueError, TypeError):
122 msg = "non-integer timestamp: %s" % salt
123 raise errors.ConfdRequestError(msg)
124
125 skew = abs(current_time - message_timestamp)
126 if skew > constants.CONFD_MAX_CLOCK_SKEW:
127 msg = "outside time range (skew: %d)" % skew
128 raise errors.ConfdRequestError(msg)
129
130 try:
131 request = objects.ConfdRequest.FromDict(message)
132 except AttributeError, err:
133 raise errors.ConfdRequestError('%s' % err)
134
135 return request
136
138 """Process one ConfdRequest request, and produce an answer
139
140 @type request: L{objects.ConfdRequest}
141 @rtype: (L{objects.ConfdReply}, string)
142 @return: tuple of reply and salt to add to the signature
143
144 """
145 logging.debug("Processing request: %s", request)
146 if request.protocol != constants.CONFD_PROTOCOL_VERSION:
147 msg = "wrong protocol version %d" % request.protocol
148 raise errors.ConfdRequestError(msg)
149
150 if request.type not in constants.CONFD_REQS:
151 msg = "wrong request type %d" % request.type
152 raise errors.ConfdRequestError(msg)
153
154 rsalt = request.rsalt
155 if not rsalt:
156 msg = "missing requested salt"
157 raise errors.ConfdRequestError(msg)
158
159 query_object = self.DISPATCH_TABLE[request.type](self.reader)
160 status, answer = query_object.Exec(request.query)
161 reply = objects.ConfdReply(
162 protocol=constants.CONFD_PROTOCOL_VERSION,
163 status=status,
164 answer=answer,
165 serial=self.reader.GetConfigSerialNo(),
166 )
167
168 logging.debug("Sending reply: %s", reply)
169
170 return (reply, rsalt)
171
173 """Serialize and sign the given reply, with salt rsalt
174
175 @type reply: L{objects.ConfdReply}
176 @type rsalt: string
177
178 """
179 return serializer.DumpSigned(reply.ToDict(), self.hmac_key, rsalt)
180