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 """Stop an instance. 170 171 For the fake hypervisor, this just removes the file in the base 172 dir, if it exist, otherwise we raise an exception. 173 174 """ 175 if name is None: 176 name = instance.name 177 if not self._IsAlive(name): 178 raise errors.HypervisorError("Failed to stop instance %s: %s" % 179 (name, "not running")) 180 self._MarkDown(name)
181
182 - def RebootInstance(self, instance):
183 """Reboot an instance. 184 185 For the fake hypervisor, this does nothing. 186 187 """ 188 return
189
190 - def BalloonInstanceMemory(self, instance, mem):
191 """Balloon an instance memory to a certain value. 192 193 @type instance: L{objects.Instance} 194 @param instance: instance to be accepted 195 @type mem: int 196 @param mem: actual memory size to use for instance runtime 197 198 """ 199 if not self._IsAlive(instance.name): 200 raise errors.HypervisorError("Failed to balloon memory for %s: %s" % 201 (instance.name, "not running")) 202 try: 203 self._MarkUp(instance, mem) 204 except EnvironmentError, err: 205 raise errors.HypervisorError("Failed to balloon memory for %s: %s" % 206 (instance.name, utils.ErrnoOrStr(err)))
207
208 - def GetNodeInfo(self):
209 """Return information about the node. 210 211 This is just a wrapper over the base GetLinuxNodeInfo method. 212 213 @return: a dict with the following keys (values in MiB): 214 - memory_total: the total memory size on the node 215 - memory_free: the available memory on the node for instances 216 - memory_dom0: the memory used by the node itself, if available 217 218 """ 219 result = self.GetLinuxNodeInfo() 220 # substract running instances 221 all_instances = self.GetAllInstancesInfo() 222 result["memory_free"] -= min(result["memory_free"], 223 sum([row[2] for row in all_instances])) 224 return result
225 226 @classmethod
227 - def GetInstanceConsole(cls, instance, hvparams, beparams):
228 """Return information for connecting to the console of an instance. 229 230 """ 231 return objects.InstanceConsole(instance=instance.name, 232 kind=constants.CONS_MESSAGE, 233 message=("Console not available for fake" 234 " hypervisor"))
235
236 - def Verify(self):
237 """Verify the hypervisor. 238 239 For the fake hypervisor, it just checks the existence of the base 240 dir. 241 242 @return: Problem description if something is wrong, C{None} otherwise 243 244 """ 245 if os.path.exists(self._ROOT_DIR): 246 return None 247 else: 248 return "The required directory '%s' does not exist" % self._ROOT_DIR
249 250 @classmethod
251 - def PowercycleNode(cls):
252 """Fake hypervisor powercycle, just a wrapper over Linux powercycle. 253 254 """ 255 cls.LinuxPowercycle()
256
257 - def AcceptInstance(self, instance, info, target):
258 """Prepare to accept an instance. 259 260 @type instance: L{objects.Instance} 261 @param instance: instance to be accepted 262 @type info: string 263 @param info: instance info, not used 264 @type target: string 265 @param target: target host (usually ip), on this node 266 267 """ 268 if self._IsAlive(instance.name): 269 raise errors.HypervisorError("Can't accept instance, already running")
270
271 - def MigrateInstance(self, instance, target, live):
272 """Migrate an instance. 273 274 @type instance: L{objects.Instance} 275 @param instance: the instance to be migrated 276 @type target: string 277 @param target: hostname (usually ip) of the target node 278 @type live: boolean 279 @param live: whether to do a live or non-live migration 280 281 """ 282 logging.debug("Fake hypervisor migrating %s to %s (live=%s)", 283 instance, target, live)
284
285 - def FinalizeMigrationDst(self, instance, info, success):
286 """Finalize the instance migration on the target node. 287 288 For the fake hv, this just marks the instance up. 289 290 @type instance: L{objects.Instance} 291 @param instance: instance whose migration is being finalized 292 @type info: string/data (opaque) 293 @param info: migration information, from the source node 294 @type success: boolean 295 @param success: whether the migration was a success or a failure 296 297 """ 298 if success: 299 self._MarkUp(instance, self._InstanceStartupMemory(instance)) 300 else: 301 # ensure it's down 302 self._MarkDown(instance.name)
303
304 - def PostMigrationCleanup(self, instance):
305 """Clean-up after a migration. 306 307 To be executed on the source node. 308 309 @type instance: L{objects.Instance} 310 @param instance: the instance that was migrated 311 312 """ 313 pass
314
315 - def FinalizeMigrationSource(self, instance, success, live):
316 """Finalize the instance migration on the source node. 317 318 @type instance: L{objects.Instance} 319 @param instance: the instance that was migrated 320 @type success: bool 321 @param success: whether the migration succeeded or not 322 @type live: bool 323 @param live: whether the user requested a live migration or not 324 325 """ 326 # pylint: disable=W0613 327 if success: 328 self._MarkDown(instance.name)
329
330 - def GetMigrationStatus(self, instance):
331 """Get the migration status 332 333 The fake hypervisor migration always succeeds. 334 335 @type instance: L{objects.Instance} 336 @param instance: the instance that is being migrated 337 @rtype: L{objects.MigrationStatus} 338 @return: the status of the current migration (one of 339 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 340 progress info that can be retrieved from the hypervisor 341 342 """ 343 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
344