1
2
3
4
5 """
6 XenServer machinery.
7 """
8
9 import threading
10 import logging
11
12 from lib.cuckoo.common.abstracts import Machinery
13 from lib.cuckoo.common.exceptions import CuckooMachineError
14 from lib.cuckoo.common.exceptions import CuckooDependencyError
15
16 try:
17 import XenAPI
18 HAVE_XENAPI = True
19 except ImportError:
20 HAVE_XENAPI = False
21
22
23 log = logging.getLogger(__name__)
27 """Virtualization layer for XenServer using the XenAPI XML-RPC interface."""
28
29 LABEL = "uuid"
30
31
32 RUNNING = "Running"
33 PAUSED = "Paused"
34 POWEROFF = "Halted"
35 ABORTED = "Suspended"
36
71
72 @property
74 tid = threading.current_thread().ident
75 sess = self._sessions.get(tid, None)
76 if sess is None:
77 sess = self._make_xenapi_session(tid)
78 return sess
79
81 tid = tid or threading.current_thread().ident
82 try:
83 sess = XenAPI.Session(self.options.xenserver.url)
84 except:
85 raise CuckooMachineError("Could not connect to XenServer: invalid "
86 "or incorrect url, please ensure the url "
87 "is correct in xenserver.conf")
88
89 try:
90 sess.xenapi.login_with_password(
91 self.options.xenserver.user, self.options.xenserver.password
92 )
93 except:
94 raise CuckooMachineError("Could not connect to XenServer: "
95 "incorrect credentials, please ensure "
96 "the user and password are correct in "
97 "xenserver.conf")
98 self._sessions[tid] = sess
99 return sess
100
102 """Get a virtual machine reference.
103 @param uuid: vm uuid
104 """
105
106 return self.session.xenapi.VM.get_by_uuid(uuid.lower())
107
109 """Get the virtual machine record.
110 @param ref: vm reference
111 """
112
113 return self.session.xenapi.VM.get_record(ref)
114
116 """Get the virtual machine power state.
117 @param ref: vm reference
118 """
119
120 return self.session.xenapi.VM.get_power_state(ref)
121
123 """Check vm existence and validity.
124 @param uuid: vm uuid
125 """
126
127 try:
128 ref = self._get_vm_ref(uuid)
129 vm = self._get_vm_record(ref)
130 except XenAPI.Failure as e:
131 raise CuckooMachineError("Vm not found: %s: %s"
132 % (uuid, e.details[0]))
133
134 if vm["is_a_snapshot"]:
135 raise CuckooMachineError("Vm is a snapshot: %s" % uuid)
136
137 if vm["is_a_template"]:
138 raise CuckooMachineError("Vm is a template: %s" % uuid)
139
140 if vm["is_control_domain"]:
141 raise CuckooMachineError("Vm is a control domain: %s" % uuid)
142
143 return (ref, vm)
144
146 """Check snapshot existence and that the snapshot is of the specified
147 vm uuid.
148 @param vm_uuid: vm uuid
149 @param snapshot_uuid: snapshot uuid
150 """
151
152 try:
153 snapshot_ref = self._get_vm_ref(snapshot_uuid)
154 snapshot = self._get_vm_record(snapshot_ref)
155 except:
156 raise CuckooMachineError("Snapshot not found: %s" % snapshot_uuid)
157
158 if not snapshot["is_a_snapshot"]:
159 raise CuckooMachineError("Invalid snapshot: %s" % snapshot_uuid)
160
161 try:
162 parent = self._get_vm_record(snapshot["snapshot_of"])
163 except:
164 raise CuckooMachineError("Invalid snapshot: %s" % snapshot_uuid)
165
166 parent_uuid = parent["uuid"]
167 if parent_uuid != vm_uuid:
168 raise CuckooMachineError("Snapshot does not belong to specified "
169 "vm: %s" % snapshot_uuid)
170
172 """Check whether each attached disk is set to reset on boot.
173 @param vm: vm record
174 """
175
176 for ref in vm["VBDs"]:
177 try:
178 vbd = self.session.xenapi.VBD.get_record(ref)
179 except:
180 log.warning("Invalid VBD for vm %s: %s", vm["uuid"], ref)
181 continue
182
183 if vbd["type"] == "Disk":
184 vdi_ref = vbd["VDI"]
185 try:
186 vdi = self.session.xenapi.VDI.get_record(vdi_ref)
187 except:
188 log.warning("Invalid VDI for vm %s: %s", vm["uuid"],
189 vdi_ref)
190 continue
191
192 if vdi["on_boot"] != "reset" and vdi["read_only"] is False:
193 raise CuckooMachineError(
194 "Vm %s contains invalid VDI %s: disk is not reset on "
195 "boot. Please set the on-boot parameter to 'reset'."
196 % (vm["uuid"], vdi["uuid"]))
197
205
207 """Checks if the virtual machine is running.
208 @param uuid: vm uuid
209 """
210
211 return vm["power_state"] == "Halted"
212
214 """Start a virtual machine.
215 @param label: vm uuid
216 """
217
218 vm_ref = self._get_vm_ref(label)
219 vm = self._get_vm_record(vm_ref)
220
221 if not self._is_halted(vm):
222 raise CuckooMachineError("Vm is already running: %s", label)
223
224 snapshot = self._snapshot_from_vm_uuid(label)
225 if snapshot:
226 snapshot_ref = self._get_vm_ref(snapshot)
227 try:
228 log.debug("Reverting vm %s to snapshot %s", label, snapshot)
229 self.session.xenapi.VM.revert(snapshot_ref)
230 log.debug("Revert completed for vm %s", label)
231 except XenAPI.Failure as e:
232 raise CuckooMachineError("Unable to revert vm %s: %s"
233 % (label, e.details[0]))
234
235 try:
236 log.debug("Resuming reverted vm %s", label)
237 self.session.xenapi.VM.resume(vm_ref, False, False)
238 except XenAPI.Failure as e:
239 raise CuckooMachineError("Unable to resume vm %s: %s"
240 % (label, e.details[0]))
241 else:
242 log.debug("No snapshot found for vm, booting: %s", label)
243 try:
244 self.session.xenapi.VM.start(vm_ref, False, False)
245 except XenAPI.Failure as e:
246 raise CuckooMachineError("Unable to start vm %s: %s"
247 % (label, e.details[0]))
248
249 log.debug("Started vm: %s", label)
250
251 - def stop(self, label=None):
252 """Stop a virtual machine.
253 @param label: vm uuid
254 """
255
256 ref = self._get_vm_ref(label)
257 vm = self._get_vm_record(ref)
258 if self._is_halted(vm):
259 log.warning("Trying to stop an already stopped machine: %s", label)
260 else:
261 try:
262 self.session.xenapi.VM.hard_shutdown(ref)
263 except XenAPI.Failure as e:
264 raise CuckooMachineError("Error shutting down virtual machine:"
265 " %s: %s" % (label, e.details[0]))
266
268 """List available virtual machines.
269 @raise CuckooMachineError: if unable to list virtual machines.
270 """
271
272 try:
273 vm_list = []
274 for ref in self.session.xenapi.VM.get_all():
275 vm = self._get_vm_record(ref)
276 vm_list.append(vm['uuid'])
277 except:
278 raise CuckooMachineError("Cannot list domains")
279 else:
280 return vm_list
281
283 """Gets current status of a vm.
284 @param label: virtual machine uuid
285 @return: status string.
286 """
287
288 ref = self._get_vm_ref(label)
289 state = self._get_vm_power_state(ref)
290
291 return state
292