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.hypervisor import hv_base
37 """Fake hypervisor interface.
38
39 This can be used for testing the ganeti code without having to have
40 a real virtualisation software installed.
41
42 """
43 CAN_MIGRATE = True
44
45 _ROOT_DIR = constants.RUN_GANETI_DIR + "/fake-hypervisor"
46
50
52 """Get the list of running instances.
53
54 """
55 return os.listdir(self._ROOT_DIR)
56
58 """Get instance properties.
59
60 @param instance_name: the instance name
61
62 @return: tuple of (name, id, memory, vcpus, stat, times)
63
64 """
65 file_name = self._InstanceFile(instance_name)
66 if not os.path.exists(file_name):
67 return None
68 try:
69 fh = open(file_name, "r")
70 try:
71 inst_id = fh.readline().strip()
72 memory = utils.TryConvert(int, fh.readline().strip())
73 vcpus = utils.TryConvert(int, fh.readline().strip())
74 stat = "---b-"
75 times = "0"
76 return (instance_name, inst_id, memory, vcpus, stat, times)
77 finally:
78 fh.close()
79 except IOError, err:
80 raise errors.HypervisorError("Failed to list instance %s: %s" %
81 (instance_name, err))
82
84 """Get properties of all instances.
85
86 @return: list of tuples (name, id, memory, vcpus, stat, times)
87
88 """
89 data = []
90 for file_name in os.listdir(self._ROOT_DIR):
91 try:
92 fh = open(utils.PathJoin(self._ROOT_DIR, file_name), "r")
93 inst_id = "-1"
94 memory = 0
95 vcpus = 1
96 stat = "-----"
97 times = "-1"
98 try:
99 inst_id = fh.readline().strip()
100 memory = utils.TryConvert(int, fh.readline().strip())
101 vcpus = utils.TryConvert(int, fh.readline().strip())
102 stat = "---b-"
103 times = "0"
104 finally:
105 fh.close()
106 data.append((file_name, inst_id, memory, vcpus, stat, times))
107 except IOError, err:
108 raise errors.HypervisorError("Failed to list instances: %s" % err)
109 return data
110
111 @classmethod
113 """Compute the instance file for an instance name.
114
115 """
116 return utils.PathJoin(cls._ROOT_DIR, instance_name)
117
119 """Checks if an instance is alive.
120
121 """
122 file_name = self._InstanceFile(instance_name)
123 return os.path.exists(file_name)
124
139
141 """Mark the instance as running.
142
143 This does no checks, which should be done by its callers.
144
145 """
146 file_name = self._InstanceFile(instance_name)
147 utils.RemoveFile(file_name)
148
150 """Start an instance.
151
152 For the fake hypervisor, it just creates a file in the base dir,
153 creating an exception if it already exists. We don't actually
154 handle race conditions properly, since these are *FAKE* instances.
155
156 """
157 if self._IsAlive(instance.name):
158 raise errors.HypervisorError("Failed to start instance %s: %s" %
159 (instance.name, "already running"))
160 try:
161 self._MarkUp(instance)
162 except IOError, err:
163 raise errors.HypervisorError("Failed to start instance %s: %s" %
164 (instance.name, err))
165
166 - def StopInstance(self, instance, force=False, retry=False, name=None):
167 """Stop an instance.
168
169 For the fake hypervisor, this just removes the file in the base
170 dir, if it exist, otherwise we raise an exception.
171
172 """
173 if name is None:
174 name = instance.name
175 if not self._IsAlive(name):
176 raise errors.HypervisorError("Failed to stop instance %s: %s" %
177 (name, "not running"))
178 self._MarkDown(name)
179
181 """Reboot an instance.
182
183 For the fake hypervisor, this does nothing.
184
185 """
186 return
187
189 """Return information about the node.
190
191 This is just a wrapper over the base GetLinuxNodeInfo method.
192
193 @return: a dict with the following keys (values in MiB):
194 - memory_total: the total memory size on the node
195 - memory_free: the available memory on the node for instances
196 - memory_dom0: the memory used by the node itself, if available
197
198 """
199 result = self.GetLinuxNodeInfo()
200
201 all_instances = self.GetAllInstancesInfo()
202 result['memory_free'] -= min(result['memory_free'],
203 sum([row[2] for row in all_instances]))
204 return result
205
206 @classmethod
208 """Return a command for connecting to the console of an instance.
209
210 """
211 return "echo Console not available for fake hypervisor"
212
214 """Verify the hypervisor.
215
216 For the fake hypervisor, it just checks the existence of the base
217 dir.
218
219 """
220 if not os.path.exists(self._ROOT_DIR):
221 return "The required directory '%s' does not exist." % self._ROOT_DIR
222
223 @classmethod
225 """Fake hypervisor powercycle, just a wrapper over Linux powercycle.
226
227 """
228 cls.LinuxPowercycle()
229
231 """Prepare to accept an instance.
232
233 @type instance: L{objects.Instance}
234 @param instance: instance to be accepted
235 @type info: string
236 @param info: instance info, not used
237 @type target: string
238 @param target: target host (usually ip), on this node
239
240 """
241 if self._IsAlive(instance.name):
242 raise errors.HypervisorError("Can't accept instance, already running")
243
245 """Migrate an instance.
246
247 @type instance: L{objects.Instance}
248 @param instance: the instance to be migrated
249 @type target: string
250 @param target: hostname (usually ip) of the target node
251 @type live: boolean
252 @param live: whether to do a live or non-live migration
253
254 """
255 logging.debug("Fake hypervisor migrating %s to %s (live=%s)",
256 instance, target, live)
257
258 self._MarkDown(instance.name)
259
261 """Finalize an instance migration.
262
263 For the fake hv, this just marks the instance up.
264
265 @type instance: L{objects.Instance}
266 @param instance: instance whose migration is being finalized
267
268 """
269 if success:
270 self._MarkUp(instance)
271 else:
272
273 self._MarkDown(instance.name)
274