Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ 856c67e1

History | View | Annotate | Download (8.5 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 a8083063 Iustin Pop
import socket
30 5675cd1f Iustin Pop
import sys
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 a8083063 Iustin Pop
class SimpleStore:
39 a8083063 Iustin Pop
  """Interface to static cluster data.
40 a8083063 Iustin Pop

41 a8083063 Iustin Pop
  This is different that the config.ConfigWriter class in that it
42 a8083063 Iustin Pop
  holds data that is (mostly) constant after the cluster
43 a8083063 Iustin Pop
  initialization. Its purpose is to allow limited customization of
44 a8083063 Iustin Pop
  things which would otherwise normally live in constants.py. Note
45 a8083063 Iustin Pop
  that this data cannot live in ConfigWriter as that is available only
46 a8083063 Iustin Pop
  on the master node, and our data must be readable by both the master
47 a8083063 Iustin Pop
  and the nodes.
48 a8083063 Iustin Pop

49 a8083063 Iustin Pop
  Other particularities of the datastore:
50 a8083063 Iustin Pop
    - keys are restricted to predefined values
51 a8083063 Iustin Pop
    - values are small (<4k)
52 05f86716 Guido Trotter
    - some keys are handled specially (read from the system)
53 a8083063 Iustin Pop

54 a8083063 Iustin Pop
  """
55 a8083063 Iustin Pop
  _SS_FILEPREFIX = "ssconf_"
56 a8083063 Iustin Pop
  SS_HYPERVISOR = "hypervisor"
57 a8083063 Iustin Pop
  SS_NODED_PASS = "node_pass"
58 880478f8 Iustin Pop
  SS_MASTER_NODE = "master_node"
59 880478f8 Iustin Pop
  SS_MASTER_IP = "master_ip"
60 880478f8 Iustin Pop
  SS_MASTER_NETDEV = "master_netdev"
61 5fcdc80d Iustin Pop
  SS_CLUSTER_NAME = "cluster_name"
62 17dfc522 Manuel Franceschini
  SS_FILE_STORAGE_DIR = "file_storage_dir"
63 742f39ac Michael Hanselmann
  SS_CONFIG_VERSION = "config_version"
64 880478f8 Iustin Pop
  _VALID_KEYS = (SS_HYPERVISOR, SS_NODED_PASS, SS_MASTER_NODE, SS_MASTER_IP,
65 742f39ac Michael Hanselmann
                 SS_MASTER_NETDEV, SS_CLUSTER_NAME, SS_FILE_STORAGE_DIR,
66 742f39ac Michael Hanselmann
                 SS_CONFIG_VERSION)
67 a8083063 Iustin Pop
  _MAX_SIZE = 4096
68 a8083063 Iustin Pop
69 a8083063 Iustin Pop
  def __init__(self, cfg_location=None):
70 a8083063 Iustin Pop
    if cfg_location is None:
71 a8083063 Iustin Pop
      self._cfg_dir = constants.DATA_DIR
72 a8083063 Iustin Pop
    else:
73 a8083063 Iustin Pop
      self._cfg_dir = cfg_location
74 a8083063 Iustin Pop
75 a8083063 Iustin Pop
  def KeyToFilename(self, key):
76 a8083063 Iustin Pop
    """Convert a given key into filename.
77 a8083063 Iustin Pop

78 a8083063 Iustin Pop
    """
79 a8083063 Iustin Pop
    if key not in self._VALID_KEYS:
80 3ecf6786 Iustin Pop
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
81 3ecf6786 Iustin Pop
                                   % str(key))
82 a8083063 Iustin Pop
83 a8083063 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
84 a8083063 Iustin Pop
    return filename
85 a8083063 Iustin Pop
86 a8083063 Iustin Pop
  def _ReadFile(self, key):
87 a8083063 Iustin Pop
    """Generic routine to read keys.
88 a8083063 Iustin Pop

89 a8083063 Iustin Pop
    This will read the file which holds the value requested. Errors
90 a8083063 Iustin Pop
    will be changed into ConfigurationErrors.
91 a8083063 Iustin Pop

92 a8083063 Iustin Pop
    """
93 a8083063 Iustin Pop
    filename = self.KeyToFilename(key)
94 a8083063 Iustin Pop
    try:
95 a8083063 Iustin Pop
      fh = file(filename, 'r')
96 a8083063 Iustin Pop
      try:
97 a8083063 Iustin Pop
        data = fh.readline(self._MAX_SIZE)
98 a8083063 Iustin Pop
        data = data.rstrip('\n')
99 a8083063 Iustin Pop
      finally:
100 a8083063 Iustin Pop
        fh.close()
101 a8083063 Iustin Pop
    except EnvironmentError, err:
102 3ecf6786 Iustin Pop
      raise errors.ConfigurationError("Can't read from the ssconf file:"
103 3ecf6786 Iustin Pop
                                      " '%s'" % str(err))
104 a8083063 Iustin Pop
    return data
105 a8083063 Iustin Pop
106 a8083063 Iustin Pop
  def GetNodeDaemonPort(self):
107 a8083063 Iustin Pop
    """Get the node daemon port for this cluster.
108 a8083063 Iustin Pop

109 a8083063 Iustin Pop
    Note that this routine does not read a ganeti-specific file, but
110 a8083063 Iustin Pop
    instead uses socket.getservbyname to allow pre-customization of
111 a8083063 Iustin Pop
    this parameter outside of ganeti.
112 a8083063 Iustin Pop

113 a8083063 Iustin Pop
    """
114 a8083063 Iustin Pop
    try:
115 a8083063 Iustin Pop
      port = socket.getservbyname("ganeti-noded", "tcp")
116 a8083063 Iustin Pop
    except socket.error:
117 a8083063 Iustin Pop
      port = constants.DEFAULT_NODED_PORT
118 a8083063 Iustin Pop
119 a8083063 Iustin Pop
    return port
120 a8083063 Iustin Pop
121 a8083063 Iustin Pop
  def GetHypervisorType(self):
122 a8083063 Iustin Pop
    """Get the hypervisor type for this cluster.
123 a8083063 Iustin Pop

124 a8083063 Iustin Pop
    """
125 a8083063 Iustin Pop
    return self._ReadFile(self.SS_HYPERVISOR)
126 a8083063 Iustin Pop
127 a8083063 Iustin Pop
  def GetNodeDaemonPassword(self):
128 a8083063 Iustin Pop
    """Get the node password for this cluster.
129 a8083063 Iustin Pop

130 a8083063 Iustin Pop
    """
131 a8083063 Iustin Pop
    return self._ReadFile(self.SS_NODED_PASS)
132 a8083063 Iustin Pop
133 880478f8 Iustin Pop
  def GetMasterNode(self):
134 880478f8 Iustin Pop
    """Get the hostname of the master node for this cluster.
135 880478f8 Iustin Pop

136 880478f8 Iustin Pop
    """
137 880478f8 Iustin Pop
    return self._ReadFile(self.SS_MASTER_NODE)
138 880478f8 Iustin Pop
139 880478f8 Iustin Pop
  def GetMasterIP(self):
140 880478f8 Iustin Pop
    """Get the IP of the master node for this cluster.
141 880478f8 Iustin Pop

142 880478f8 Iustin Pop
    """
143 880478f8 Iustin Pop
    return self._ReadFile(self.SS_MASTER_IP)
144 880478f8 Iustin Pop
145 880478f8 Iustin Pop
  def GetMasterNetdev(self):
146 880478f8 Iustin Pop
    """Get the netdev to which we'll add the master ip.
147 880478f8 Iustin Pop

148 880478f8 Iustin Pop
    """
149 880478f8 Iustin Pop
    return self._ReadFile(self.SS_MASTER_NETDEV)
150 880478f8 Iustin Pop
151 5fcdc80d Iustin Pop
  def GetClusterName(self):
152 5fcdc80d Iustin Pop
    """Get the cluster name.
153 5fcdc80d Iustin Pop

154 5fcdc80d Iustin Pop
    """
155 5fcdc80d Iustin Pop
    return self._ReadFile(self.SS_CLUSTER_NAME)
156 5fcdc80d Iustin Pop
157 17dfc522 Manuel Franceschini
  def GetFileStorageDir(self):
158 17dfc522 Manuel Franceschini
    """Get the file storage dir.
159 17dfc522 Manuel Franceschini

160 17dfc522 Manuel Franceschini
    """
161 17dfc522 Manuel Franceschini
    return self._ReadFile(self.SS_FILE_STORAGE_DIR)
162 17dfc522 Manuel Franceschini
163 742f39ac Michael Hanselmann
  def GetConfigVersion(self):
164 742f39ac Michael Hanselmann
    """Get the configuration version.
165 742f39ac Michael Hanselmann

166 742f39ac Michael Hanselmann
    """
167 742f39ac Michael Hanselmann
    value = self._ReadFile(self.SS_CONFIG_VERSION)
168 742f39ac Michael Hanselmann
    try:
169 742f39ac Michael Hanselmann
      return int(value)
170 742f39ac Michael Hanselmann
    except (ValueError, TypeError), err:
171 742f39ac Michael Hanselmann
      raise errors.ConfigurationError("Failed to convert config version %s to"
172 742f39ac Michael Hanselmann
                                      " int: '%s'" % (value, str(err)))
173 742f39ac Michael Hanselmann
174 05f86716 Guido Trotter
  def GetFileList(self):
175 05f86716 Guido Trotter
    """Return the list of all config files.
176 05f86716 Guido Trotter

177 05f86716 Guido Trotter
    This is used for computing node replication data.
178 05f86716 Guido Trotter

179 05f86716 Guido Trotter
    """
180 05f86716 Guido Trotter
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
181 05f86716 Guido Trotter
182 05f86716 Guido Trotter
183 05f86716 Guido Trotter
class WritableSimpleStore(SimpleStore):
184 05f86716 Guido Trotter
  """This is a read/write interface to SimpleStore, which is used rarely, when
185 05f86716 Guido Trotter
  values need to be changed. Since WriteFile handles updates in an atomic way
186 05f86716 Guido Trotter
  it should be fine to use two WritableSimpleStore at the same time, but in
187 05f86716 Guido Trotter
  the future we might want to put additional protection for this class.
188 05f86716 Guido Trotter

189 05f86716 Guido Trotter
  A WritableSimpleStore cannot be used to update system-dependent values.
190 05f86716 Guido Trotter

191 05f86716 Guido Trotter
  """
192 05f86716 Guido Trotter
193 a8083063 Iustin Pop
  def SetKey(self, key, value):
194 a8083063 Iustin Pop
    """Set the value of a key.
195 a8083063 Iustin Pop

196 8498462b Guido Trotter
    This should be used only when adding a node to a cluster, or in other
197 8498462b Guido Trotter
    infrequent operations such as cluster-rename or master-failover.
198 a8083063 Iustin Pop

199 a8083063 Iustin Pop
    """
200 a8083063 Iustin Pop
    file_name = self.KeyToFilename(key)
201 41a57aab Michael Hanselmann
    utils.WriteFile(file_name, data="%s\n" % str(value),
202 41a57aab Michael Hanselmann
                    uid=0, gid=0, mode=0400)
203 a8083063 Iustin Pop
204 5675cd1f Iustin Pop
205 856c67e1 Michael Hanselmann
class SimpleConfigReader:
206 856c67e1 Michael Hanselmann
  """Simple class to read configuration file.
207 856c67e1 Michael Hanselmann

208 856c67e1 Michael Hanselmann
  """
209 856c67e1 Michael Hanselmann
  def __init__(self, file_name=constants.CLUSTER_CONF_FILE):
210 856c67e1 Michael Hanselmann
    """Initializes this class.
211 856c67e1 Michael Hanselmann

212 856c67e1 Michael Hanselmann
    @type file_name: string
213 856c67e1 Michael Hanselmann
    @param file_name: Configuration file path
214 856c67e1 Michael Hanselmann

215 856c67e1 Michael Hanselmann
    """
216 856c67e1 Michael Hanselmann
    self._file_name = file_name
217 856c67e1 Michael Hanselmann
    self._config_data = serializer.Load(utils.ReadFile(file_name))
218 856c67e1 Michael Hanselmann
    # TODO: Error handling
219 856c67e1 Michael Hanselmann
220 856c67e1 Michael Hanselmann
  def GetClusterName(self):
221 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["cluster_name"]
222 856c67e1 Michael Hanselmann
223 856c67e1 Michael Hanselmann
  def GetHostKey(self):
224 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["rsahostkeypub"]
225 856c67e1 Michael Hanselmann
226 856c67e1 Michael Hanselmann
  def GetMasterNode(self):
227 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_node"]
228 856c67e1 Michael Hanselmann
229 856c67e1 Michael Hanselmann
  def GetMasterIP(self):
230 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_ip"]
231 856c67e1 Michael Hanselmann
232 856c67e1 Michael Hanselmann
  def GetMasterNetdev(self):
233 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["master_netdev"]
234 856c67e1 Michael Hanselmann
235 856c67e1 Michael Hanselmann
  def GetFileStorageDir(self):
236 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["file_storage_dir"]
237 856c67e1 Michael Hanselmann
238 856c67e1 Michael Hanselmann
  def GetHypervisorType(self):
239 856c67e1 Michael Hanselmann
    return self._config_data["cluster"]["hypervisor"]
240 856c67e1 Michael Hanselmann
241 856c67e1 Michael Hanselmann
  def GetNodeList(self):
242 856c67e1 Michael Hanselmann
    return self._config_data["nodes"].keys()
243 856c67e1 Michael Hanselmann
244 856c67e1 Michael Hanselmann
245 856c67e1 Michael Hanselmann
class SimpleConfigWriter(SimpleConfigReader):
246 856c67e1 Michael Hanselmann
  """Simple class to write configuration file.
247 856c67e1 Michael Hanselmann

248 856c67e1 Michael Hanselmann
  """
249 856c67e1 Michael Hanselmann
  def SetMasterNode(self, node):
250 856c67e1 Michael Hanselmann
    """Change master node.
251 856c67e1 Michael Hanselmann

252 856c67e1 Michael Hanselmann
    """
253 856c67e1 Michael Hanselmann
    self._config_data["cluster"]["master_node"] = node
254 856c67e1 Michael Hanselmann
255 856c67e1 Michael Hanselmann
  def Save(self):
256 856c67e1 Michael Hanselmann
    """Writes configuration file.
257 856c67e1 Michael Hanselmann

258 856c67e1 Michael Hanselmann
    Warning: Doesn't take care of locking or synchronizing with other
259 856c67e1 Michael Hanselmann
    processes.
260 856c67e1 Michael Hanselmann

261 856c67e1 Michael Hanselmann
    """
262 856c67e1 Michael Hanselmann
    utils.WriteFile(self._file_name,
263 856c67e1 Michael Hanselmann
                    data=serializer.Dump(self._config_data),
264 856c67e1 Michael Hanselmann
                    mode=0600)
265 856c67e1 Michael Hanselmann
266 856c67e1 Michael Hanselmann
267 b33e986b Iustin Pop
def GetMasterAndMyself(ss=None):
268 b33e986b Iustin Pop
  """Get the master node and my own hostname.
269 b33e986b Iustin Pop

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

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

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

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

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