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