Revision c259ce64 lib/ssconf.py

b/lib/ssconf.py
35 35
from ganeti import serializer
36 36

  
37 37

  
38
class SimpleStore:
39
  """Interface to static cluster data.
40

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

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

  
54
  """
55
  _SS_FILEPREFIX = "ssconf_"
56
  SS_HYPERVISOR = "hypervisor"
57
  SS_NODED_PASS = "node_pass"
58
  SS_MASTER_NODE = "master_node"
59
  SS_MASTER_IP = "master_ip"
60
  SS_MASTER_NETDEV = "master_netdev"
61
  SS_CLUSTER_NAME = "cluster_name"
62
  SS_FILE_STORAGE_DIR = "file_storage_dir"
63
  SS_CONFIG_VERSION = "config_version"
64
  _VALID_KEYS = (SS_HYPERVISOR, SS_NODED_PASS, SS_MASTER_NODE, SS_MASTER_IP,
65
                 SS_MASTER_NETDEV, SS_CLUSTER_NAME, SS_FILE_STORAGE_DIR,
66
                 SS_CONFIG_VERSION)
67
  _MAX_SIZE = 4096
68

  
69
  def __init__(self, cfg_location=None):
70
    if cfg_location is None:
71
      self._cfg_dir = constants.DATA_DIR
72
    else:
73
      self._cfg_dir = cfg_location
74

  
75
  def KeyToFilename(self, key):
76
    """Convert a given key into filename.
77

  
78
    """
79
    if key not in self._VALID_KEYS:
80
      raise errors.ProgrammerError("Invalid key requested from SSConf: '%s'"
81
                                   % str(key))
82

  
83
    filename = self._cfg_dir + '/' + self._SS_FILEPREFIX + key
84
    return filename
85

  
86
  def _ReadFile(self, key):
87
    """Generic routine to read keys.
88

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

  
92
    """
93
    filename = self.KeyToFilename(key)
94
    try:
95
      fh = file(filename, 'r')
96
      try:
97
        data = fh.readline(self._MAX_SIZE)
98
        data = data.rstrip('\n')
99
      finally:
100
        fh.close()
101
    except EnvironmentError, err:
102
      raise errors.ConfigurationError("Can't read from the ssconf file:"
103
                                      " '%s'" % str(err))
104
    return data
105

  
106
  def GetNodeDaemonPort(self):
107
    """Get the node daemon port for this cluster.
108

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

  
113
    """
114
    try:
115
      port = socket.getservbyname("ganeti-noded", "tcp")
116
    except socket.error:
117
      port = constants.DEFAULT_NODED_PORT
118

  
119
    return port
120

  
121
  def GetHypervisorType(self):
122
    """Get the hypervisor type for this cluster.
123

  
124
    """
125
    return self._ReadFile(self.SS_HYPERVISOR)
126

  
127
  def GetNodeDaemonPassword(self):
128
    """Get the node password for this cluster.
129

  
130
    """
131
    return self._ReadFile(self.SS_NODED_PASS)
132

  
133
  def GetMasterNode(self):
134
    """Get the hostname of the master node for this cluster.
135

  
136
    """
137
    return self._ReadFile(self.SS_MASTER_NODE)
138

  
139
  def GetMasterIP(self):
140
    """Get the IP of the master node for this cluster.
141

  
142
    """
143
    return self._ReadFile(self.SS_MASTER_IP)
144

  
145
  def GetMasterNetdev(self):
146
    """Get the netdev to which we'll add the master ip.
147

  
148
    """
149
    return self._ReadFile(self.SS_MASTER_NETDEV)
150

  
151
  def GetClusterName(self):
152
    """Get the cluster name.
153

  
154
    """
155
    return self._ReadFile(self.SS_CLUSTER_NAME)
156

  
157
  def GetFileStorageDir(self):
158
    """Get the file storage dir.
159

  
160
    """
161
    return self._ReadFile(self.SS_FILE_STORAGE_DIR)
162

  
163
  def GetConfigVersion(self):
164
    """Get the configuration version.
165

  
166
    """
167
    value = self._ReadFile(self.SS_CONFIG_VERSION)
168
    try:
169
      return int(value)
170
    except (ValueError, TypeError), err:
171
      raise errors.ConfigurationError("Failed to convert config version %s to"
172
                                      " int: '%s'" % (value, str(err)))
173

  
174
  def GetFileList(self):
175
    """Return the list of all config files.
176

  
177
    This is used for computing node replication data.
178

  
179
    """
180
    return [self.KeyToFilename(key) for key in self._VALID_KEYS]
181

  
182

  
183
class WritableSimpleStore(SimpleStore):
184
  """This is a read/write interface to SimpleStore, which is used rarely, when
185
  values need to be changed. Since WriteFile handles updates in an atomic way
186
  it should be fine to use two WritableSimpleStore at the same time, but in
187
  the future we might want to put additional protection for this class.
188

  
189
  A WritableSimpleStore cannot be used to update system-dependent values.
190

  
191
  """
192

  
193
  def SetKey(self, key, value):
194
    """Set the value of a key.
195

  
196
    This should be used only when adding a node to a cluster, or in other
197
    infrequent operations such as cluster-rename or master-failover.
198

  
199
    """
200
    file_name = self.KeyToFilename(key)
201
    utils.WriteFile(file_name, data="%s\n" % str(value),
202
                    uid=0, gid=0, mode=0400)
203

  
204

  
205 38
class SimpleConfigReader:
206 39
  """Simple class to read configuration file.
207 40

  

Also available in: Unified diff