1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
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
65
67 """Get the list of running instances.
68
69 """
70 return os.listdir(self._ROOT_DIR)
71
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 = hv_base.HvInstanceState.RUNNING
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
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 = hv_base.HvInstanceState.SHUTDOWN
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 = hv_base.HvInstanceState.RUNNING
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
133 """Compute the instance file for an instance name.
134
135 """
136 return utils.PathJoin(cls._ROOT_DIR, instance_name)
137
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
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):
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
204 """Reboot an instance.
205
206 For the fake hypervisor, this does nothing.
207
208 """
209 return
210
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
230 """Return information about the node.
231
232 See L{BaseHypervisor.GetLinuxNodeInfo}.
233
234 """
235 result = self.GetLinuxNodeInfo()
236
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
252
253 - def Verify(self, hvparams=None):
254 """Verify the hypervisor.
255
256 For the fake hypervisor, it just checks the existence of the base
257 dir.
258
259 @type hvparams: dict of strings
260 @param hvparams: hypervisor parameters to be verified against; not used
261 for fake hypervisors
262
263 @return: Problem description if something is wrong, C{None} otherwise
264
265 """
266 if os.path.exists(self._ROOT_DIR):
267 return None
268 else:
269 return "The required directory '%s' does not exist" % self._ROOT_DIR
270
271 @classmethod
273 """Fake hypervisor powercycle, just a wrapper over Linux powercycle.
274
275 @type hvparams: dict of strings
276 @param hvparams: hypervisor params to be used on this node
277
278 """
279 cls.LinuxPowercycle()
280
282 """Prepare to accept an instance.
283
284 @type instance: L{objects.Instance}
285 @param instance: instance to be accepted
286 @type info: string
287 @param info: instance info, not used
288 @type target: string
289 @param target: target host (usually ip), on this node
290
291 """
292 if self._IsAlive(instance.name):
293 raise errors.HypervisorError("Can't accept instance, already running")
294
296 """Migrate an instance.
297
298 @type cluster_name: string
299 @param cluster_name: name of the cluster
300 @type instance: L{objects.Instance}
301 @param instance: the instance to be migrated
302 @type target: string
303 @param target: hostname (usually ip) of the target node
304 @type live: boolean
305 @param live: whether to do a live or non-live migration
306
307 """
308 logging.debug("Fake hypervisor migrating %s to %s (live=%s)",
309 instance, target, live)
310
312 """Finalize the instance migration on the target node.
313
314 For the fake hv, this just marks the instance up.
315
316 @type instance: L{objects.Instance}
317 @param instance: instance whose migration is being finalized
318 @type info: string/data (opaque)
319 @param info: migration information, from the source node
320 @type success: boolean
321 @param success: whether the migration was a success or a failure
322
323 """
324 if success:
325 self._MarkUp(instance, self._InstanceStartupMemory(instance))
326 else:
327
328 self._MarkDown(instance.name)
329
330 - def PostMigrationCleanup(self, instance):
331 """Clean-up after a migration.
332
333 To be executed on the source node.
334
335 @type instance: L{objects.Instance}
336 @param instance: the instance that was migrated
337
338 """
339 pass
340
342 """Finalize the instance migration on the source node.
343
344 @type instance: L{objects.Instance}
345 @param instance: the instance that was migrated
346 @type success: bool
347 @param success: whether the migration succeeded or not
348 @type live: bool
349 @param live: whether the user requested a live migration or not
350
351 """
352
353 if success:
354 self._MarkDown(instance.name)
355
357 """Get the migration status
358
359 The fake hypervisor migration always succeeds.
360
361 @type instance: L{objects.Instance}
362 @param instance: the instance that is being migrated
363 @rtype: L{objects.MigrationStatus}
364 @return: the status of the current migration (one of
365 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional
366 progress info that can be retrieved from the hypervisor
367
368 """
369 return objects.MigrationStatus(status=constants.HV_MIGRATION_COMPLETED)
370