Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ 01cf7dbe

History | View | Annotate | Download (8.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 01cf7dbe Guido Trotter
    try:
56 01cf7dbe Guido Trotter
      self._config_data = serializer.Load(utils.ReadFile(file_name))
57 01cf7dbe Guido Trotter
    except IOError, err:
58 01cf7dbe Guido Trotter
      raise errors.ConfigurationError("Cannot read config file %s: %s" %
59 01cf7dbe Guido Trotter
                                      (file_name, err))
60 01cf7dbe Guido Trotter
    except ValueError, err:
61 01cf7dbe Guido Trotter
      raise errors.ConfigurationError("Cannot load config file %s: %s" %
62 01cf7dbe Guido Trotter
                                      (file_name, err))
63 856c67e1 Michael Hanselmann
64 856c67e1 Michael Hanselmann
  def GetClusterName(self):
65 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["cluster_name"]
66 856c67e1 Michael Hanselmann
67 856c67e1 Michael Hanselmann
  def GetHostKey(self):
68 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["rsahostkeypub"]
69 856c67e1 Michael Hanselmann
70 856c67e1 Michael Hanselmann
  def GetMasterNode(self):
71 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_node"]
72 856c67e1 Michael Hanselmann
73 856c67e1 Michael Hanselmann
  def GetMasterIP(self):
74 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_ip"]
75 856c67e1 Michael Hanselmann
76 856c67e1 Michael Hanselmann
  def GetMasterNetdev(self):
77 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_netdev"]
78 856c67e1 Michael Hanselmann
79 856c67e1 Michael Hanselmann
  def GetFileStorageDir(self):
80 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["file_storage_dir"]
81 856c67e1 Michael Hanselmann
82 856c67e1 Michael Hanselmann
  def GetHypervisorType(self):
83 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["hypervisor"]
84 856c67e1 Michael Hanselmann
85 856c67e1 Michael Hanselmann
  def GetNodeList(self):
86 856c67e1 Michael Hanselmann
    return self._config_data["nodes"].keys()
87 856c67e1 Michael Hanselmann
88 856c67e1 Michael Hanselmann
89 93384844 Iustin Pop
class SimpleStore(object):
90 93384844 Iustin Pop
  """Interface to static cluster data.
91 93384844 Iustin Pop

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

96 93384844 Iustin Pop
  Other particularities of the datastore:
97 93384844 Iustin Pop
    - keys are restricted to predefined values
98 93384844 Iustin Pop

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

129 93384844 Iustin Pop
    """
130 93384844 Iustin Pop
    if key not in self._VALID_KEYS:
131 93384844 Iustin Pop
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
132 93384844 Iustin Pop
                                   % str(key))
133 93384844 Iustin Pop
134 93384844 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
135 93384844 Iustin Pop
    return filename
136 93384844 Iustin Pop
137 93384844 Iustin Pop
  def _ReadFile(self, key):
138 93384844 Iustin Pop
    """Generic routine to read keys.
139 93384844 Iustin Pop

140 93384844 Iustin Pop
    This will read the file which holds the value requested. Errors
141 93384844 Iustin Pop
    will be changed into ConfigurationErrors.
142 93384844 Iustin Pop

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

156 89b14f05 Iustin Pop
    @type values: dict
157 89b14f05 Iustin Pop
    @param values: Dictionary of (name, value)
158 89b14f05 Iustin Pop

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

175 93384844 Iustin Pop
    This is used for computing node replication data.
176 93384844 Iustin Pop

177 93384844 Iustin Pop
    """
178 93384844 Iustin Pop
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
179 93384844 Iustin Pop
180 93384844 Iustin Pop
  def GetClusterName(self):
181 93384844 Iustin Pop
    """Get the cluster name.
182 93384844 Iustin Pop

183 93384844 Iustin Pop
    """
184 93384844 Iustin Pop
    return self._ReadFile(constants.SS_CLUSTER_NAME)
185 93384844 Iustin Pop
186 93384844 Iustin Pop
  def GetFileStorageDir(self):
187 93384844 Iustin Pop
    """Get the file storage dir.
188 93384844 Iustin Pop

189 93384844 Iustin Pop
    """
190 93384844 Iustin Pop
    return self._ReadFile(constants.SS_FILE_STORAGE_DIR)
191 93384844 Iustin Pop
192 f56618e0 Iustin Pop
  def GetMasterCandidates(self):
193 f56618e0 Iustin Pop
    """Return the list of master candidates.
194 f56618e0 Iustin Pop

195 f56618e0 Iustin Pop
    """
196 f56618e0 Iustin Pop
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES)
197 f56618e0 Iustin Pop
    nl = data.splitlines(False)
198 f56618e0 Iustin Pop
    return nl
199 f56618e0 Iustin Pop
200 8113a52e Luca Bigliardi
  def GetMasterCandidatesIPList(self):
201 8113a52e Luca Bigliardi
    """Return the list of master candidates' primary IP.
202 8113a52e Luca Bigliardi

203 8113a52e Luca Bigliardi
    """
204 8113a52e Luca Bigliardi
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES_IPS)
205 8113a52e Luca Bigliardi
    nl = data.splitlines(False)
206 8113a52e Luca Bigliardi
    return nl
207 8113a52e Luca Bigliardi
208 93384844 Iustin Pop
  def GetMasterIP(self):
209 93384844 Iustin Pop
    """Get the IP of the master node for this cluster.
210 93384844 Iustin Pop

211 93384844 Iustin Pop
    """
212 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_IP)
213 93384844 Iustin Pop
214 93384844 Iustin Pop
  def GetMasterNetdev(self):
215 93384844 Iustin Pop
    """Get the netdev to which we'll add the master ip.
216 93384844 Iustin Pop

217 93384844 Iustin Pop
    """
218 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NETDEV)
219 93384844 Iustin Pop
220 93384844 Iustin Pop
  def GetMasterNode(self):
221 93384844 Iustin Pop
    """Get the hostname of the master node for this cluster.
222 93384844 Iustin Pop

223 93384844 Iustin Pop
    """
224 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NODE)
225 93384844 Iustin Pop
226 93384844 Iustin Pop
  def GetNodeList(self):
227 93384844 Iustin Pop
    """Return the list of cluster nodes.
228 93384844 Iustin Pop

229 93384844 Iustin Pop
    """
230 93384844 Iustin Pop
    data = self._ReadFile(constants.SS_NODE_LIST)
231 93384844 Iustin Pop
    nl = data.splitlines(False)
232 93384844 Iustin Pop
    return nl
233 93384844 Iustin Pop
234 f9780ccd Luca Bigliardi
  def GetNodePrimaryIPList(self):
235 f9780ccd Luca Bigliardi
    """Return the list of cluster nodes' primary IP.
236 f9780ccd Luca Bigliardi

237 f9780ccd Luca Bigliardi
    """
238 f9780ccd Luca Bigliardi
    data = self._ReadFile(constants.SS_NODE_PRIMARY_IPS)
239 f9780ccd Luca Bigliardi
    nl = data.splitlines(False)
240 f9780ccd Luca Bigliardi
    return nl
241 f9780ccd Luca Bigliardi
242 f9780ccd Luca Bigliardi
  def GetNodeSecondaryIPList(self):
243 f9780ccd Luca Bigliardi
    """Return the list of cluster nodes' secondary IP.
244 f9780ccd Luca Bigliardi

245 f9780ccd Luca Bigliardi
    """
246 f9780ccd Luca Bigliardi
    data = self._ReadFile(constants.SS_NODE_SECONDARY_IPS)
247 f9780ccd Luca Bigliardi
    nl = data.splitlines(False)
248 f9780ccd Luca Bigliardi
    return nl
249 f9780ccd Luca Bigliardi
250 25e39bfa Iustin Pop
  def GetClusterTags(self):
251 25e39bfa Iustin Pop
    """Return the cluster tags.
252 25e39bfa Iustin Pop

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

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

265 b33e986b Iustin Pop
  The function does not handle any errors, these should be handled in
266 b33e986b Iustin Pop
  the caller (errors.ConfigurationError, errors.ResolverError).
267 b33e986b Iustin Pop

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

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

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

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

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

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