Package ganeti :: Package hypervisor :: Module hv_fake
[hide private]
[frames] | no frames]

Source Code for Module ganeti.hypervisor.hv_fake

  1  # 
  2  # 
  3   
  4  # Copyright (C) 2006, 2007, 2008 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  """Fake hypervisor 
 23   
 24  """ 
 25   
 26  import os 
 27  import os.path 
 28  import logging 
 29   
 30  from ganeti import utils 
 31  from ganeti import constants 
 32  from ganeti import errors 
 33  from ganeti import objects 
 34  from ganeti import pathutils 
 35  from ganeti.hypervisor import hv_base 
36 37 38 -class FakeHypervisor(hv_base.BaseHypervisor):
39 """Fake hypervisor interface. 40 41 This can be used for testing the ganeti code without having to have 42 a real virtualisation software installed. 43 44 """ 45 CAN_MIGRATE = True 46 47 _ROOT_DIR = pathutils.RUN_DIR + "/fake-hypervisor" 48
49 - def __init__(self):
52
53 - def ListInstances(self):
54 """Get the list of running instances. 55 56 """ 57 return os.listdir(self._ROOT_DIR)
58
59 - def GetInstanceInfo(self, instance_name):
60 """Get instance properties. 61 62 @param instance_name: the instance name 63 64 @return: tuple of (name, id, memory, vcpus, stat, times) 65 66 """ 67 file_name = self._InstanceFile(instance_name) 68 if not os.path.exists(file_name): 69 return None 70 try: 71 fh = open(file_name, "r") 72 try: 73 inst_id = fh.readline().strip() 74 memory = utils.TryConvert(int, fh.readline().strip()) 75 vcpus = utils.TryConvert(int, fh.readline().strip()) 76 stat = "---b-" 77 times = "0" 78 return (instance_name, inst_id, memory, vcpus, stat, times) 79 finally: 80 fh.close() 81 except IOError, err: 82 raise errors.HypervisorError("Failed to list instance %s: %s" % 83 (instance_name, err))
84
85 - def GetAllInstancesInfo(self):
86 """Get properties of all instances. 87 88 @return: list of tuples (name, id, memory, vcpus, stat, times) 89 90 """ 91 data = [] 92 for file_name in os.listdir(self._ROOT_DIR): 93 try: 94 fh = open(utils.PathJoin(self._ROOT_DIR, file_name), "r") 95 inst_id = "-1" 96 memory = 0 97 vcpus = 1 98 stat = "-----" 99 times = "-1" 100 try: 101 inst_id = fh.readline().strip() 102 memory = utils.TryConvert(int, fh.readline().strip()) 103 vcpus = utils.TryConvert(int, fh.readline().strip()) 104 stat = "---b-" 105 times = "0" 106 finally: 107 fh.close() 108 data.append((file_name, inst_id, memory, vcpus, stat, times)) 109 except IOError, err: 110 raise errors.HypervisorError("Failed to list instances: %s" % err) 111 return data
112 113 @classmethod
114 - def _InstanceFile(cls, instance_name):
115 """Compute the instance file for an instance name. 116 117 """ 118 return utils.PathJoin(cls._ROOT_DIR, instance_name)
119
120 - def _IsAlive(self, instance_name):
121 """Checks if an instance is alive. 122 123 """ 124 file_name = self._InstanceFile(instance_name) 125 return os.path.exists(file_name)
126
127 - def _MarkUp(self, instance, memory):
128 """Mark the instance as running. 129 130 This does no checks, which should be done by its callers. 131 132 """ 133 file_name = self._InstanceFile(instance.name) 134 fh = file(file_name, "w") 135 try: 136 fh.write("0\n%d\n%d\n" % 137 (memory, 138 instance.beparams[constants.BE_VCPUS])) 139 finally: 140 fh.close()
141
142 - def _MarkDown(self, instance_name):
143 """Mark the instance as running. 144 145 This does no checks, which should be done by its callers. 146 147 """ 148 file_name = self._InstanceFile(instance_name) 149 utils.RemoveFile(file_name)
150
151 - def StartInstance(self, instance, block_devices, startup_paused):
152 """Start an instance. 153 154 For the fake hypervisor, it just creates a file in the base dir, 155 creating an exception if it already exists. We don't actually 156 handle race conditions properly, since these are *FAKE* instances. 157 158 """ 159 if self._IsAlive(instance.name): 160 raise errors.HypervisorError("Failed to start instance %s: %s" % 161 (instance.name, "already running")) 162 try: 163 self._MarkUp(instance, self._InstanceStartupMemory(instance)) 164 except IOError, err: 165 raise errors.HypervisorError("Failed to start instance %s: %s" % 166 (instance.name, err))
167
168 - def StopInstance(self, instance, force=False, retry=False, name=None, 169 timeout=None):
170 """Stop an instance. 171 172 For the fake hypervisor, this just removes the file in the base 173 dir, if it exist, otherwise we raise an exception. 174 175 """ 176 assert(timeout is None or force is not None) 177 178 if name is None: 179 name = instance.name 180 if not self._IsAlive(name): 181 raise errors.HypervisorError("Failed to stop instance %s: %s" % 182 (name, "not running")) 183 self._MarkDown(name)
184
185 - def RebootInstance(self, instance):
186 """Reboot an instance. 187 188 For the fake hypervisor, this does nothing. 189 190 """ 191 return
192
193 - def BalloonInstanceMemory(self, instance, mem):
194 """Balloon an instance memory to a certain value. 195 196 @type instance: L{objects.Instance} 197 @param instance: instance to be accepted 198 @type mem: int 199 @param mem: actual memory size to use for instance runtime 200 201 """ 202 if not self._IsAlive(instance.name): 203 raise errors.HypervisorError("Failed to balloon memory for %s: %s" % 204 (instance.name, "not running")) 205 try: 206 self._MarkUp(instance, mem) 207 except EnvironmentError, err: 208 raise errors.HypervisorError("Failed to balloon memory for %s: %s" % 209 (instance.name, utils.ErrnoOrStr(err)))
210
211 - def GetNodeInfo(self):
212 """Return information about the node. 213 214 This is just a wrapper over the base GetLinuxNodeInfo method. 215 216 @return: a dict with the following keys (values in MiB): 217 - memory_total: the total memory size on the node 218 - memory_free: the available memory on the node for instances 219 - memory_dom0: the memory used by the node itself, if available 220 221 """ 222 result = self.GetLinuxNodeInfo() 223 # substract running instances 224 all_instances = self.GetAllInstancesInfo() 225 result["memory_free"] -= min(result["memory_free"], 226 sum([row[2] for row in all_instances])) 227 return result
228 229 @classmethod
230 - def GetInstanceConsole(cls, instance, hvparams, beparams):
231 """Return information for connecting to the console of an instance. 232 233 """ 234 return objects.InstanceConsole(instance=instance.name, 235 kind=constants.CONS_MESSAGE, 236 message=("Console not available for fake" 237 " hypervisor"))
238
239 - def Verify(self):
240 """Verify the hypervisor. 241 242 For the fake hypervisor, it just checks the existence of the base 243 dir. 244 245 @return: Problem description if something is wrong, C{None} otherwise 246 247 """ 248 if os.path.exists(self._ROOT_DIR): 249 return None 250 else: 251 return "The required directory '%s' does not exist" % self._ROOT_DIR
252 253 @classmethod
254 - def PowercycleNode(cls):
255 """Fake hypervisor powercycle, just a wrapper over Linux powercycle. 256 257 """ 258 cls.LinuxPowercycle()
259
260 - def AcceptInstance(self, instance, info, target):
261 """Prepare to accept an instance. 262 263 @type instance: L{objects.Instance} 264 @param instance: instance to be accepted 265 @type info: string 266 @param info: instance info, not used 267 @type target: string 268 @param target: target host (usually ip), on this node 269 270 """ 271 if self._IsAlive(instance.name): 272 raise errors.HypervisorError("Can't accept instance, already running")
273
274 - def MigrateInstance(self, instance, target, live):
275 """Migrate an instance. 276 277 @type instance: L{objects.Instance} 278 @param instance: the instance to be migrated 279 @type target: string 280 @param target: hostname (usually ip) of the target node 281 @type live: boolean 282 @param live: whether to do a live or non-live migration 283 284 """ 285 logging.debug("Fake hypervisor migrating %s to %s (live=%s)", 286 instance, target, live)
287
288 - def FinalizeMigrationDst(self, instance, info, success):
289 """Finalize the instance migration on the target node. 290 291 For the fake hv, this just marks the instance up. 292 293 @type instance: L{objects.Instance} 294 @param instance: instance whose migration is being finalized 295 @type info: string/data (opaque) 296 @param info: migration information, from the source node 297 @type success: boolean 298 @param success: whether the migration was a success or a failure 299 300 """ 301 if success: 302 self._MarkUp(instance, self._InstanceStartupMemory(instance)) 303 else: 304 # ensure it's down 305 self._MarkDown(instance.name)
306
307 - def PostMigrationCleanup(self, instance):
308 """Clean-up after a migration. 309 310 To be executed on the source node. 311 312 @type instance: L{objects.Instance} 313 @param instance: the instance that was migrated 314 315 """ 316 pass
317
318 - def FinalizeMigrationSource(self, instance, success, live):
319 """Finalize the instance migration on the source node. 320 321 @type instance: L{objects.Instance} 322 @param instance: the instance that was migrated 323 @type success: bool 324 @param success: whether the migration succeeded or not 325 @type live: bool 326 @param live: whether the user requested a live migration or not 327 328 """ 329 # pylint: disable=W0613 330 if success: 331 self._MarkDown(instance.name)
332
333 - def GetMigrationStatus(self, instance):
334 """Get the migration status 335 336 The fake hypervisor migration always succeeds. 337 338 @type instance: L{objects.Instance} 339 @param instance: the instance that is being migrated 340 @rtype: L{objects.MigrationStatus} 341 @return: the status of the current migration (one of 342 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 343 progress info that can be retrieved from the hypervisor 344 345 """ 346 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
347