1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
56
58 """Get the list of running instances.
59
60 """
61 return os.listdir(self._ROOT_DIR)
62
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
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
124 """Compute the instance file for an instance name.
125
126 """
127 return utils.PathJoin(cls._ROOT_DIR, instance_name)
128
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
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):
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
195 """Reboot an instance.
196
197 For the fake hypervisor, this does nothing.
198
199 """
200 return
201
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
221 """Return information about the node.
222
223 See L{BaseHypervisor.GetLinuxNodeInfo}.
224
225 """
226 result = self.GetLinuxNodeInfo()
227
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
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
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
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
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
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
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
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
343 if success:
344 self._MarkDown(instance.name)
345
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