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