Package ganeti :: Module vcluster
[hide private]
[frames] | no frames]

Source Code for Module ganeti.vcluster

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2012 Google Inc. 
  5  # All rights reserved. 
  6  # 
  7  # Redistribution and use in source and binary forms, with or without 
  8  # modification, are permitted provided that the following conditions are 
  9  # met: 
 10  # 
 11  # 1. Redistributions of source code must retain the above copyright notice, 
 12  # this list of conditions and the following disclaimer. 
 13  # 
 14  # 2. Redistributions in binary form must reproduce the above copyright 
 15  # notice, this list of conditions and the following disclaimer in the 
 16  # documentation and/or other materials provided with the distribution. 
 17  # 
 18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
 19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
 20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
 25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
 26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
 27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29   
 30   
 31  """Module containing utilities for virtual clusters. 
 32   
 33  Most functions manipulate file system paths and are no-ops when the environment 
 34  variables C{GANETI_ROOTDIR} and C{GANETI_HOSTNAME} are not set. See the 
 35  functions' docstrings for details. 
 36   
 37  """ 
 38   
 39  import os 
 40   
 41  from ganeti import compat 
 42  from ganeti import _constants 
 43  # cannot use constants, as this would cause a circular import 
 44   
 45   
 46  ETC_HOSTS = _constants.V_CLUSTER_ETC_HOSTS 
 47   
 48  _VIRT_PATH_PREFIX = _constants.V_CLUSTER_VIRT_PATH_PREFIX 
 49  _ROOTDIR_ENVNAME = _constants.V_CLUSTER_ROOTDIR_ENVNAME 
 50  _HOSTNAME_ENVNAME = _constants.V_CLUSTER_HOSTNAME_ENVNAME 
 51   
 52  #: List of paths which shouldn't be virtualized 
 53  _VPATH_WHITELIST = _constants.V_CLUSTER_VPATH_WHITELIST 
 54   
 55   
56 -def _GetRootDirectory(envname):
57 """Retrieves root directory from an environment variable. 58 59 @type envname: string 60 @param envname: Environment variable name 61 @rtype: string 62 @return: Root directory (can be empty) 63 64 """ 65 path = os.getenv(envname) 66 67 if path: 68 if not os.path.isabs(path): 69 raise RuntimeError("Root directory in '%s' must be absolute: %s" % 70 (envname, path)) 71 return os.path.normpath(path) 72 73 return ""
74 75
76 -def _GetHostname(envname):
77 """Retrieves virtual hostname from an environment variable. 78 79 @type envname: string 80 @param envname: Environment variable name 81 @rtype: string 82 @return: Host name (can be empty) 83 84 """ 85 return os.getenv(envname, default="")
86 87
88 -def _CheckHostname(hostname):
89 """Very basic check for hostnames. 90 91 @type hostname: string 92 @param hostname: Hostname 93 94 """ 95 if os.path.basename(hostname) != hostname: 96 raise RuntimeError("Hostname '%s' can not be used for a file system" 97 " path" % hostname)
98 99
100 -def _PreparePaths(rootdir, hostname):
101 """Checks if the root directory and hostname are acceptable. 102 103 The (node-specific) root directory must have the hostname as its last 104 component. The parent directory then becomes the cluster-wide root directory. 105 This is necessary as some components must be able to predict the root path on 106 a remote node (e.g. copying files via scp). 107 108 @type rootdir: string 109 @param rootdir: Root directory (from environment) 110 @type hostname: string 111 @param hostname: Hostname (from environment) 112 @rtype: tuple; (string, string, string or None) 113 @return: Tuple containing cluster-global root directory, node root directory 114 and virtual hostname 115 116 """ 117 if bool(rootdir) ^ bool(hostname): 118 raise RuntimeError("Both root directory and hostname must be specified" 119 " using the environment variables %s and %s" % 120 (_ROOTDIR_ENVNAME, _HOSTNAME_ENVNAME)) 121 122 if rootdir: 123 assert rootdir == os.path.normpath(rootdir), "Not normalized: " + rootdir 124 125 _CheckHostname(hostname) 126 127 if os.path.basename(rootdir) != hostname: 128 raise RuntimeError("Last component of root directory ('%s') must match" 129 " hostname ('%s')" % (rootdir, hostname)) 130 131 return (os.path.dirname(rootdir), rootdir, hostname) 132 else: 133 return ("", "", None)
134 135 136 (_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME) = \ 137 _PreparePaths(_GetRootDirectory(_ROOTDIR_ENVNAME), 138 _GetHostname(_HOSTNAME_ENVNAME)) 139 140 141 assert (compat.all([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME]) or 142 not compat.any([_VIRT_BASEDIR, _VIRT_NODEROOT, _VIRT_HOSTNAME])) 143 144
145 -def GetVirtualHostname():
146 """Returns the virtual hostname. 147 148 @rtype: string or L{None} 149 150 """ 151 return _VIRT_HOSTNAME
152 153
154 -def MakeNodeRoot(base, node_name):
155 """Appends a node name to the base directory. 156 157 """ 158 _CheckHostname(node_name) 159 return os.path.normpath("%s/%s" % (base, node_name))
160 161
162 -def ExchangeNodeRoot(node_name, filename, 163 _basedir=_VIRT_BASEDIR, _noderoot=_VIRT_NODEROOT):
164 """Replaces the node-specific root directory in a path. 165 166 Replaces it with the root directory for another node. Assuming 167 C{/tmp/vcluster/node1} is the root directory for C{node1}, the result will be 168 C{/tmp/vcluster/node3} for C{node3} (as long as a root directory is specified 169 in the environment). 170 171 """ 172 if _basedir: 173 pure = _RemoveNodePrefix(filename, _noderoot=_noderoot) 174 result = "%s/%s" % (MakeNodeRoot(_basedir, node_name), pure) 175 else: 176 result = filename 177 178 return os.path.normpath(result)
179 180
181 -def EnvironmentForHost(hostname, _basedir=_VIRT_BASEDIR):
182 """Returns the environment variables for a host. 183 184 """ 185 if _basedir: 186 return { 187 _ROOTDIR_ENVNAME: MakeNodeRoot(_basedir, hostname), 188 _HOSTNAME_ENVNAME: hostname, 189 } 190 else: 191 return {}
192 193
194 -def AddNodePrefix(path, _noderoot=_VIRT_NODEROOT):
195 """Adds a node-specific prefix to a path in a virtual cluster. 196 197 Returned path includes user-specified root directory if specified in 198 environment. As an example, the path C{/var/lib/ganeti} becomes 199 C{/tmp/vcluster/node1/var/lib/ganeti} if C{/tmp/vcluster/node1} is the root 200 directory specified in the environment. 201 202 """ 203 assert os.path.isabs(path), "Path not absolute: " + path 204 205 if _noderoot: 206 result = "%s/%s" % (_noderoot, path) 207 else: 208 result = path 209 210 assert os.path.isabs(result), "Path not absolute: " + path 211 212 return os.path.normpath(result)
213 214
215 -def _RemoveNodePrefix(path, _noderoot=_VIRT_NODEROOT):
216 """Removes the node-specific prefix from a path. 217 218 This is the opposite of L{AddNodePrefix} and removes a node-local prefix 219 path. 220 221 """ 222 assert os.path.isabs(path), "Path not absolute: " + path 223 224 norm_path = os.path.normpath(path) 225 226 if _noderoot: 227 # Make sure path is actually below node root 228 norm_root = os.path.normpath(_noderoot) 229 root_with_sep = "%s%s" % (norm_root, os.sep) 230 prefix = os.path.commonprefix([root_with_sep, norm_path]) 231 232 if prefix == root_with_sep: 233 result = norm_path[len(norm_root):] 234 else: 235 raise RuntimeError("Path '%s' is not below node root '%s'" % 236 (path, _noderoot)) 237 else: 238 result = norm_path 239 240 assert os.path.isabs(result), "Path not absolute: " + path 241 242 return result
243 244
245 -def MakeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
246 """Virtualizes a path. 247 248 A path is "virtualized" by stripping it of its node-specific directory and 249 prepending a prefix (L{_VIRT_PATH_PREFIX}). Use L{LocalizeVirtualPath} to 250 undo the process. Virtual paths are meant to be transported via RPC. 251 252 """ 253 assert os.path.isabs(path), "Path not absolute: " + path 254 255 if _noderoot and path not in _VPATH_WHITELIST: 256 return _VIRT_PATH_PREFIX + _RemoveNodePrefix(path, _noderoot=_noderoot) 257 else: 258 return path
259 260
261 -def LocalizeVirtualPath(path, _noderoot=_VIRT_NODEROOT):
262 """Localizes a virtual path. 263 264 A "virtualized" path consists of a prefix (L{LocalizeVirtualPath}) and a 265 local path. This function adds the node-specific directory to the local path. 266 Virtual paths are meant to be transported via RPC. 267 268 """ 269 assert os.path.isabs(path), "Path not absolute: " + path 270 271 if _noderoot and path not in _VPATH_WHITELIST: 272 if path.startswith(_VIRT_PATH_PREFIX): 273 return AddNodePrefix(path[len(_VIRT_PATH_PREFIX):], _noderoot=_noderoot) 274 else: 275 raise RuntimeError("Path '%s' is not a virtual path" % path) 276 else: 277 return path
278