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_MASTER_CANDIDATES,
59 constants.SS_MASTER_CANDIDATES_IPS,
60 constants.SS_MASTER_IP,
61 constants.SS_MASTER_NETDEV,
62 constants.SS_MASTER_NETMASK,
63 constants.SS_MASTER_NODE,
64 constants.SS_NODE_LIST,
65 constants.SS_NODE_PRIMARY_IPS,
66 constants.SS_NODE_SECONDARY_IPS,
67 constants.SS_OFFLINE_NODES,
68 constants.SS_ONLINE_NODES,
69 constants.SS_PRIMARY_IP_FAMILY,
70 constants.SS_INSTANCE_LIST,
71 constants.SS_RELEASE_VERSION,
72 constants.SS_HYPERVISOR_LIST,
73 constants.SS_MAINTAIN_NODE_HEALTH,
74 constants.SS_UID_POOL,
75 constants.SS_NODEGROUPS,
76 constants.SS_NETWORKS,
77 constants.SS_HVPARAMS_XEN_PVM,
78 constants.SS_HVPARAMS_XEN_FAKE,
79 constants.SS_HVPARAMS_XEN_HVM,
80 constants.SS_HVPARAMS_XEN_KVM,
81 constants.SS_HVPARAMS_XEN_CHROOT,
82 constants.SS_HVPARAMS_XEN_LXC,
83 ])
84
85
86 _MAX_SIZE = 128 * 1024
87
88
90 """Reads an ssconf file and verifies its size.
91
92 @type filename: string
93 @param filename: Path to file
94 @rtype: string
95 @return: File contents without newlines at the end
96 @raise RuntimeError: When the file size exceeds L{_MAX_SIZE}
97
98 """
99 statcb = utils.FileStatHelper()
100
101 data = utils.ReadFile(filename, size=_MAX_SIZE, preread=statcb)
102
103 if statcb.st.st_size > _MAX_SIZE:
104 msg = ("File '%s' has a size of %s bytes (up to %s allowed)" %
105 (filename, statcb.st.st_size, _MAX_SIZE))
106 raise RuntimeError(msg)
107
108 return data.rstrip("\n")
109
110
112 """Interface to static cluster data.
113
114 This is different that the config.ConfigWriter and
115 SimpleConfigReader classes in that it holds data that will always be
116 present, even on nodes which don't have all the cluster data.
117
118 Other particularities of the datastore:
119 - keys are restricted to predefined values
120
121 """
123 if cfg_location is None:
124 self._cfg_dir = pathutils.DATA_DIR
125 else:
126 self._cfg_dir = cfg_location
127
128 self._lockfile = _lockfile
129
140
142 """Generic routine to read keys.
143
144 This will read the file which holds the value requested. Errors
145 will be changed into ConfigurationErrors.
146
147 """
148 filename = self.KeyToFilename(key)
149 try:
150 return ReadSsconfFile(filename)
151 except EnvironmentError, err:
152 if err.errno == errno.ENOENT and default is not None:
153 return default
154 raise errors.ConfigurationError("Can't read ssconf file %s: %s" %
155 (filename, str(err)))
156
158 """Reads all keys and returns their values.
159
160 @rtype: dict
161 @return: Dictionary, ssconf key as key, value as value
162
163 """
164 result = []
165
166 for key in _VALID_KEYS:
167 try:
168 value = self._ReadFile(key)
169 except errors.ConfigurationError:
170
171 pass
172 else:
173 result.append((key, value))
174
175 return dict(result)
176
178 """Writes ssconf files used by external scripts.
179
180 @type values: dict
181 @param values: Dictionary of (name, value)
182 @type dry_run boolean
183 @param dry_run: Whether to perform a dry run
184
185 """
186 ssconf_lock = utils.FileLock.Open(self._lockfile)
187
188
189 ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
190 try:
191 for name, value in values.iteritems():
192 if value and not value.endswith("\n"):
193 value += "\n"
194
195 if len(value) > _MAX_SIZE:
196 msg = ("Value '%s' has a length of %s bytes, but only up to %s are"
197 " allowed" % (name, len(value), _MAX_SIZE))
198 raise errors.ConfigurationError(msg)
199
200 utils.WriteFile(self.KeyToFilename(name), data=value,
201 mode=constants.SS_FILE_PERMS,
202 dry_run=dry_run)
203 finally:
204 ssconf_lock.Unlock()
205
207 """Return the list of all config files.
208
209 This is used for computing node replication data.
210
211 """
212 return [self.KeyToFilename(key) for key in _VALID_KEYS]
213
219
225
231
239
247
253
259
270
276
284
292
300
308
316
324
332
340
342 """Return the hypervisor parameters of the given hypervisor.
343
344 @type hvname: string
345 @param hvname: name of the hypervisor, must be in C{constants.HYPER_TYPES}
346 @rtype: dict of strings
347 @returns: dictionary with hypervisor parameters
348
349 """
350 data = self._ReadFile(constants.SS_HVPARAMS_PREF + hvname)
351 lines = data.splitlines(False)
352 hvparams = {}
353 for line in lines:
354 (key, value) = line.split("=")
355 hvparams[key] = value
356 return hvparams
357
359 """Return the hypervisor parameters of all hypervisors.
360
361 @rtype: dict of dict of strings
362 @returns: dictionary mapping hypervisor names to hvparams
363
364 """
365 all_hvparams = {}
366 for hv in constants.HYPER_TYPES:
367 all_hvparams[hv] = self.GetHvparamsForHypervisor(hv)
368 return all_hvparams
369
371 """Return the value of the maintain_node_health option.
372
373 """
374 data = self._ReadFile(constants.SS_MAINTAIN_NODE_HEALTH)
375
376 return data == "True"
377
379 """Return the user-id pool definition string.
380
381 The separator character is a newline.
382
383 The return value can be parsed using uidpool.ParseUidPool()::
384
385 ss = ssconf.SimpleStore()
386 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
387
388 """
389 data = self._ReadFile(constants.SS_UID_POOL)
390 return data
391
402
403
405 """Update all ssconf files.
406
407 Wrapper around L{SimpleStore.WriteFiles}.
408
409 """
410 SimpleStore().WriteFiles(values, dry_run=dry_run)
411
412
414 """Get the master node and my own hostname.
415
416 This can be either used for a 'soft' check (compared to CheckMaster,
417 which exits) or just for computing both at the same time.
418
419 The function does not handle any errors, these should be handled in
420 the caller (errors.ConfigurationError, errors.ResolverError).
421
422 @param ss: either a sstore.SimpleConfigReader or a
423 sstore.SimpleStore instance
424 @rtype: tuple
425 @return: a tuple (master node name, my own name)
426
427 """
428 if ss is None:
429 ss = SimpleStore()
430 return ss.GetMasterNode(), netutils.Hostname.GetSysName()
431
432
453
454
456 """Verifies cluster name against a local cluster name.
457
458 @type name: string
459 @param name: Cluster name
460
461 """
462 sstore = SimpleStore(cfg_location=_cfg_location)
463
464 try:
465 local_name = sstore.GetClusterName()
466 except errors.ConfigurationError, err:
467 logging.debug("Can't get local cluster name: %s", err)
468 else:
469 if name != local_name:
470 raise errors.GenericError("Current cluster name is '%s'" % local_name)
471
472
474 """Raises an exception if unknown ssconf keys are given.
475
476 @type keys: sequence
477 @param keys: Key names to verify
478 @raise errors.GenericError: When invalid keys were found
479
480 """
481 invalid = frozenset(keys) - _VALID_KEYS
482 if invalid:
483 raise errors.GenericError("Invalid ssconf keys: %s" %
484 utils.CommaJoin(sorted(invalid)))
485