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 ])
69
70
71 _MAX_SIZE = 128 * 1024
72
73
75 """Reads an ssconf file and verifies its size.
76
77 @type filename: string
78 @param filename: Path to file
79 @rtype: string
80 @return: File contents without newlines at the end
81 @raise RuntimeError: When the file size exceeds L{_MAX_SIZE}
82
83 """
84 statcb = utils.FileStatHelper()
85
86 data = utils.ReadFile(filename, size=_MAX_SIZE, preread=statcb)
87
88 if statcb.st.st_size > _MAX_SIZE:
89 msg = ("File '%s' has a size of %s bytes (up to %s allowed)" %
90 (filename, statcb.st.st_size, _MAX_SIZE))
91 raise RuntimeError(msg)
92
93 return data.rstrip("\n")
94
95
97 """Interface to static cluster data.
98
99 This is different that the config.ConfigWriter and
100 SimpleConfigReader classes in that it holds data that will always be
101 present, even on nodes which don't have all the cluster data.
102
103 Other particularities of the datastore:
104 - keys are restricted to predefined values
105
106 """
108 if cfg_location is None:
109 self._cfg_dir = pathutils.DATA_DIR
110 else:
111 self._cfg_dir = cfg_location
112
113 self._lockfile = _lockfile
114
125
127 """Generic routine to read keys.
128
129 This will read the file which holds the value requested. Errors
130 will be changed into ConfigurationErrors.
131
132 """
133 filename = self.KeyToFilename(key)
134 try:
135 return ReadSsconfFile(filename)
136 except EnvironmentError, err:
137 if err.errno == errno.ENOENT and default is not None:
138 return default
139 raise errors.ConfigurationError("Can't read ssconf file %s: %s" %
140 (filename, str(err)))
141
143 """Reads all keys and returns their values.
144
145 @rtype: dict
146 @return: Dictionary, ssconf key as key, value as value
147
148 """
149 result = []
150
151 for key in _VALID_KEYS:
152 try:
153 value = self._ReadFile(key)
154 except errors.ConfigurationError:
155
156 pass
157 else:
158 result.append((key, value))
159
160 return dict(result)
161
163 """Writes ssconf files used by external scripts.
164
165 @type values: dict
166 @param values: Dictionary of (name, value)
167 @type dry_run boolean
168 @param dry_run: Whether to perform a dry run
169
170 """
171 ssconf_lock = utils.FileLock.Open(self._lockfile)
172
173
174 ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
175 try:
176 for name, value in values.iteritems():
177 if value and not value.endswith("\n"):
178 value += "\n"
179
180 if len(value) > _MAX_SIZE:
181 msg = ("Value '%s' has a length of %s bytes, but only up to %s are"
182 " allowed" % (name, len(value), _MAX_SIZE))
183 raise errors.ConfigurationError(msg)
184
185 utils.WriteFile(self.KeyToFilename(name), data=value,
186 mode=constants.SS_FILE_PERMS,
187 dry_run=dry_run)
188 finally:
189 ssconf_lock.Unlock()
190
192 """Return the list of all config files.
193
194 This is used for computing node replication data.
195
196 """
197 return [self.KeyToFilename(key) for key in _VALID_KEYS]
198
204
210
216
224
232
238
244
255
261
269
277
285
293
301
309
317
319 """Return the value of the maintain_node_health option.
320
321 """
322 data = self._ReadFile(constants.SS_MAINTAIN_NODE_HEALTH)
323
324 return data == "True"
325
327 """Return the user-id pool definition string.
328
329 The separator character is a newline.
330
331 The return value can be parsed using uidpool.ParseUidPool()::
332
333 ss = ssconf.SimpleStore()
334 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\\n")
335
336 """
337 data = self._ReadFile(constants.SS_UID_POOL)
338 return data
339
350
351
353 """Update all ssconf files.
354
355 Wrapper around L{SimpleStore.WriteFiles}.
356
357 """
358 SimpleStore().WriteFiles(values, dry_run=dry_run)
359
360
362 """Get the master node and my own hostname.
363
364 This can be either used for a 'soft' check (compared to CheckMaster,
365 which exits) or just for computing both at the same time.
366
367 The function does not handle any errors, these should be handled in
368 the caller (errors.ConfigurationError, errors.ResolverError).
369
370 @param ss: either a sstore.SimpleConfigReader or a
371 sstore.SimpleStore instance
372 @rtype: tuple
373 @return: a tuple (master node name, my own name)
374
375 """
376 if ss is None:
377 ss = SimpleStore()
378 return ss.GetMasterNode(), netutils.Hostname.GetSysName()
379
380
401
402
404 """Verifies cluster name against a local cluster name.
405
406 @type name: string
407 @param name: Cluster name
408
409 """
410 sstore = SimpleStore(cfg_location=_cfg_location)
411
412 try:
413 local_name = sstore.GetClusterName()
414 except errors.ConfigurationError, err:
415 logging.debug("Can't get local cluster name: %s", err)
416 else:
417 if name != local_name:
418 raise errors.GenericError("Current cluster name is '%s'" % local_name)
419
420
422 """Raises an exception if unknown ssconf keys are given.
423
424 @type keys: sequence
425 @param keys: Key names to verify
426 @raise errors.GenericError: When invalid keys were found
427
428 """
429 invalid = frozenset(keys) - _VALID_KEYS
430 if invalid:
431 raise errors.GenericError("Invalid ssconf keys: %s" %
432 utils.CommaJoin(sorted(invalid)))
433