Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ 1fe93c75

History | View | Annotate | Download (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 1fe93c75 Guido Trotter
    self.Reload()
56 1fe93c75 Guido Trotter
57 1fe93c75 Guido Trotter
  def Reload(self):
58 1fe93c75 Guido Trotter
    """Reloads the config file.
59 1fe93c75 Guido Trotter

60 1fe93c75 Guido Trotter
    """
61 01cf7dbe Guido Trotter
    try:
62 1fe93c75 Guido Trotter
      self._config_data = serializer.Load(utils.ReadFile(self._file_name))
63 01cf7dbe Guido Trotter
    except IOError, err:
64 01cf7dbe Guido Trotter
      raise errors.ConfigurationError("Cannot read config file %s: %s" %
65 1fe93c75 Guido Trotter
                                      (self._file_name, err))
66 01cf7dbe Guido Trotter
    except ValueError, err:
67 01cf7dbe Guido Trotter
      raise errors.ConfigurationError("Cannot load config file %s: %s" %
68 1fe93c75 Guido Trotter
                                      (self._file_name, err))
69 856c67e1 Michael Hanselmann
70 856c67e1 Michael Hanselmann
  def GetClusterName(self):
71 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["cluster_name"]
72 856c67e1 Michael Hanselmann
73 856c67e1 Michael Hanselmann
  def GetHostKey(self):
74 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["rsahostkeypub"]
75 856c67e1 Michael Hanselmann
76 856c67e1 Michael Hanselmann
  def GetMasterNode(self):
77 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_node"]
78 856c67e1 Michael Hanselmann
79 856c67e1 Michael Hanselmann
  def GetMasterIP(self):
80 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_ip"]
81 856c67e1 Michael Hanselmann
82 856c67e1 Michael Hanselmann
  def GetMasterNetdev(self):
83 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_netdev"]
84 856c67e1 Michael Hanselmann
85 856c67e1 Michael Hanselmann
  def GetFileStorageDir(self):
86 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["file_storage_dir"]
87 856c67e1 Michael Hanselmann
88 856c67e1 Michael Hanselmann
  def GetHypervisorType(self):
89 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["hypervisor"]
90 856c67e1 Michael Hanselmann
91 856c67e1 Michael Hanselmann
  def GetNodeList(self):
92 856c67e1 Michael Hanselmann
    return self._config_data["nodes"].keys()
93 856c67e1 Michael Hanselmann
94 856c67e1 Michael Hanselmann
95 93384844 Iustin Pop
class SimpleStore(object):
96 93384844 Iustin Pop
  """Interface to static cluster data.
97 93384844 Iustin Pop

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

102 93384844 Iustin Pop
  Other particularities of the datastore:
103 93384844 Iustin Pop
    - keys are restricted to predefined values
104 93384844 Iustin Pop

105 93384844 Iustin Pop
  """
106 93384844 Iustin Pop
  _SS_FILEPREFIX = "ssconf_"
107 93384844 Iustin Pop
  _VALID_KEYS = (
108 93384844 Iustin Pop
    constants.SS_CLUSTER_NAME,
109 5d60b3bd Iustin Pop
    constants.SS_CLUSTER_TAGS,
110 93384844 Iustin Pop
    constants.SS_FILE_STORAGE_DIR,
111 f56618e0 Iustin Pop
    constants.SS_MASTER_CANDIDATES,
112 8113a52e Luca Bigliardi
    constants.SS_MASTER_CANDIDATES_IPS,
113 93384844 Iustin Pop
    constants.SS_MASTER_IP,
114 93384844 Iustin Pop
    constants.SS_MASTER_NETDEV,
115 93384844 Iustin Pop
    constants.SS_MASTER_NODE,
116 93384844 Iustin Pop
    constants.SS_NODE_LIST,
117 f9780ccd Luca Bigliardi
    constants.SS_NODE_PRIMARY_IPS,
118 f9780ccd Luca Bigliardi
    constants.SS_NODE_SECONDARY_IPS,
119 a3316e4a Iustin Pop
    constants.SS_OFFLINE_NODES,
120 81a49123 Iustin Pop
    constants.SS_ONLINE_NODES,
121 81a49123 Iustin Pop
    constants.SS_INSTANCE_LIST,
122 8a113c7a Iustin Pop
    constants.SS_RELEASE_VERSION,
123 93384844 Iustin Pop
    )
124 93384844 Iustin Pop
  _MAX_SIZE = 131072
125 93384844 Iustin Pop
126 93384844 Iustin Pop
  def __init__(self, cfg_location=None):
127 93384844 Iustin Pop
    if cfg_location is None:
128 93384844 Iustin Pop
      self._cfg_dir = constants.DATA_DIR
129 93384844 Iustin Pop
    else:
130 93384844 Iustin Pop
      self._cfg_dir = cfg_location
131 93384844 Iustin Pop
132 93384844 Iustin Pop
  def KeyToFilename(self, key):
133 93384844 Iustin Pop
    """Convert a given key into filename.
134 93384844 Iustin Pop

135 93384844 Iustin Pop
    """
136 93384844 Iustin Pop
    if key not in self._VALID_KEYS:
137 93384844 Iustin Pop
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
138 93384844 Iustin Pop
                                   % str(key))
139 93384844 Iustin Pop
140 93384844 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
141 93384844 Iustin Pop
    return filename
142 93384844 Iustin Pop
143 93384844 Iustin Pop
  def _ReadFile(self, key):
144 93384844 Iustin Pop
    """Generic routine to read keys.
145 93384844 Iustin Pop

146 93384844 Iustin Pop
    This will read the file which holds the value requested. Errors
147 93384844 Iustin Pop
    will be changed into ConfigurationErrors.
148 93384844 Iustin Pop

149 93384844 Iustin Pop
    """
150 93384844 Iustin Pop
    filename = self.KeyToFilename(key)
151 93384844 Iustin Pop
    try:
152 920b5878 Guido Trotter
      data = utils.ReadFile(filename, size=self._MAX_SIZE)
153 93384844 Iustin Pop
    except EnvironmentError, err:
154 93384844 Iustin Pop
      raise errors.ConfigurationError("Can't read from the ssconf file:"
155 93384844 Iustin Pop
                                      " '%s'" % str(err))
156 920b5878 Guido Trotter
    data = data.rstrip('\n')
157 93384844 Iustin Pop
    return data
158 93384844 Iustin Pop
159 89b14f05 Iustin Pop
  def WriteFiles(self, values):
160 89b14f05 Iustin Pop
    """Writes ssconf files used by external scripts.
161 89b14f05 Iustin Pop

162 89b14f05 Iustin Pop
    @type values: dict
163 89b14f05 Iustin Pop
    @param values: Dictionary of (name, value)
164 89b14f05 Iustin Pop

165 89b14f05 Iustin Pop
    """
166 89b14f05 Iustin Pop
    ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE)
167 89b14f05 Iustin Pop
168 89b14f05 Iustin Pop
    # Get lock while writing files
169 89b14f05 Iustin Pop
    ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
170 89b14f05 Iustin Pop
    try:
171 89b14f05 Iustin Pop
      for name, value in values.iteritems():
172 02b31f32 Iustin Pop
        if value and not value.endswith("\n"):
173 89b14f05 Iustin Pop
          value += "\n"
174 81a49123 Iustin Pop
        utils.WriteFile(self.KeyToFilename(name), data=value, mode=0444)
175 89b14f05 Iustin Pop
    finally:
176 89b14f05 Iustin Pop
      ssconf_lock.Unlock()
177 89b14f05 Iustin Pop
178 93384844 Iustin Pop
  def GetFileList(self):
179 93384844 Iustin Pop
    """Return the list of all config files.
180 93384844 Iustin Pop

181 93384844 Iustin Pop
    This is used for computing node replication data.
182 93384844 Iustin Pop

183 93384844 Iustin Pop
    """
184 93384844 Iustin Pop
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
185 93384844 Iustin Pop
186 93384844 Iustin Pop
  def GetClusterName(self):
187 93384844 Iustin Pop
    """Get the cluster name.
188 93384844 Iustin Pop

189 93384844 Iustin Pop
    """
190 93384844 Iustin Pop
    return self._ReadFile(constants.SS_CLUSTER_NAME)
191 93384844 Iustin Pop
192 93384844 Iustin Pop
  def GetFileStorageDir(self):
193 93384844 Iustin Pop
    """Get the file storage dir.
194 93384844 Iustin Pop

195 93384844 Iustin Pop
    """
196 93384844 Iustin Pop
    return self._ReadFile(constants.SS_FILE_STORAGE_DIR)
197 93384844 Iustin Pop
198 f56618e0 Iustin Pop
  def GetMasterCandidates(self):
199 f56618e0 Iustin Pop
    """Return the list of master candidates.
200 f56618e0 Iustin Pop

201 f56618e0 Iustin Pop
    """
202 f56618e0 Iustin Pop
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES)
203 f56618e0 Iustin Pop
    nl = data.splitlines(False)
204 f56618e0 Iustin Pop
    return nl
205 f56618e0 Iustin Pop
206 8113a52e Luca Bigliardi
  def GetMasterCandidatesIPList(self):
207 8113a52e Luca Bigliardi
    """Return the list of master candidates' primary IP.
208 8113a52e Luca Bigliardi

209 8113a52e Luca Bigliardi
    """
210 8113a52e Luca Bigliardi
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES_IPS)
211 8113a52e Luca Bigliardi
    nl = data.splitlines(False)
212 8113a52e Luca Bigliardi
    return nl
213 8113a52e Luca Bigliardi
214 93384844 Iustin Pop
  def GetMasterIP(self):
215 93384844 Iustin Pop
    """Get the IP of the master node for this cluster.
216 93384844 Iustin Pop

217 93384844 Iustin Pop
    """
218 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_IP)
219 93384844 Iustin Pop
220 93384844 Iustin Pop
  def GetMasterNetdev(self):
221 93384844 Iustin Pop
    """Get the netdev to which we'll add the master ip.
222 93384844 Iustin Pop

223 93384844 Iustin Pop
    """
224 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NETDEV)
225 93384844 Iustin Pop
226 93384844 Iustin Pop
  def GetMasterNode(self):
227 93384844 Iustin Pop
    """Get the hostname of the master node for this cluster.
228 93384844 Iustin Pop

229 93384844 Iustin Pop
    """
230 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NODE)
231 93384844 Iustin Pop
232 93384844 Iustin Pop
  def GetNodeList(self):
233 93384844 Iustin Pop
    """Return the list of cluster nodes.
234 93384844 Iustin Pop

235 93384844 Iustin Pop
    """
236 93384844 Iustin Pop
    data = self._ReadFile(constants.SS_NODE_LIST)
237 93384844 Iustin Pop
    nl = data.splitlines(False)
238 93384844 Iustin Pop
    return nl
239 93384844 Iustin Pop
240 f9780ccd Luca Bigliardi
  def GetNodePrimaryIPList(self):
241 f9780ccd Luca Bigliardi
    """Return the list of cluster nodes' primary IP.
242 f9780ccd Luca Bigliardi

243 f9780ccd Luca Bigliardi
    """
244 f9780ccd Luca Bigliardi
    data = self._ReadFile(constants.SS_NODE_PRIMARY_IPS)
245 f9780ccd Luca Bigliardi
    nl = data.splitlines(False)
246 f9780ccd Luca Bigliardi
    return nl
247 f9780ccd Luca Bigliardi
248 f9780ccd Luca Bigliardi
  def GetNodeSecondaryIPList(self):
249 f9780ccd Luca Bigliardi
    """Return the list of cluster nodes' secondary IP.
250 f9780ccd Luca Bigliardi

251 f9780ccd Luca Bigliardi
    """
252 f9780ccd Luca Bigliardi
    data = self._ReadFile(constants.SS_NODE_SECONDARY_IPS)
253 f9780ccd Luca Bigliardi
    nl = data.splitlines(False)
254 f9780ccd Luca Bigliardi
    return nl
255 f9780ccd Luca Bigliardi
256 25e39bfa Iustin Pop
  def GetClusterTags(self):
257 25e39bfa Iustin Pop
    """Return the cluster tags.
258 25e39bfa Iustin Pop

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

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

271 b33e986b Iustin Pop
  The function does not handle any errors, these should be handled in
272 b33e986b Iustin Pop
  the caller (errors.ConfigurationError, errors.ResolverError).
273 b33e986b Iustin Pop

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

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

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

291 5675cd1f Iustin Pop
  """
292 5675cd1f Iustin Pop
  try:
293 b33e986b Iustin Pop
    master_name, myself = GetMasterAndMyself(ss)
294 5675cd1f Iustin Pop
  except errors.ConfigurationError, err:
295 5675cd1f Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
296 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
297 5675cd1f Iustin Pop
  except errors.ResolverError, err:
298 5675cd1f Iustin Pop
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
299 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
300 5675cd1f Iustin Pop
301 b33e986b Iustin Pop
  if myself != master_name:
302 5675cd1f Iustin Pop
    if debug:
303 5675cd1f Iustin Pop
      sys.stderr.write("Not master, exiting.\n")
304 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NOTMASTER)
305 3f71b464 Guido Trotter
306 3f71b464 Guido Trotter
307 3f71b464 Guido Trotter
def CheckMasterCandidate(debug, ss=None):
308 3f71b464 Guido Trotter
  """Checks the node setup.
309 3f71b464 Guido Trotter

310 3f71b464 Guido Trotter
  If this is a master candidate, the function will return. Otherwise it will
311 3f71b464 Guido Trotter
  exit with an exit code based on the node status.
312 3f71b464 Guido Trotter

313 3f71b464 Guido Trotter
  """
314 3f71b464 Guido Trotter
  try:
315 3f71b464 Guido Trotter
    if ss is None:
316 3f71b464 Guido Trotter
      ss = SimpleStore()
317 3f71b464 Guido Trotter
    myself = utils.HostInfo().name
318 3f71b464 Guido Trotter
    candidates = ss.GetMasterCandidates()
319 3f71b464 Guido Trotter
  except errors.ConfigurationError, err:
320 3f71b464 Guido Trotter
    print "Cluster configuration incomplete: '%s'" % str(err)
321 3f71b464 Guido Trotter
    sys.exit(constants.EXIT_NODESETUP_ERROR)
322 3f71b464 Guido Trotter
  except errors.ResolverError, err:
323 3f71b464 Guido Trotter
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
324 3f71b464 Guido Trotter
    sys.exit(constants.EXIT_NODESETUP_ERROR)
325 3f71b464 Guido Trotter
326 3f71b464 Guido Trotter
  if myself not in candidates:
327 3f71b464 Guido Trotter
    if debug:
328 3f71b464 Guido Trotter
      sys.stderr.write("Not master candidate, exiting.\n")
329 3f71b464 Guido Trotter
    sys.exit(constants.EXIT_NOTCANDIDATE)