Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ 23f06b2b

History | View | Annotate | Download (7.9 kB)

1 2f31098c Iustin Pop
#
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 856c67e1 Michael Hanselmann
# Copyright (C) 2006, 2007, 2008 Google Inc.
5 a8083063 Iustin Pop
#
6 a8083063 Iustin Pop
# This program is free software; you can redistribute it and/or modify
7 a8083063 Iustin Pop
# it under the terms of the GNU General Public License as published by
8 a8083063 Iustin Pop
# the Free Software Foundation; either version 2 of the License, or
9 a8083063 Iustin Pop
# (at your option) any later version.
10 a8083063 Iustin Pop
#
11 a8083063 Iustin Pop
# This program is distributed in the hope that it will be useful, but
12 a8083063 Iustin Pop
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 a8083063 Iustin Pop
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 a8083063 Iustin Pop
# General Public License for more details.
15 a8083063 Iustin Pop
#
16 a8083063 Iustin Pop
# You should have received a copy of the GNU General Public License
17 a8083063 Iustin Pop
# along with this program; if not, write to the Free Software
18 a8083063 Iustin Pop
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 a8083063 Iustin Pop
# 02110-1301, USA.
20 a8083063 Iustin Pop
21 a8083063 Iustin Pop
22 a8083063 Iustin Pop
"""Global Configuration data for Ganeti.
23 a8083063 Iustin Pop

24 a8083063 Iustin Pop
This module provides the interface to a special case of cluster
25 a8083063 Iustin Pop
configuration data, which is mostly static and available to all nodes.
26 a8083063 Iustin Pop

27 a8083063 Iustin Pop
"""
28 a8083063 Iustin Pop
29 5675cd1f Iustin Pop
import sys
30 03d1dba2 Michael Hanselmann
import re
31 a8083063 Iustin Pop
32 a8083063 Iustin Pop
from ganeti import errors
33 a8083063 Iustin Pop
from ganeti import constants
34 41a57aab Michael Hanselmann
from ganeti import utils
35 856c67e1 Michael Hanselmann
from ganeti import serializer
36 a8083063 Iustin Pop
37 a8083063 Iustin Pop
38 0c223ea9 Michael Hanselmann
SSCONF_LOCK_TIMEOUT = 10
39 0c223ea9 Michael Hanselmann
40 03d1dba2 Michael Hanselmann
RE_VALID_SSCONF_NAME = re.compile(r'^[-_a-z0-9]+$')
41 03d1dba2 Michael Hanselmann
42 0c223ea9 Michael Hanselmann
43 02f99608 Oleksiy Mishchenko
class SimpleConfigReader(object):
44 856c67e1 Michael Hanselmann
  """Simple class to read configuration file.
45 856c67e1 Michael Hanselmann

46 856c67e1 Michael Hanselmann
  """
47 856c67e1 Michael Hanselmann
  def __init__(self, file_name=constants.CLUSTER_CONF_FILE):
48 856c67e1 Michael Hanselmann
    """Initializes this class.
49 856c67e1 Michael Hanselmann

50 856c67e1 Michael Hanselmann
    @type file_name: string
51 856c67e1 Michael Hanselmann
    @param file_name: Configuration file path
52 856c67e1 Michael Hanselmann

53 856c67e1 Michael Hanselmann
    """
54 856c67e1 Michael Hanselmann
    self._file_name = file_name
55 856c67e1 Michael Hanselmann
    self._config_data = serializer.Load(utils.ReadFile(file_name))
56 856c67e1 Michael Hanselmann
    # TODO: Error handling
57 856c67e1 Michael Hanselmann
58 856c67e1 Michael Hanselmann
  def GetClusterName(self):
59 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["cluster_name"]
60 856c67e1 Michael Hanselmann
61 856c67e1 Michael Hanselmann
  def GetHostKey(self):
62 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["rsahostkeypub"]
63 856c67e1 Michael Hanselmann
64 856c67e1 Michael Hanselmann
  def GetMasterNode(self):
65 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_node"]
66 856c67e1 Michael Hanselmann
67 856c67e1 Michael Hanselmann
  def GetMasterIP(self):
68 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_ip"]
69 856c67e1 Michael Hanselmann
70 856c67e1 Michael Hanselmann
  def GetMasterNetdev(self):
71 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_netdev"]
72 856c67e1 Michael Hanselmann
73 856c67e1 Michael Hanselmann
  def GetFileStorageDir(self):
74 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["file_storage_dir"]
75 856c67e1 Michael Hanselmann
76 856c67e1 Michael Hanselmann
  def GetHypervisorType(self):
77 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["hypervisor"]
78 856c67e1 Michael Hanselmann
79 856c67e1 Michael Hanselmann
  def GetNodeList(self):
80 856c67e1 Michael Hanselmann
    return self._config_data["nodes"].keys()
81 856c67e1 Michael Hanselmann
82 02f99608 Oleksiy Mishchenko
  @classmethod
83 02f99608 Oleksiy Mishchenko
  def FromDict(cls, val, cfg_file=constants.CLUSTER_CONF_FILE):
84 02f99608 Oleksiy Mishchenko
    """Alternative construction from a dictionary.
85 02f99608 Oleksiy Mishchenko

86 02f99608 Oleksiy Mishchenko
    """
87 02f99608 Oleksiy Mishchenko
    obj = SimpleConfigReader.__new__(cls)
88 02f99608 Oleksiy Mishchenko
    obj._config_data = val
89 02f99608 Oleksiy Mishchenko
    obj._file_name = cfg_file
90 02f99608 Oleksiy Mishchenko
    return obj
91 02f99608 Oleksiy Mishchenko
92 856c67e1 Michael Hanselmann
93 856c67e1 Michael Hanselmann
class SimpleConfigWriter(SimpleConfigReader):
94 856c67e1 Michael Hanselmann
  """Simple class to write configuration file.
95 856c67e1 Michael Hanselmann

96 856c67e1 Michael Hanselmann
  """
97 856c67e1 Michael Hanselmann
  def SetMasterNode(self, node):
98 856c67e1 Michael Hanselmann
    """Change master node.
99 856c67e1 Michael Hanselmann

100 856c67e1 Michael Hanselmann
    """
101 856c67e1 Michael Hanselmann
    self._config_data["cluster"]["master_node"] = node
102 856c67e1 Michael Hanselmann
103 856c67e1 Michael Hanselmann
  def Save(self):
104 856c67e1 Michael Hanselmann
    """Writes configuration file.
105 856c67e1 Michael Hanselmann

106 856c67e1 Michael Hanselmann
    Warning: Doesn't take care of locking or synchronizing with other
107 856c67e1 Michael Hanselmann
    processes.
108 856c67e1 Michael Hanselmann

109 856c67e1 Michael Hanselmann
    """
110 856c67e1 Michael Hanselmann
    utils.WriteFile(self._file_name,
111 856c67e1 Michael Hanselmann
                    data=serializer.Dump(self._config_data),
112 856c67e1 Michael Hanselmann
                    mode=0600)
113 856c67e1 Michael Hanselmann
114 856c67e1 Michael Hanselmann
115 93384844 Iustin Pop
class SimpleStore(object):
116 93384844 Iustin Pop
  """Interface to static cluster data.
117 93384844 Iustin Pop

118 93384844 Iustin Pop
  This is different that the config.ConfigWriter and
119 93384844 Iustin Pop
  SimpleConfigReader classes in that it holds data that will always be
120 93384844 Iustin Pop
  present, even on nodes which don't have all the cluster data.
121 93384844 Iustin Pop

122 93384844 Iustin Pop
  Other particularities of the datastore:
123 93384844 Iustin Pop
    - keys are restricted to predefined values
124 93384844 Iustin Pop

125 93384844 Iustin Pop
  """
126 93384844 Iustin Pop
  _SS_FILEPREFIX = "ssconf_"
127 93384844 Iustin Pop
  _VALID_KEYS = (
128 93384844 Iustin Pop
    constants.SS_CLUSTER_NAME,
129 5d60b3bd Iustin Pop
    constants.SS_CLUSTER_TAGS,
130 93384844 Iustin Pop
    constants.SS_FILE_STORAGE_DIR,
131 f56618e0 Iustin Pop
    constants.SS_MASTER_CANDIDATES,
132 93384844 Iustin Pop
    constants.SS_MASTER_IP,
133 93384844 Iustin Pop
    constants.SS_MASTER_NETDEV,
134 93384844 Iustin Pop
    constants.SS_MASTER_NODE,
135 93384844 Iustin Pop
    constants.SS_NODE_LIST,
136 a3316e4a Iustin Pop
    constants.SS_OFFLINE_NODES,
137 81a49123 Iustin Pop
    constants.SS_ONLINE_NODES,
138 81a49123 Iustin Pop
    constants.SS_INSTANCE_LIST,
139 8a113c7a Iustin Pop
    constants.SS_RELEASE_VERSION,
140 93384844 Iustin Pop
    )
141 93384844 Iustin Pop
  _MAX_SIZE = 131072
142 93384844 Iustin Pop
143 93384844 Iustin Pop
  def __init__(self, cfg_location=None):
144 93384844 Iustin Pop
    if cfg_location is None:
145 93384844 Iustin Pop
      self._cfg_dir = constants.DATA_DIR
146 93384844 Iustin Pop
    else:
147 93384844 Iustin Pop
      self._cfg_dir = cfg_location
148 93384844 Iustin Pop
149 93384844 Iustin Pop
  def KeyToFilename(self, key):
150 93384844 Iustin Pop
    """Convert a given key into filename.
151 93384844 Iustin Pop

152 93384844 Iustin Pop
    """
153 93384844 Iustin Pop
    if key not in self._VALID_KEYS:
154 93384844 Iustin Pop
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
155 93384844 Iustin Pop
                                   % str(key))
156 93384844 Iustin Pop
157 93384844 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
158 93384844 Iustin Pop
    return filename
159 93384844 Iustin Pop
160 93384844 Iustin Pop
  def _ReadFile(self, key):
161 93384844 Iustin Pop
    """Generic routine to read keys.
162 93384844 Iustin Pop

163 93384844 Iustin Pop
    This will read the file which holds the value requested. Errors
164 93384844 Iustin Pop
    will be changed into ConfigurationErrors.
165 93384844 Iustin Pop

166 93384844 Iustin Pop
    """
167 93384844 Iustin Pop
    filename = self.KeyToFilename(key)
168 93384844 Iustin Pop
    try:
169 93384844 Iustin Pop
      fh = file(filename, 'r')
170 93384844 Iustin Pop
      try:
171 93384844 Iustin Pop
        data = fh.read(self._MAX_SIZE)
172 93384844 Iustin Pop
        data = data.rstrip('\n')
173 93384844 Iustin Pop
      finally:
174 93384844 Iustin Pop
        fh.close()
175 93384844 Iustin Pop
    except EnvironmentError, err:
176 93384844 Iustin Pop
      raise errors.ConfigurationError("Can't read from the ssconf file:"
177 93384844 Iustin Pop
                                      " '%s'" % str(err))
178 93384844 Iustin Pop
    return data
179 93384844 Iustin Pop
180 89b14f05 Iustin Pop
  def WriteFiles(self, values):
181 89b14f05 Iustin Pop
    """Writes ssconf files used by external scripts.
182 89b14f05 Iustin Pop

183 89b14f05 Iustin Pop
    @type values: dict
184 89b14f05 Iustin Pop
    @param values: Dictionary of (name, value)
185 89b14f05 Iustin Pop

186 89b14f05 Iustin Pop
    """
187 89b14f05 Iustin Pop
    ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE)
188 89b14f05 Iustin Pop
189 89b14f05 Iustin Pop
    # Get lock while writing files
190 89b14f05 Iustin Pop
    ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
191 89b14f05 Iustin Pop
    try:
192 89b14f05 Iustin Pop
      for name, value in values.iteritems():
193 02b31f32 Iustin Pop
        if value and not value.endswith("\n"):
194 89b14f05 Iustin Pop
          value += "\n"
195 81a49123 Iustin Pop
        utils.WriteFile(self.KeyToFilename(name), data=value, mode=0444)
196 89b14f05 Iustin Pop
    finally:
197 89b14f05 Iustin Pop
      ssconf_lock.Unlock()
198 89b14f05 Iustin Pop
199 93384844 Iustin Pop
  def GetFileList(self):
200 93384844 Iustin Pop
    """Return the list of all config files.
201 93384844 Iustin Pop

202 93384844 Iustin Pop
    This is used for computing node replication data.
203 93384844 Iustin Pop

204 93384844 Iustin Pop
    """
205 93384844 Iustin Pop
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
206 93384844 Iustin Pop
207 93384844 Iustin Pop
  def GetClusterName(self):
208 93384844 Iustin Pop
    """Get the cluster name.
209 93384844 Iustin Pop

210 93384844 Iustin Pop
    """
211 93384844 Iustin Pop
    return self._ReadFile(constants.SS_CLUSTER_NAME)
212 93384844 Iustin Pop
213 93384844 Iustin Pop
  def GetFileStorageDir(self):
214 93384844 Iustin Pop
    """Get the file storage dir.
215 93384844 Iustin Pop

216 93384844 Iustin Pop
    """
217 93384844 Iustin Pop
    return self._ReadFile(constants.SS_FILE_STORAGE_DIR)
218 93384844 Iustin Pop
219 f56618e0 Iustin Pop
  def GetMasterCandidates(self):
220 f56618e0 Iustin Pop
    """Return the list of master candidates.
221 f56618e0 Iustin Pop

222 f56618e0 Iustin Pop
    """
223 f56618e0 Iustin Pop
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES)
224 f56618e0 Iustin Pop
    nl = data.splitlines(False)
225 f56618e0 Iustin Pop
    return nl
226 f56618e0 Iustin Pop
227 93384844 Iustin Pop
  def GetMasterIP(self):
228 93384844 Iustin Pop
    """Get the IP of the master node for this cluster.
229 93384844 Iustin Pop

230 93384844 Iustin Pop
    """
231 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_IP)
232 93384844 Iustin Pop
233 93384844 Iustin Pop
  def GetMasterNetdev(self):
234 93384844 Iustin Pop
    """Get the netdev to which we'll add the master ip.
235 93384844 Iustin Pop

236 93384844 Iustin Pop
    """
237 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NETDEV)
238 93384844 Iustin Pop
239 93384844 Iustin Pop
  def GetMasterNode(self):
240 93384844 Iustin Pop
    """Get the hostname of the master node for this cluster.
241 93384844 Iustin Pop

242 93384844 Iustin Pop
    """
243 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NODE)
244 93384844 Iustin Pop
245 93384844 Iustin Pop
  def GetNodeList(self):
246 93384844 Iustin Pop
    """Return the list of cluster nodes.
247 93384844 Iustin Pop

248 93384844 Iustin Pop
    """
249 93384844 Iustin Pop
    data = self._ReadFile(constants.SS_NODE_LIST)
250 93384844 Iustin Pop
    nl = data.splitlines(False)
251 93384844 Iustin Pop
    return nl
252 93384844 Iustin Pop
253 25e39bfa Iustin Pop
  def GetClusterTags(self):
254 25e39bfa Iustin Pop
    """Return the cluster tags.
255 25e39bfa Iustin Pop

256 25e39bfa Iustin Pop
    """
257 25e39bfa Iustin Pop
    data = self._ReadFile(constants.SS_CLUSTER_TAGS)
258 25e39bfa Iustin Pop
    nl = data.splitlines(False)
259 25e39bfa Iustin Pop
    return nl
260 25e39bfa Iustin Pop
261 93384844 Iustin Pop
262 b33e986b Iustin Pop
def GetMasterAndMyself(ss=None):
263 b33e986b Iustin Pop
  """Get the master node and my own hostname.
264 b33e986b Iustin Pop

265 b33e986b Iustin Pop
  This can be either used for a 'soft' check (compared to CheckMaster,
266 b33e986b Iustin Pop
  which exits) or just for computing both at the same time.
267 b33e986b Iustin Pop

268 b33e986b Iustin Pop
  The function does not handle any errors, these should be handled in
269 b33e986b Iustin Pop
  the caller (errors.ConfigurationError, errors.ResolverError).
270 b33e986b Iustin Pop

271 8135a2db Iustin Pop
  @param ss: either a sstore.SimpleConfigReader or a
272 8135a2db Iustin Pop
      sstore.SimpleStore instance
273 8135a2db Iustin Pop
  @rtype: tuple
274 8135a2db Iustin Pop
  @return: a tuple (master node name, my own name)
275 8135a2db Iustin Pop

276 b33e986b Iustin Pop
  """
277 b33e986b Iustin Pop
  if ss is None:
278 93384844 Iustin Pop
    ss = SimpleStore()
279 b33e986b Iustin Pop
  return ss.GetMasterNode(), utils.HostInfo().name
280 b33e986b Iustin Pop
281 06dc5b44 Iustin Pop
282 b33e986b Iustin Pop
def CheckMaster(debug, ss=None):
283 5675cd1f Iustin Pop
  """Checks the node setup.
284 5675cd1f Iustin Pop

285 5675cd1f Iustin Pop
  If this is the master, the function will return. Otherwise it will
286 5675cd1f Iustin Pop
  exit with an exit code based on the node status.
287 5675cd1f Iustin Pop

288 5675cd1f Iustin Pop
  """
289 5675cd1f Iustin Pop
  try:
290 b33e986b Iustin Pop
    master_name, myself = GetMasterAndMyself(ss)
291 5675cd1f Iustin Pop
  except errors.ConfigurationError, err:
292 5675cd1f Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
293 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
294 5675cd1f Iustin Pop
  except errors.ResolverError, err:
295 5675cd1f Iustin Pop
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
296 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
297 5675cd1f Iustin Pop
298 b33e986b Iustin Pop
  if myself != master_name:
299 5675cd1f Iustin Pop
    if debug:
300 5675cd1f Iustin Pop
      sys.stderr.write("Not master, exiting.\n")
301 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NOTMASTER)