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 = "---b-" 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 = "-----" 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 = "---b-" 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, hvparams, beparams):
244 """Return information for connecting to the console of an instance. 245 246 """ 247 return objects.InstanceConsole(instance=instance.name, 248 kind=constants.CONS_MESSAGE, 249 message=("Console not available for fake" 250 " hypervisor"))
251
252 - def Verify(self, hvparams=None):
253 """Verify the hypervisor. 254 255 For the fake hypervisor, it just checks the existence of the base 256 dir. 257 258 @type hvparams: dict of strings 259 @param hvparams: hypervisor parameters to be verified against; not used 260 for fake hypervisors 261 262 @return: Problem description if something is wrong, C{None} otherwise 263 264 """ 265 if os.path.exists(self._ROOT_DIR): 266 return None 267 else: 268 return "The required directory '%s' does not exist" % self._ROOT_DIR
269 270 @classmethod
271 - def PowercycleNode(cls, hvparams=None):
272 """Fake hypervisor powercycle, just a wrapper over Linux powercycle. 273 274 @type hvparams: dict of strings 275 @param hvparams: hypervisor params to be used on this node 276 277 """ 278 cls.LinuxPowercycle()
279
280 - def AcceptInstance(self, instance, info, target):
281 """Prepare to accept an instance. 282 283 @type instance: L{objects.Instance} 284 @param instance: instance to be accepted 285 @type info: string 286 @param info: instance info, not used 287 @type target: string 288 @param target: target host (usually ip), on this node 289 290 """ 291 if self._IsAlive(instance.name): 292 raise errors.HypervisorError("Can't accept instance, already running")
293
294 - def MigrateInstance(self, cluster_name, instance, target, live):
295 """Migrate an instance. 296 297 @type cluster_name: string 298 @param cluster_name: name of the cluster 299 @type instance: L{objects.Instance} 300 @param instance: the instance to be migrated 301 @type target: string 302 @param target: hostname (usually ip) of the target node 303 @type live: boolean 304 @param live: whether to do a live or non-live migration 305 306 """ 307 logging.debug("Fake hypervisor migrating %s to %s (live=%s)", 308 instance, target, live)
309
310 - def FinalizeMigrationDst(self, instance, info, success):
311 """Finalize the instance migration on the target node. 312 313 For the fake hv, this just marks the instance up. 314 315 @type instance: L{objects.Instance} 316 @param instance: instance whose migration is being finalized 317 @type info: string/data (opaque) 318 @param info: migration information, from the source node 319 @type success: boolean 320 @param success: whether the migration was a success or a failure 321 322 """ 323 if success: 324 self._MarkUp(instance, self._InstanceStartupMemory(instance)) 325 else: 326 # ensure it's down 327 self._MarkDown(instance.name)
328
329 - def PostMigrationCleanup(self, instance):
330 """Clean-up after a migration. 331 332 To be executed on the source node. 333 334 @type instance: L{objects.Instance} 335 @param instance: the instance that was migrated 336 337 """ 338 pass
339
340 - def FinalizeMigrationSource(self, instance, success, live):
341 """Finalize the instance migration on the source node. 342 343 @type instance: L{objects.Instance} 344 @param instance: the instance that was migrated 345 @type success: bool 346 @param success: whether the migration succeeded or not 347 @type live: bool 348 @param live: whether the user requested a live migration or not 349 350 """ 351 # pylint: disable=W0613 352 if success: 353 self._MarkDown(instance.name)
354
355 - def GetMigrationStatus(self, instance):
356 """Get the migration status 357 358 The fake hypervisor migration always succeeds. 359 360 @type instance: L{objects.Instance} 361 @param instance: the instance that is being migrated 362 @rtype: L{objects.MigrationStatus} 363 @return: the status of the current migration (one of 364 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 365 progress info that can be retrieved from the hypervisor 366 367 """ 368 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
369