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