Statistics
| Branch: | Tag: | Revision:

root / lib / ssconf.py @ d0b3526f

History | View | Annotate | Download (4.7 kB)

1 a8083063 Iustin Pop
#!/usr/bin/python
2 a8083063 Iustin Pop
#
3 a8083063 Iustin Pop
4 a8083063 Iustin Pop
# Copyright (C) 2006, 2007 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 os
30 a8083063 Iustin Pop
import tempfile
31 a8083063 Iustin Pop
import errno
32 a8083063 Iustin Pop
import socket
33 a8083063 Iustin Pop
34 a8083063 Iustin Pop
from ganeti import errors
35 a8083063 Iustin Pop
from ganeti import constants
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 a8083063 Iustin Pop
    - since the data is practically static, read keys are cached in memory
53 a8083063 Iustin Pop
    - some keys are handled specially (read from the system, so
54 a8083063 Iustin Pop
      we can't update them)
55 a8083063 Iustin Pop

56 a8083063 Iustin Pop
  """
57 a8083063 Iustin Pop
  _SS_FILEPREFIX = "ssconf_"
58 a8083063 Iustin Pop
  SS_HYPERVISOR = "hypervisor"
59 a8083063 Iustin Pop
  SS_NODED_PASS = "node_pass"
60 a8083063 Iustin Pop
  _VALID_KEYS = (SS_HYPERVISOR, SS_NODED_PASS,)
61 a8083063 Iustin Pop
  _MAX_SIZE = 4096
62 a8083063 Iustin Pop
63 a8083063 Iustin Pop
  def __init__(self, cfg_location=None):
64 a8083063 Iustin Pop
    if cfg_location is None:
65 a8083063 Iustin Pop
      self._cfg_dir = constants.DATA_DIR
66 a8083063 Iustin Pop
    else:
67 a8083063 Iustin Pop
      self._cfg_dir = cfg_location
68 a8083063 Iustin Pop
    self._cache = {}
69 a8083063 Iustin Pop
70 a8083063 Iustin Pop
  def KeyToFilename(self, key):
71 a8083063 Iustin Pop
    """Convert a given key into filename.
72 a8083063 Iustin Pop

73 a8083063 Iustin Pop
    """
74 a8083063 Iustin Pop
    if key not in self._VALID_KEYS:
75 a8083063 Iustin Pop
      raise errors.ProgrammerError, ("Invalid key requested from SSConf: '%s'"
76 a8083063 Iustin Pop
                                     % str(key))
77 a8083063 Iustin Pop
78 a8083063 Iustin Pop
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
79 a8083063 Iustin Pop
    return filename
80 a8083063 Iustin Pop
81 a8083063 Iustin Pop
  def _ReadFile(self, key):
82 a8083063 Iustin Pop
    """Generic routine to read keys.
83 a8083063 Iustin Pop

84 a8083063 Iustin Pop
    This will read the file which holds the value requested. Errors
85 a8083063 Iustin Pop
    will be changed into ConfigurationErrors.
86 a8083063 Iustin Pop

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

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

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

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

128 a8083063 Iustin Pop
    """
129 a8083063 Iustin Pop
    return self._ReadFile(self.SS_NODED_PASS)
130 a8083063 Iustin Pop
131 a8083063 Iustin Pop
  def SetKey(self, key, value):
132 a8083063 Iustin Pop
    """Set the value of a key.
133 a8083063 Iustin Pop

134 a8083063 Iustin Pop
    This should be used only when adding a node to a cluster.
135 a8083063 Iustin Pop

136 a8083063 Iustin Pop
    """
137 a8083063 Iustin Pop
    file_name = self.KeyToFilename(key)
138 a8083063 Iustin Pop
    dir_name, small_name = os.path.split(file_name)
139 a8083063 Iustin Pop
    fd, new_name = tempfile.mkstemp('.new', small_name, dir_name)
140 a8083063 Iustin Pop
    # here we need to make sure we remove the temp file, if any error
141 a8083063 Iustin Pop
    # leaves it in place
142 a8083063 Iustin Pop
    try:
143 a8083063 Iustin Pop
      os.chown(new_name, 0, 0)
144 a8083063 Iustin Pop
      os.chmod(new_name, 0400)
145 a8083063 Iustin Pop
      os.write(fd, "%s\n" % str(value))
146 a8083063 Iustin Pop
      os.fsync(fd)
147 a8083063 Iustin Pop
      os.rename(new_name, file_name)
148 a8083063 Iustin Pop
      self._cache[key] = value
149 a8083063 Iustin Pop
    finally:
150 a8083063 Iustin Pop
      os.close(fd)
151 a8083063 Iustin Pop
      try:
152 a8083063 Iustin Pop
        os.unlink(new_name)
153 a8083063 Iustin Pop
      except OSError, err:
154 a8083063 Iustin Pop
        if err.errno != errno.ENOENT:
155 a8083063 Iustin Pop
          raise
156 a8083063 Iustin Pop
157 a8083063 Iustin Pop
  def GetFileList(self):
158 a8083063 Iustin Pop
    """Return the lis of all config files.
159 a8083063 Iustin Pop

160 a8083063 Iustin Pop
    This is used for computing node replication data.
161 a8083063 Iustin Pop

162 a8083063 Iustin Pop
    """
163 a8083063 Iustin Pop
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]