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