Statistics
| Branch: | Tag: | Revision:

root / lib / vcluster.py @ 2958c56e

History | View | Annotate | Download (7.2 kB)

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

24 9340cc2b Michael Hanselmann
Most functions manipulate file system paths and are no-ops when the environment
25 9340cc2b Michael Hanselmann
variables C{GANETI_ROOTDIR} and C{GANETI_HOSTNAME} are not set. See the
26 9340cc2b Michael Hanselmann
functions' docstrings for details.
27 05e733b4 Michael Hanselmann

28 05e733b4 Michael Hanselmann
"""
29 05e733b4 Michael Hanselmann
30 05e733b4 Michael Hanselmann
import os
31 05e733b4 Michael Hanselmann
32 05e733b4 Michael Hanselmann
from ganeti import compat
33 05e733b4 Michael Hanselmann
34 05e733b4 Michael Hanselmann
35 05e733b4 Michael Hanselmann
_VIRT_PATH_PREFIX = "/###-VIRTUAL-PATH-###,"
36 05e733b4 Michael Hanselmann
_ROOTDIR_ENVNAME = "GANETI_ROOTDIR"
37 05e733b4 Michael Hanselmann
_HOSTNAME_ENVNAME = "GANETI_HOSTNAME"
38 05e733b4 Michael Hanselmann
39 05e733b4 Michael Hanselmann
40 05e733b4 Michael Hanselmann
def _GetRootDirectory(envname):
41 05e733b4 Michael Hanselmann
  """Retrieves root directory from an environment variable.
42 05e733b4 Michael Hanselmann

43 05e733b4 Michael Hanselmann
  @type envname: string
44 05e733b4 Michael Hanselmann
  @param envname: Environment variable name
45 05e733b4 Michael Hanselmann
  @rtype: string
46 05e733b4 Michael Hanselmann
  @return: Root directory (can be empty)
47 05e733b4 Michael Hanselmann

48 05e733b4 Michael Hanselmann
  """
49 05e733b4 Michael Hanselmann
  path = os.getenv(envname)
50 05e733b4 Michael Hanselmann
51 05e733b4 Michael Hanselmann
  if path:
52 05e733b4 Michael Hanselmann
    if not os.path.isabs(path):
53 05e733b4 Michael Hanselmann
      raise RuntimeError("Root directory in '%s' must be absolute: %s" %
54 05e733b4 Michael Hanselmann
                         (envname, path))
55 05e733b4 Michael Hanselmann
    return os.path.normpath(path)
56 05e733b4 Michael Hanselmann
57 05e733b4 Michael Hanselmann
  return ""
58 05e733b4 Michael Hanselmann
59 05e733b4 Michael Hanselmann
60 05e733b4 Michael Hanselmann
def _GetHostname(envname):
61 05e733b4 Michael Hanselmann
  """Retrieves virtual hostname from an environment variable.
62 05e733b4 Michael Hanselmann

63 05e733b4 Michael Hanselmann
  @type envname: string
64 05e733b4 Michael Hanselmann
  @param envname: Environment variable name
65 05e733b4 Michael Hanselmann
  @rtype: string
66 05e733b4 Michael Hanselmann
  @return: Host name (can be empty)
67 05e733b4 Michael Hanselmann

68 05e733b4 Michael Hanselmann
  """
69 05e733b4 Michael Hanselmann
  return os.getenv(envname, default="")
70 05e733b4 Michael Hanselmann
71 05e733b4 Michael Hanselmann
72 05e733b4 Michael Hanselmann
def _CheckHostname(hostname):
73 05e733b4 Michael Hanselmann
  """Very basic check for hostnames.
74 05e733b4 Michael Hanselmann

75 05e733b4 Michael Hanselmann
  @type hostname: string
76 05e733b4 Michael Hanselmann
  @param hostname: Hostname
77 05e733b4 Michael Hanselmann

78 05e733b4 Michael Hanselmann
  """
79 05e733b4 Michael Hanselmann
  if os.path.basename(hostname) != hostname:
80 05e733b4 Michael Hanselmann
    raise RuntimeError("Hostname '%s' can not be used for a file system"
81 05e733b4 Michael Hanselmann
                       " path" % hostname)
82 05e733b4 Michael Hanselmann
83 05e733b4 Michael Hanselmann
84 05e733b4 Michael Hanselmann
def _PreparePaths(rootdir, hostname):
85 05e733b4 Michael Hanselmann
  """Checks if the root directory and hostname are acceptable.
86 05e733b4 Michael Hanselmann

87 9340cc2b Michael Hanselmann
  The (node-specific) root directory must have the hostname as its last
88 9340cc2b Michael Hanselmann
  component. The parent directory then becomes the cluster-wide root directory.
89 9340cc2b Michael Hanselmann
  This is necessary as some components must be able to predict the root path on
90 9340cc2b Michael Hanselmann
  a remote node (e.g. copying files via scp).
91 9340cc2b Michael Hanselmann

92 05e733b4 Michael Hanselmann
  @type rootdir: string
93 05e733b4 Michael Hanselmann
  @param rootdir: Root directory (from environment)
94 05e733b4 Michael Hanselmann
  @type hostname: string
95 05e733b4 Michael Hanselmann
  @param hostname: Hostname (from environment)
96 05e733b4 Michael Hanselmann
  @rtype: tuple; (string, string, string or None)
97 05e733b4 Michael Hanselmann
  @return: Tuple containing cluster-global root directory, node root directory
98 05e733b4 Michael Hanselmann
    and virtual hostname
99 05e733b4 Michael Hanselmann

100 05e733b4 Michael Hanselmann
  """
101 05e733b4 Michael Hanselmann
  if bool(rootdir) ^ bool(hostname):
102 05e733b4 Michael Hanselmann
    raise RuntimeError("Both root directory and hostname must be specified"
103 05e733b4 Michael Hanselmann
                       " using the environment variables %s and %s" %
104 05e733b4 Michael Hanselmann
                       (_ROOTDIR_ENVNAME, _HOSTNAME_ENVNAME))
105 05e733b4 Michael Hanselmann
106 05e733b4 Michael Hanselmann
  if rootdir:
107 05e733b4 Michael Hanselmann
    assert rootdir == os.path.normpath(rootdir)
108 05e733b4 Michael Hanselmann
109 05e733b4 Michael Hanselmann
    _CheckHostname(hostname)
110 05e733b4 Michael Hanselmann
111 05e733b4 Michael Hanselmann
    if os.path.basename(rootdir) != hostname:
112 05e733b4 Michael Hanselmann
      raise RuntimeError("Last component of root directory ('%s') must match"
113 05e733b4 Michael Hanselmann
                         " hostname ('%s')" % (rootdir, hostname))
114 05e733b4 Michael Hanselmann
115 05e733b4 Michael Hanselmann
    return (os.path.dirname(rootdir), rootdir, hostname)
116 05e733b4 Michael Hanselmann
  else:
117 05e733b4 Michael Hanselmann
    return ("", "", None)
118 05e733b4 Michael Hanselmann
119 05e733b4 Michael Hanselmann
120 05e733b4 Michael Hanselmann
(_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME) = \
121 05e733b4 Michael Hanselmann
  _PreparePaths(_GetRootDirectory(_ROOTDIR_ENVNAME),
122 05e733b4 Michael Hanselmann
                _GetHostname(_HOSTNAME_ENVNAME))
123 05e733b4 Michael Hanselmann
124 05e733b4 Michael Hanselmann
125 05e733b4 Michael Hanselmann
assert (compat.all([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME]) or
126 05e733b4 Michael Hanselmann
        not compat.any([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME]))
127 05e733b4 Michael Hanselmann
128 05e733b4 Michael Hanselmann
129 05e733b4 Michael Hanselmann
def GetVirtualHostname():
130 05e733b4 Michael Hanselmann
  """Returns the virtual hostname.
131 05e733b4 Michael Hanselmann

132 05e733b4 Michael Hanselmann
  @rtype: string or L{None}
133 05e733b4 Michael Hanselmann

134 05e733b4 Michael Hanselmann
  """
135 05e733b4 Michael Hanselmann
  return _VIRT_HOSTNAME
136 05e733b4 Michael Hanselmann
137 05e733b4 Michael Hanselmann
138 05e733b4 Michael Hanselmann
def _MakeNodeRoot(base, node_name):
139 05e733b4 Michael Hanselmann
  """Appends a node name to the base directory.
140 05e733b4 Michael Hanselmann

141 05e733b4 Michael Hanselmann
  """
142 05e733b4 Michael Hanselmann
  _CheckHostname(node_name)
143 05e733b4 Michael Hanselmann
  return os.path.normpath("%s/%s" % (base, node_name))
144 05e733b4 Michael Hanselmann
145 05e733b4 Michael Hanselmann
146 05e733b4 Michael Hanselmann
def ExchangeNodeRoot(node_name, filename,
147 05e733b4 Michael Hanselmann
                     _basedir=_VIRT_BASEDIR, _noderoot=_VIRT_NODEROOT):
148 05e733b4 Michael Hanselmann
  """Replaces the node-specific root directory in a path.
149 05e733b4 Michael Hanselmann

150 9340cc2b Michael Hanselmann
  Replaces it with the root directory for another node. Assuming
151 9340cc2b Michael Hanselmann
  C{/tmp/vcluster/node1} is the root directory for C{node1}, the result will be
152 9340cc2b Michael Hanselmann
  C{/tmp/vcluster/node3} for C{node3} (as long as a root directory is specified
153 9340cc2b Michael Hanselmann
  in the environment).
154 05e733b4 Michael Hanselmann

155 05e733b4 Michael Hanselmann
  """
156 05e733b4 Michael Hanselmann
  if _basedir:
157 05e733b4 Michael Hanselmann
    pure = _RemoveNodePrefix(filename, _noderoot=_noderoot)
158 05e733b4 Michael Hanselmann
    result = "%s/%s" % (_MakeNodeRoot(_basedir, node_name), pure)
159 05e733b4 Michael Hanselmann
  else:
160 05e733b4 Michael Hanselmann
    result = filename
161 05e733b4 Michael Hanselmann
162 05e733b4 Michael Hanselmann
  return os.path.normpath(result)
163 05e733b4 Michael Hanselmann
164 05e733b4 Michael Hanselmann
165 05e733b4 Michael Hanselmann
def EnvironmentForHost(hostname, _basedir=_VIRT_BASEDIR):
166 05e733b4 Michael Hanselmann
  """Returns the environment variables for a host.
167 05e733b4 Michael Hanselmann

168 05e733b4 Michael Hanselmann
  """
169 05e733b4 Michael Hanselmann
  if _basedir:
170 05e733b4 Michael Hanselmann
    return {
171 05e733b4 Michael Hanselmann
      _ROOTDIR_ENVNAME: _MakeNodeRoot(_basedir, hostname),
172 05e733b4 Michael Hanselmann
      _HOSTNAME_ENVNAME: hostname,
173 05e733b4 Michael Hanselmann
      }
174 05e733b4 Michael Hanselmann
  else:
175 05e733b4 Michael Hanselmann
    return {}
176 05e733b4 Michael Hanselmann
177 05e733b4 Michael Hanselmann
178 05e733b4 Michael Hanselmann
def AddNodePrefix(path, _noderoot=_VIRT_NODEROOT):
179 05e733b4 Michael Hanselmann
  """Adds a node-specific prefix to a path in a virtual cluster.
180 05e733b4 Michael Hanselmann

181 05e733b4 Michael Hanselmann
  Returned path includes user-specified root directory if specified in
182 9340cc2b Michael Hanselmann
  environment. As an example, the path C{/var/lib/ganeti} becomes
183 9340cc2b Michael Hanselmann
  C{/tmp/vcluster/node1/var/lib/ganeti} if C{/tmp/vcluster/node1} is the root
184 9340cc2b Michael Hanselmann
  directory specified in the environment.
185 05e733b4 Michael Hanselmann

186 05e733b4 Michael Hanselmann
  """
187 05e733b4 Michael Hanselmann
  assert os.path.isabs(path)
188 05e733b4 Michael Hanselmann
189 05e733b4 Michael Hanselmann
  if _noderoot:
190 05e733b4 Michael Hanselmann
    result = "%s/%s" % (_noderoot, path)
191 05e733b4 Michael Hanselmann
  else:
192 05e733b4 Michael Hanselmann
    result = path
193 05e733b4 Michael Hanselmann
194 05e733b4 Michael Hanselmann
  assert os.path.isabs(result)
195 05e733b4 Michael Hanselmann
196 05e733b4 Michael Hanselmann
  return os.path.normpath(result)
197 05e733b4 Michael Hanselmann
198 05e733b4 Michael Hanselmann
199 05e733b4 Michael Hanselmann
def _RemoveNodePrefix(path, _noderoot=_VIRT_NODEROOT):
200 05e733b4 Michael Hanselmann
  """Removes the node-specific prefix from a path.
201 05e733b4 Michael Hanselmann

202 9340cc2b Michael Hanselmann
  This is the opposite of L{AddNodePrefix} and removes a node-local prefix
203 9340cc2b Michael Hanselmann
  path.
204 9340cc2b Michael Hanselmann

205 05e733b4 Michael Hanselmann
  """
206 05e733b4 Michael Hanselmann
  assert os.path.isabs(path)
207 05e733b4 Michael Hanselmann
208 05e733b4 Michael Hanselmann
  norm_path = os.path.normpath(path)
209 05e733b4 Michael Hanselmann
210 05e733b4 Michael Hanselmann
  if _noderoot:
211 05e733b4 Michael Hanselmann
    # Make sure path is actually below node root
212 05e733b4 Michael Hanselmann
    norm_root = os.path.normpath(_noderoot)
213 05e733b4 Michael Hanselmann
    root_with_sep = "%s%s" % (norm_root, os.sep)
214 05e733b4 Michael Hanselmann
    prefix = os.path.commonprefix([root_with_sep, norm_path])
215 05e733b4 Michael Hanselmann
216 05e733b4 Michael Hanselmann
    if prefix == root_with_sep:
217 05e733b4 Michael Hanselmann
      result = norm_path[len(norm_root):]
218 05e733b4 Michael Hanselmann
    else:
219 05e733b4 Michael Hanselmann
      raise RuntimeError("Path '%s' is not below node root '%s'" %
220 05e733b4 Michael Hanselmann
                         (path, _noderoot))
221 05e733b4 Michael Hanselmann
  else:
222 05e733b4 Michael Hanselmann
    result = norm_path
223 05e733b4 Michael Hanselmann
224 05e733b4 Michael Hanselmann
  assert os.path.isabs(result)
225 05e733b4 Michael Hanselmann
226 05e733b4 Michael Hanselmann
  return result
227 05e733b4 Michael Hanselmann
228 05e733b4 Michael Hanselmann
229 05e733b4 Michael Hanselmann
def MakeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
230 05e733b4 Michael Hanselmann
  """Virtualizes a path.
231 05e733b4 Michael Hanselmann

232 05e733b4 Michael Hanselmann
  A path is "virtualized" by stripping it of its node-specific directory and
233 05e733b4 Michael Hanselmann
  prepending a prefix (L{_VIRT_PATH_PREFIX}). Use L{LocalizeVirtualPath} to
234 9340cc2b Michael Hanselmann
  undo the process. Virtual paths are meant to be transported via RPC.
235 05e733b4 Michael Hanselmann

236 05e733b4 Michael Hanselmann
  """
237 05e733b4 Michael Hanselmann
  assert os.path.isabs(path)
238 05e733b4 Michael Hanselmann
239 05e733b4 Michael Hanselmann
  if _noderoot:
240 05e733b4 Michael Hanselmann
    return _VIRT_PATH_PREFIX + _RemoveNodePrefix(path, _noderoot=_noderoot)
241 05e733b4 Michael Hanselmann
  else:
242 05e733b4 Michael Hanselmann
    return path
243 05e733b4 Michael Hanselmann
244 05e733b4 Michael Hanselmann
245 05e733b4 Michael Hanselmann
def LocalizeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
246 05e733b4 Michael Hanselmann
  """Localizes a virtual path.
247 05e733b4 Michael Hanselmann

248 05e733b4 Michael Hanselmann
  A "virtualized" path consists of a prefix (L{LocalizeVirtualPath}) and a
249 05e733b4 Michael Hanselmann
  local path. This function adds the node-specific directory to the local path.
250 9340cc2b Michael Hanselmann
  Virtual paths are meant to be transported via RPC.
251 05e733b4 Michael Hanselmann

252 05e733b4 Michael Hanselmann
  """
253 05e733b4 Michael Hanselmann
  assert os.path.isabs(path)
254 05e733b4 Michael Hanselmann
255 05e733b4 Michael Hanselmann
  if _noderoot:
256 05e733b4 Michael Hanselmann
    if path.startswith(_VIRT_PATH_PREFIX):
257 05e733b4 Michael Hanselmann
      return AddNodePrefix(path[len(_VIRT_PATH_PREFIX):], _noderoot=_noderoot)
258 05e733b4 Michael Hanselmann
    else:
259 05e733b4 Michael Hanselmann
      raise RuntimeError("Path '%s' is not a virtual path" % path)
260 05e733b4 Michael Hanselmann
  else:
261 05e733b4 Michael Hanselmann
    return path