1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 """Global Configuration data for Ganeti.
32
33 This module provides the interface to a special case of cluster
34 configuration data, which is mostly static and available to all nodes.
35
36 """
37
38 import sys
39 import errno
40 import logging
41
42 from ganeti import compat
43 from ganeti import errors
44 from ganeti import constants
45 from ganeti import utils
46 from ganeti import netutils
47 from ganeti import pathutils
48
49
50 SSCONF_LOCK_TIMEOUT = 10
51
52
53 _VALID_KEYS = compat.UniqueFrozenset([
54 constants.SS_CLUSTER_NAME,
55 constants.SS_CLUSTER_TAGS,
56 constants.SS_FILE_STORAGE_DIR,
57 constants.SS_SHARED_FILE_STORAGE_DIR,
58 constants.SS_GLUSTER_STORAGE_DIR,
59 constants.SS_MASTER_CANDIDATES,
60 constants.SS_MASTER_CANDIDATES_IPS,
61 constants.SS_MASTER_CANDIDATES_CERTS,
62 constants.SS_MASTER_IP,
63 constants.SS_MASTER_NETDEV,
64 constants.SS_MASTER_NETMASK,
65 constants.SS_MASTER_NODE,
66 constants.SS_NODE_LIST,
67 constants.SS_NODE_PRIMARY_IPS,
68 constants.SS_NODE_SECONDARY_IPS,
69 constants.SS_NODE_VM_CAPABLE,
70 constants.SS_OFFLINE_NODES,
71 constants.SS_ONLINE_NODES,
72 constants.SS_PRIMARY_IP_FAMILY,
73 constants.SS_INSTANCE_LIST,
74 constants.SS_RELEASE_VERSION,
75 constants.SS_HYPERVISOR_LIST,
76 constants.SS_MAINTAIN_NODE_HEALTH,
77 constants.SS_UID_POOL,
78 constants.SS_NODEGROUPS,
79 constants.SS_NETWORKS,
80 constants.SS_HVPARAMS_XEN_PVM,
81 constants.SS_HVPARAMS_XEN_FAKE,
82 constants.SS_HVPARAMS_XEN_HVM,
83 constants.SS_HVPARAMS_XEN_KVM,
84 constants.SS_HVPARAMS_XEN_CHROOT,
85 constants.SS_HVPARAMS_XEN_LXC,
86 constants.SS_ENABLED_USER_SHUTDOWN,
87 ])
88
89
90 _MAX_SIZE = 128 * 1024
91
92
94 """Reads an ssconf file and verifies its size.
95
96 @type filename: string
97 @param filename: Path to file
98 @rtype: string
99 @return: File contents without newlines at the end
100 @raise RuntimeError: When the file size exceeds L{_MAX_SIZE}
101
102 """
103 statcb = utils.FileStatHelper()
104
105 data = utils.ReadFile(filename, size=_MAX_SIZE, preread=statcb)
106
107 if statcb.st.st_size > _MAX_SIZE:
108 msg = ("File '%s' has a size of %s bytes (up to %s allowed)" %
109 (filename, statcb.st.st_size, _MAX_SIZE))
110 raise RuntimeError(msg)
111
112 return data.rstrip("\n")
113
114
116 """Interface to static cluster data.
117
118 This is different that the config.ConfigWriter and
119 SimpleConfigReader classes in that it holds data that will always be
120 present, even on nodes which don't have all the cluster data.
121
122 Other particularities of the datastore:
123 - keys are restricted to predefined values
124
125 """
127 if cfg_location is None:
128 self._cfg_dir = pathutils.DATA_DIR
129 else:
130 self._cfg_dir = cfg_location
131
132 self._lockfile = _lockfile
133
144
146 """Generic routine to read keys.
147
148 This will read the file which holds the value requested. Errors
149 will be changed into ConfigurationErrors.
150
151 """
152 filename = self.KeyToFilename(key)
153 try:
154 return ReadSsconfFile(filename)
155 except EnvironmentError, err:
156 if err.errno == errno.ENOENT and default is not None:
157 return default
158 raise errors.ConfigurationError("Can't read ssconf file %s: %s" %
159 (filename, str(err)))
160
162 """Reads all keys and returns their values.
163
164 @rtype: dict
165 @return: Dictionary, ssconf key as key, value as value
166
167 """
168 result = []
169
170 for key in _VALID_KEYS:
171 try:
172 value = self._ReadFile(key)
173 except errors.ConfigurationError:
174
175 pass
176 else:
177 result.append((key, value))
178
179 return dict(result)
180
182 """Writes ssconf files used by external scripts.
183
184 @type values: dict
185 @param values: Dictionary of (name, value)
186 @type dry_run boolean
187 @param dry_run: Whether to perform a dry run
188
189 """
190 ssconf_lock = utils.FileLock.Open(self._lockfile)
191
192
193 ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
194 try:
195 for name, value in values.iteritems():
196 if value and not value.endswith("\n"):
197 value += "\n"
198
199 if len(value) > _MAX_SIZE:
200 msg = ("Value '%s' has a length of %s bytes, but only up to %s are"
201 " allowed" % (name, len(value), _MAX_SIZE))
202 raise errors.ConfigurationError(msg)
203
204 utils.WriteFile(self.KeyToFilename(name), data=value,
205 mode=constants.SS_FILE_PERMS,
206 dry_run=dry_run)
207 finally:
208 ssconf_lock.Unlock()
209
211 """Return the list of all config files.
212
213 This is used for computing node replication data.
214
215 """
216 return [self.KeyToFilename(key) for key in _VALID_KEYS]
217
223
229
235
241
249
257
259 """Returns the map of master candidate UUIDs to ssl cert.
260
261 @rtype: dict of string to string
262 @return: dictionary mapping the master candidates' UUIDs
263 to their SSL certificate digests
264
265 """
266 data = self._ReadFile(constants.SS_MASTER_CANDIDATES_CERTS)
267 lines = data.splitlines(False)
268 certs = {}
269 for line in lines:
270 (node_uuid, cert_digest) = line.split("=")
271 certs[node_uuid] = cert_digest
272 return certs
273
279
285
296
302
310
318
326
334
336 """Return the cluster nodes' vm capable value.
337
338 @rtype: dict of string to bool
339 @return: mapping of node names to vm capable values
340
341 """
342 data = self._ReadFile(constants.SS_NODE_VM_CAPABLE)
343 vm_capable = {}
344 for line in data.splitlines(False):
345 (node_uuid, node_vm_capable) = line.split("=")
346 vm_capable[node_uuid] = node_vm_capable == "True"
347 return vm_capable
348
356
364
372
380
382 """Return the hypervisor parameters of the given hypervisor.
383
384 @type hvname: string
385 @param hvname: name of the hypervisor, must be in C{constants.HYPER_TYPES}
386 @rtype: dict of strings
387 @returns: dictionary with hypervisor parameters
388
389 """
390 data = self._ReadFile(constants.SS_HVPARAMS_PREF + hvname)
391 lines = data.splitlines(False)
392 hvparams = {}
393 for line in lines:
394 (key, value) = line.split("=")
395 hvparams[key] = value
396 return hvparams
397
399 """Return the hypervisor parameters of all hypervisors.
400
401 @rtype: dict of dict of strings
402 @returns: dictionary mapping hypervisor names to hvparams
403
404 """
405 all_hvparams = {}
406 for hv in constants.HYPER_TYPES:
407 all_hvparams[hv] = self.GetHvparamsForHypervisor(hv)
408 return all_hvparams
409
411 """Return the value of the maintain_node_health option.
412
413 """
414 data = self._ReadFile(constants.SS_MAINTAIN_NODE_HEALTH)
415
416 return data == "True"
417
419 """Return the user-id pool definition string.
420
421 The separator character is a newline.
422
423 The return value can be parsed using uidpool.ParseUidPool()::
424
425 ss = ssconf.SimpleStore()
426 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
427
428 """
429 data = self._ReadFile(constants.SS_UID_POOL)
430 return data
431
442
444 """Return whether user shutdown is enabled.
445
446 @rtype: bool
447 @return: 'True' if user shutdown is enabled, 'False' otherwise
448
449 """
450 return self._ReadFile(constants.SS_ENABLED_USER_SHUTDOWN) == "True"
451
452
454 """Update all ssconf files.
455
456 Wrapper around L{SimpleStore.WriteFiles}.
457
458 """
459 SimpleStore().WriteFiles(values, dry_run=dry_run)
460
461
463 """Get the master node and my own hostname.
464
465 This can be either used for a 'soft' check (compared to CheckMaster,
466 which exits) or just for computing both at the same time.
467
468 The function does not handle any errors, these should be handled in
469 the caller (errors.ConfigurationError, errors.ResolverError).
470
471 @param ss: either a sstore.SimpleConfigReader or a
472 sstore.SimpleStore instance
473 @rtype: tuple
474 @return: a tuple (master node name, my own name)
475
476 """
477 if ss is None:
478 ss = SimpleStore()
479 return ss.GetMasterNode(), netutils.Hostname.GetSysName()
480
481
502
503
505 """Verifies cluster name against a local cluster name.
506
507 @type name: string
508 @param name: Cluster name
509
510 """
511 sstore = SimpleStore(cfg_location=_cfg_location)
512
513 try:
514 local_name = sstore.GetClusterName()
515 except errors.ConfigurationError, err:
516 logging.debug("Can't get local cluster name: %s", err)
517 else:
518 if name != local_name:
519 raise errors.GenericError("Current cluster name is '%s'" % local_name)
520
521
523 """Raises an exception if unknown ssconf keys are given.
524
525 @type keys: sequence
526 @param keys: Key names to verify
527 @raise errors.GenericError: When invalid keys were found
528
529 """
530 invalid = frozenset(keys) - _VALID_KEYS
531 if invalid:
532 raise errors.GenericError("Invalid ssconf keys: %s" %
533 utils.CommaJoin(sorted(invalid)))
534