Statistics
| Branch: | Tag: | Revision:

root / lib / vcluster.py @ 05e733b4

History | View | Annotate | Download (6.2 kB)

1
#
2
#
3

    
4
# Copyright (C) 2012 Google Inc.
5
#
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#
11
# This program is distributed in the hope that it will be useful, but
12
# WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
# General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
# 02110-1301, USA.
20

    
21

    
22
"""Module containing utilities for virtual clusters.
23

24

25
"""
26

    
27
import os
28

    
29
from ganeti import compat
30

    
31

    
32
_VIRT_PATH_PREFIX = "/###-VIRTUAL-PATH-###,"
33
_ROOTDIR_ENVNAME = "GANETI_ROOTDIR"
34
_HOSTNAME_ENVNAME = "GANETI_HOSTNAME"
35

    
36

    
37
def _GetRootDirectory(envname):
38
  """Retrieves root directory from an environment variable.
39

40
  @type envname: string
41
  @param envname: Environment variable name
42
  @rtype: string
43
  @return: Root directory (can be empty)
44

45
  """
46
  path = os.getenv(envname)
47

    
48
  if path:
49
    if not os.path.isabs(path):
50
      raise RuntimeError("Root directory in '%s' must be absolute: %s" %
51
                         (envname, path))
52
    return os.path.normpath(path)
53

    
54
  return ""
55

    
56

    
57
def _GetHostname(envname):
58
  """Retrieves virtual hostname from an environment variable.
59

60
  @type envname: string
61
  @param envname: Environment variable name
62
  @rtype: string
63
  @return: Host name (can be empty)
64

65
  """
66
  return os.getenv(envname, default="")
67

    
68

    
69
def _CheckHostname(hostname):
70
  """Very basic check for hostnames.
71

72
  @type hostname: string
73
  @param hostname: Hostname
74

75
  """
76
  if os.path.basename(hostname) != hostname:
77
    raise RuntimeError("Hostname '%s' can not be used for a file system"
78
                       " path" % hostname)
79

    
80

    
81
def _PreparePaths(rootdir, hostname):
82
  """Checks if the root directory and hostname are acceptable.
83

84
  @type rootdir: string
85
  @param rootdir: Root directory (from environment)
86
  @type hostname: string
87
  @param hostname: Hostname (from environment)
88
  @rtype: tuple; (string, string, string or None)
89
  @return: Tuple containing cluster-global root directory, node root directory
90
    and virtual hostname
91

92
  """
93
  if bool(rootdir) ^ bool(hostname):
94
    raise RuntimeError("Both root directory and hostname must be specified"
95
                       " using the environment variables %s and %s" %
96
                       (_ROOTDIR_ENVNAME, _HOSTNAME_ENVNAME))
97

    
98
  if rootdir:
99
    assert rootdir == os.path.normpath(rootdir)
100

    
101
    _CheckHostname(hostname)
102

    
103
    if os.path.basename(rootdir) != hostname:
104
      raise RuntimeError("Last component of root directory ('%s') must match"
105
                         " hostname ('%s')" % (rootdir, hostname))
106

    
107
    return (os.path.dirname(rootdir), rootdir, hostname)
108
  else:
109
    return ("", "", None)
110

    
111

    
112
(_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME) = \
113
  _PreparePaths(_GetRootDirectory(_ROOTDIR_ENVNAME),
114
                _GetHostname(_HOSTNAME_ENVNAME))
115

    
116

    
117
assert (compat.all([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME]) or
118
        not compat.any([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME]))
119

    
120

    
121
def GetVirtualHostname():
122
  """Returns the virtual hostname.
123

124
  @rtype: string or L{None}
125

126
  """
127
  return _VIRT_HOSTNAME
128

    
129

    
130
def _MakeNodeRoot(base, node_name):
131
  """Appends a node name to the base directory.
132

133
  """
134
  _CheckHostname(node_name)
135
  return os.path.normpath("%s/%s" % (base, node_name))
136

    
137

    
138
def ExchangeNodeRoot(node_name, filename,
139
                     _basedir=_VIRT_BASEDIR, _noderoot=_VIRT_NODEROOT):
140
  """Replaces the node-specific root directory in a path.
141

142
  Replaces it with the root directory for another node.
143

144
  """
145
  if _basedir:
146
    pure = _RemoveNodePrefix(filename, _noderoot=_noderoot)
147
    result = "%s/%s" % (_MakeNodeRoot(_basedir, node_name), pure)
148
  else:
149
    result = filename
150

    
151
  return os.path.normpath(result)
152

    
153

    
154
def EnvironmentForHost(hostname, _basedir=_VIRT_BASEDIR):
155
  """Returns the environment variables for a host.
156

157
  """
158
  if _basedir:
159
    return {
160
      _ROOTDIR_ENVNAME: _MakeNodeRoot(_basedir, hostname),
161
      _HOSTNAME_ENVNAME: hostname,
162
      }
163
  else:
164
    return {}
165

    
166

    
167
def AddNodePrefix(path, _noderoot=_VIRT_NODEROOT):
168
  """Adds a node-specific prefix to a path in a virtual cluster.
169

170
  Returned path includes user-specified root directory if specified in
171
  environment.
172

173
  """
174
  assert os.path.isabs(path)
175

    
176
  if _noderoot:
177
    result = "%s/%s" % (_noderoot, path)
178
  else:
179
    result = path
180

    
181
  assert os.path.isabs(result)
182

    
183
  return os.path.normpath(result)
184

    
185

    
186
def _RemoveNodePrefix(path, _noderoot=_VIRT_NODEROOT):
187
  """Removes the node-specific prefix from a path.
188

189
  """
190
  assert os.path.isabs(path)
191

    
192
  norm_path = os.path.normpath(path)
193

    
194
  if _noderoot:
195
    # Make sure path is actually below node root
196
    norm_root = os.path.normpath(_noderoot)
197
    root_with_sep = "%s%s" % (norm_root, os.sep)
198
    prefix = os.path.commonprefix([root_with_sep, norm_path])
199

    
200
    if prefix == root_with_sep:
201
      result = norm_path[len(norm_root):]
202
    else:
203
      raise RuntimeError("Path '%s' is not below node root '%s'" %
204
                         (path, _noderoot))
205
  else:
206
    result = norm_path
207

    
208
  assert os.path.isabs(result)
209

    
210
  return result
211

    
212

    
213
def MakeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
214
  """Virtualizes a path.
215

216
  A path is "virtualized" by stripping it of its node-specific directory and
217
  prepending a prefix (L{_VIRT_PATH_PREFIX}). Use L{LocalizeVirtualPath} to
218
  undo the process.
219

220
  """
221
  assert os.path.isabs(path)
222

    
223
  if _noderoot:
224
    return _VIRT_PATH_PREFIX + _RemoveNodePrefix(path, _noderoot=_noderoot)
225
  else:
226
    return path
227

    
228

    
229
def LocalizeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
230
  """Localizes a virtual path.
231

232
  A "virtualized" path consists of a prefix (L{LocalizeVirtualPath}) and a
233
  local path. This function adds the node-specific directory to the local path.
234

235
  """
236
  assert os.path.isabs(path)
237

    
238
  if _noderoot:
239
    if path.startswith(_VIRT_PATH_PREFIX):
240
      return AddNodePrefix(path[len(_VIRT_PATH_PREFIX):], _noderoot=_noderoot)
241
    else:
242
      raise RuntimeError("Path '%s' is not a virtual path" % path)
243
  else:
244
    return path