Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ a33848a5

History | View | Annotate | Download (7.1 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 856c67e1 Michael Hanselmann
83 93384844 Iustin Pop
class SimpleStore(object):
84 93384844 Iustin Pop
  """Interface to static cluster data.
85 93384844 Iustin Pop

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

90 93384844 Iustin Pop
  Other particularities of the datastore:
91 93384844 Iustin Pop
    - keys are restricted to predefined values
92 93384844 Iustin Pop

93 93384844 Iustin Pop
  """
94 93384844 Iustin Pop
  _SS_FILEPREFIX = "ssconf_"
95 93384844 Iustin Pop
  _VALID_KEYS = (
96 93384844 Iustin Pop
    constants.SS_CLUSTER_NAME,
97 5d60b3bd Iustin Pop
    constants.SS_CLUSTER_TAGS,
98 93384844 Iustin Pop
    constants.SS_FILE_STORAGE_DIR,
99 f56618e0 Iustin Pop
    constants.SS_MASTER_CANDIDATES,
100 93384844 Iustin Pop
    constants.SS_MASTER_IP,
101 93384844 Iustin Pop
    constants.SS_MASTER_NETDEV,
102 93384844 Iustin Pop
    constants.SS_MASTER_NODE,
103 93384844 Iustin Pop
    constants.SS_NODE_LIST,
104 a3316e4a Iustin Pop
    constants.SS_OFFLINE_NODES,
105 81a49123 Iustin Pop
    constants.SS_ONLINE_NODES,
106 81a49123 Iustin Pop
    constants.SS_INSTANCE_LIST,
107 8a113c7a Iustin Pop
    constants.SS_RELEASE_VERSION,
108 93384844 Iustin Pop
    )
109 93384844 Iustin Pop
  _MAX_SIZE = 131072
110 93384844 Iustin Pop
111 93384844 Iustin Pop
  def __init__(self, cfg_location=None):
112 93384844 Iustin Pop
    if cfg_location is None:
113 93384844 Iustin Pop
      self._cfg_dir = constants.DATA_DIR
114 93384844 Iustin Pop
    else:
115 93384844 Iustin Pop
      self._cfg_dir = cfg_location
116 93384844 Iustin Pop
117 93384844 Iustin Pop
  def KeyToFilename(self, key):
118 93384844 Iustin Pop
    """Convert a given key into filename.
119 93384844 Iustin Pop

120 93384844 Iustin Pop
    """
121 93384844 Iustin Pop
    if key not in self._VALID_KEYS:
122 93384844 Iustin Pop
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
123 93384844 Iustin Pop
                                   % str(key))
124 93384844 Iustin Pop
125 93384844 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
126 93384844 Iustin Pop
    return filename
127 93384844 Iustin Pop
128 93384844 Iustin Pop
  def _ReadFile(self, key):
129 93384844 Iustin Pop
    """Generic routine to read keys.
130 93384844 Iustin Pop

131 93384844 Iustin Pop
    This will read the file which holds the value requested. Errors
132 93384844 Iustin Pop
    will be changed into ConfigurationErrors.
133 93384844 Iustin Pop

134 93384844 Iustin Pop
    """
135 93384844 Iustin Pop
    filename = self.KeyToFilename(key)
136 93384844 Iustin Pop
    try:
137 920b5878 Guido Trotter
      data = utils.ReadFile(filename, size=self._MAX_SIZE)
138 93384844 Iustin Pop
    except EnvironmentError, err:
139 93384844 Iustin Pop
      raise errors.ConfigurationError("Can't read from the ssconf file:"
140 93384844 Iustin Pop
                                      " '%s'" % str(err))
141 920b5878 Guido Trotter
    data = data.rstrip('\n')
142 93384844 Iustin Pop
    return data
143 93384844 Iustin Pop
144 89b14f05 Iustin Pop
  def WriteFiles(self, values):
145 89b14f05 Iustin Pop
    """Writes ssconf files used by external scripts.
146 89b14f05 Iustin Pop

147 89b14f05 Iustin Pop
    @type values: dict
148 89b14f05 Iustin Pop
    @param values: Dictionary of (name, value)
149 89b14f05 Iustin Pop

150 89b14f05 Iustin Pop
    """
151 89b14f05 Iustin Pop
    ssconf_lock = utils.FileLock(constants.SSCONF_LOCK_FILE)
152 89b14f05 Iustin Pop
153 89b14f05 Iustin Pop
    # Get lock while writing files
154 89b14f05 Iustin Pop
    ssconf_lock.Exclusive(blocking=True, timeout=SSCONF_LOCK_TIMEOUT)
155 89b14f05 Iustin Pop
    try:
156 89b14f05 Iustin Pop
      for name, value in values.iteritems():
157 02b31f32 Iustin Pop
        if value and not value.endswith("\n"):
158 89b14f05 Iustin Pop
          value += "\n"
159 81a49123 Iustin Pop
        utils.WriteFile(self.KeyToFilename(name), data=value, mode=0444)
160 89b14f05 Iustin Pop
    finally:
161 89b14f05 Iustin Pop
      ssconf_lock.Unlock()
162 89b14f05 Iustin Pop
163 93384844 Iustin Pop
  def GetFileList(self):
164 93384844 Iustin Pop
    """Return the list of all config files.
165 93384844 Iustin Pop

166 93384844 Iustin Pop
    This is used for computing node replication data.
167 93384844 Iustin Pop

168 93384844 Iustin Pop
    """
169 93384844 Iustin Pop
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
170 93384844 Iustin Pop
171 93384844 Iustin Pop
  def GetClusterName(self):
172 93384844 Iustin Pop
    """Get the cluster name.
173 93384844 Iustin Pop

174 93384844 Iustin Pop
    """
175 93384844 Iustin Pop
    return self._ReadFile(constants.SS_CLUSTER_NAME)
176 93384844 Iustin Pop
177 93384844 Iustin Pop
  def GetFileStorageDir(self):
178 93384844 Iustin Pop
    """Get the file storage dir.
179 93384844 Iustin Pop

180 93384844 Iustin Pop
    """
181 93384844 Iustin Pop
    return self._ReadFile(constants.SS_FILE_STORAGE_DIR)
182 93384844 Iustin Pop
183 f56618e0 Iustin Pop
  def GetMasterCandidates(self):
184 f56618e0 Iustin Pop
    """Return the list of master candidates.
185 f56618e0 Iustin Pop

186 f56618e0 Iustin Pop
    """
187 f56618e0 Iustin Pop
    data = self._ReadFile(constants.SS_MASTER_CANDIDATES)
188 f56618e0 Iustin Pop
    nl = data.splitlines(False)
189 f56618e0 Iustin Pop
    return nl
190 f56618e0 Iustin Pop
191 93384844 Iustin Pop
  def GetMasterIP(self):
192 93384844 Iustin Pop
    """Get the IP of the master node for this cluster.
193 93384844 Iustin Pop

194 93384844 Iustin Pop
    """
195 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_IP)
196 93384844 Iustin Pop
197 93384844 Iustin Pop
  def GetMasterNetdev(self):
198 93384844 Iustin Pop
    """Get the netdev to which we'll add the master ip.
199 93384844 Iustin Pop

200 93384844 Iustin Pop
    """
201 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NETDEV)
202 93384844 Iustin Pop
203 93384844 Iustin Pop
  def GetMasterNode(self):
204 93384844 Iustin Pop
    """Get the hostname of the master node for this cluster.
205 93384844 Iustin Pop

206 93384844 Iustin Pop
    """
207 93384844 Iustin Pop
    return self._ReadFile(constants.SS_MASTER_NODE)
208 93384844 Iustin Pop
209 93384844 Iustin Pop
  def GetNodeList(self):
210 93384844 Iustin Pop
    """Return the list of cluster nodes.
211 93384844 Iustin Pop

212 93384844 Iustin Pop
    """
213 93384844 Iustin Pop
    data = self._ReadFile(constants.SS_NODE_LIST)
214 93384844 Iustin Pop
    nl = data.splitlines(False)
215 93384844 Iustin Pop
    return nl
216 93384844 Iustin Pop
217 25e39bfa Iustin Pop
  def GetClusterTags(self):
218 25e39bfa Iustin Pop
    """Return the cluster tags.
219 25e39bfa Iustin Pop

220 25e39bfa Iustin Pop
    """
221 25e39bfa Iustin Pop
    data = self._ReadFile(constants.SS_CLUSTER_TAGS)
222 25e39bfa Iustin Pop
    nl = data.splitlines(False)
223 25e39bfa Iustin Pop
    return nl
224 25e39bfa Iustin Pop
225 93384844 Iustin Pop
226 b33e986b Iustin Pop
def GetMasterAndMyself(ss=None):
227 b33e986b Iustin Pop
  """Get the master node and my own hostname.
228 b33e986b Iustin Pop

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

232 b33e986b Iustin Pop
  The function does not handle any errors, these should be handled in
233 b33e986b Iustin Pop
  the caller (errors.ConfigurationError, errors.ResolverError).
234 b33e986b Iustin Pop

235 8135a2db Iustin Pop
  @param ss: either a sstore.SimpleConfigReader or a
236 8135a2db Iustin Pop
      sstore.SimpleStore instance
237 8135a2db Iustin Pop
  @rtype: tuple
238 8135a2db Iustin Pop
  @return: a tuple (master node name, my own name)
239 8135a2db Iustin Pop

240 b33e986b Iustin Pop
  """
241 b33e986b Iustin Pop
  if ss is None:
242 93384844 Iustin Pop
    ss = SimpleStore()
243 b33e986b Iustin Pop
  return ss.GetMasterNode(), utils.HostInfo().name
244 b33e986b Iustin Pop
245 06dc5b44 Iustin Pop
246 b33e986b Iustin Pop
def CheckMaster(debug, ss=None):
247 5675cd1f Iustin Pop
  """Checks the node setup.
248 5675cd1f Iustin Pop

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

252 5675cd1f Iustin Pop
  """
253 5675cd1f Iustin Pop
  try:
254 b33e986b Iustin Pop
    master_name, myself = GetMasterAndMyself(ss)
255 5675cd1f Iustin Pop
  except errors.ConfigurationError, err:
256 5675cd1f Iustin Pop
    print "Cluster configuration incomplete: '%s'" % str(err)
257 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
258 5675cd1f Iustin Pop
  except errors.ResolverError, err:
259 5675cd1f Iustin Pop
    sys.stderr.write("Cannot resolve my own name (%s)\n" % err.args[0])
260 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NODESETUP_ERROR)
261 5675cd1f Iustin Pop
262 b33e986b Iustin Pop
  if myself != master_name:
263 5675cd1f Iustin Pop
    if debug:
264 5675cd1f Iustin Pop
      sys.stderr.write("Not master, exiting.\n")
265 5675cd1f Iustin Pop
    sys.exit(constants.EXIT_NOTMASTER)