1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Global Configuration data for Ganeti.
23
24 This module provides the interface to a special case of cluster
25 configuration data, which is mostly static and available to all nodes.
26
27 """
28
29 import sys
30 import errno
31 import logging
32
33 from ganeti import compat
34 from ganeti import errors
35 from ganeti import constants
36 from ganeti import utils
37 from ganeti import netutils
38 from ganeti import pathutils
39
40
41 SSCONF_LOCK_TIMEOUT = 10
42
43
44 _VALID_KEYS = compat.UniqueFrozenset([
45 constants.SS_CLUSTER_NAME,
46 constants.SS_CLUSTER_TAGS,
47 constants.SS_FILE_STORAGE_DIR,
48 constants.SS_SHARED_FILE_STORAGE_DIR,
49 constants.SS_MASTER_CANDIDATES,
50 constants.SS_MASTER_CANDIDATES_IPS,
51 constants.SS_MASTER_IP,
52 constants.SS_MASTER_NETDEV,
53 constants.SS_MASTER_NETMASK,
54 constants.SS_MASTER_NODE,
55 constants.SS_NODE_LIST,
56 constants.SS_NODE_PRIMARY_IPS,
57 constants.SS_NODE_SECONDARY_IPS,
58 constants.SS_OFFLINE_NODES,
59 constants.SS_ONLINE_NODES,
60 constants.SS_PRIMARY_IP_FAMILY,
61 constants.SS_INSTANCE_LIST,
62 constants.SS_RELEASE_VERSION,
63 constants.SS_HYPERVISOR_LIST,
64 constants.SS_MAINTAIN_NODE_HEALTH,
65 constants.SS_UID_POOL,
66 constants.SS_NODEGROUPS,
67 constants.SS_NETWORKS,
68 constants.SS_HVPARAMS_XEN_PVM,
69 constants.SS_HVPARAMS_XEN_FAKE,
70 constants.SS_HVPARAMS_XEN_HVM,
71 constants.SS_HVPARAMS_XEN_KVM,
72 constants.SS_HVPARAMS_XEN_CHROOT,
73 constants.SS_HVPARAMS_XEN_LXC,
74 ])
75
76
77 _MAX_SIZE = 128 * 1024
78
79
81 """Reads an ssconf file and verifies its size.
82
83 @type filename: string
84 @param filename: Path to file
85 @rtype: string
86 @return: File contents without newlines at the end
87 @raise RuntimeError: When the file size exceeds L{_MAX_SIZE}
88
89 """
90 statcb = utils.FileStatHelper()
91
92 data = utils.ReadFile(filename, size=_MAX_SIZE, preread=statcb)
93
94 if statcb.st.st_size > _MAX_SIZE:
95 msg = ("File '%s' has a size of %s bytes (up to %s allowed)" %
96 (filename, statcb.st.st_size, _MAX_SIZE))
97 raise RuntimeError(msg)
98
99 return data.rstrip("\n")
100
101
103 """Interface to static cluster data.
104
105 This is different that the config.ConfigWriter and
106 SimpleConfigReader classes in that it holds data that will always be
107 present, even on nodes which don't have all the cluster data.
108
109 Other particularities of the datastore:
110 - keys are restricted to predefined values
111
112 """
114 if cfg_location is None:
115 self._cfg_dir = pathutils.DATA_DIR
116 else:
117 self._cfg_dir = cfg_location
118
119 self._lockfile = _lockfile
120
131
133 """Generic routine to read keys.
134
135 This will read the file which holds the value requested. Errors
136 will be changed into ConfigurationErrors.
137
138 """
139 filename = self.KeyToFilename(key)
140 try:
141 return ReadSsconfFile(filename)
142 except EnvironmentError, err:
143 if err.errno == errno.ENOENT and default is not None:
144 return default
145 raise errors.ConfigurationError("Can't read ssconf file %s: %s" %
146 (filename, str(err)))
147
149 """Reads all keys and returns their values.
150
151 @rtype: dict
152 @return: Dictionary, ssconf key as key, value as value
153
154 """
155 result = []
156
157 for key in _VALID_KEYS:
158 try:
159 value = self._ReadFile(key)
160 except errors.ConfigurationError:
161
162 pass
163 else:
164 result.append((key, value))
165
166 return dict(result)
167
169 """Writes ssconf files used by external scripts.
170
171 @type values: dict
172 @param values: Dictionary of (name, value)
173 @type dry_run boolean
174 @param dry_run: Whether to perform a dry run
175
176 """
177 ssconf_lock = utils.FileLock.Open(self._lockfile)
178
179
180 ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
181 try:
182 for name, value in values.iteritems():
183 if value and not value.endswith("\n"):
184 value += "\n"
185
186 if len(value) > _MAX_SIZE:
187 msg = ("Value '%s' has a length of %s bytes, but only up to %s are"
188 " allowed" % (name, len(value), _MAX_SIZE))
189 raise errors.ConfigurationError(msg)
190
191 utils.WriteFile(self.KeyToFilename(name), data=value,
192 mode=constants.SS_FILE_PERMS,
193 dry_run=dry_run)
194 finally:
195 ssconf_lock.Unlock()
196
198 """Return the list of all config files.
199
200 This is used for computing node replication data.
201
202 """
203 return [self.KeyToFilename(key) for key in _VALID_KEYS]
204
210
216
222
230
238
244
250
261
267
275
283
291
299
307
315
323
325 """Return the hypervisor parameters of the given hypervisor.
326
327 @type hvname: string
328 @param hvname: name of the hypervisor, must be in C{constants.HYPER_TYPES}
329 @rtype: dict of strings
330 @returns: dictionary with hypervisor parameters
331
332 """
333 data = self._ReadFile(constants.SS_HVPARAMS_PREF + hvname)
334 lines = data.splitlines(False)
335 hvparams = {}
336 for line in lines:
337 (key, value) = line.split("=")
338 hvparams[key] = value
339 return hvparams
340
342 """Return the hypervisor parameters of all hypervisors.
343
344 @rtype: dict of dict of strings
345 @returns: dictionary mapping hypervisor names to hvparams
346
347 """
348 all_hvparams = {}
349 for hv in constants.HYPER_TYPES:
350 all_hvparams[hv] = self.GetHvparamsForHypervisor(hv)
351 return all_hvparams
352
354 """Return the value of the maintain_node_health option.
355
356 """
357 data = self._ReadFile(constants.SS_MAINTAIN_NODE_HEALTH)
358
359 return data == "True"
360
362 """Return the user-id pool definition string.
363
364 The separator character is a newline.
365
366 The return value can be parsed using uidpool.ParseUidPool()::
367
368 ss = ssconf.SimpleStore()
369 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
370
371 """
372 data = self._ReadFile(constants.SS_UID_POOL)
373 return data
374
385
386
388 """Update all ssconf files.
389
390 Wrapper around L{SimpleStore.WriteFiles}.
391
392 """
393 SimpleStore().WriteFiles(values, dry_run=dry_run)
394
395
397 """Get the master node and my own hostname.
398
399 This can be either used for a 'soft' check (compared to CheckMaster,
400 which exits) or just for computing both at the same time.
401
402 The function does not handle any errors, these should be handled in
403 the caller (errors.ConfigurationError, errors.ResolverError).
404
405 @param ss: either a sstore.SimpleConfigReader or a
406 sstore.SimpleStore instance
407 @rtype: tuple
408 @return: a tuple (master node name, my own name)
409
410 """
411 if ss is None:
412 ss = SimpleStore()
413 return ss.GetMasterNode(), netutils.Hostname.GetSysName()
414
415
436
437
439 """Verifies cluster name against a local cluster name.
440
441 @type name: string
442 @param name: Cluster name
443
444 """
445 sstore = SimpleStore(cfg_location=_cfg_location)
446
447 try:
448 local_name = sstore.GetClusterName()
449 except errors.ConfigurationError, err:
450 logging.debug("Can't get local cluster name: %s", err)
451 else:
452 if name != local_name:
453 raise errors.GenericError("Current cluster name is '%s'" % local_name)
454
455
457 """Raises an exception if unknown ssconf keys are given.
458
459 @type keys: sequence
460 @param keys: Key names to verify
461 @raise errors.GenericError: When invalid keys were found
462
463 """
464 invalid = frozenset(keys) - _VALID_KEYS
465 if invalid:
466 raise errors.GenericError("Invalid ssconf keys: %s" %
467 utils.CommaJoin(sorted(invalid)))
468