Package modules :: Package machinery :: Module xenserver
[hide private]
[frames] | no frames]

Source Code for Module modules.machinery.xenserver

  1  # Copyright (C) 2010-2013 Claudio Guarnieri. 
  2  # Copyright (C) 2014-2016 Cuckoo Foundation. 
  3  # This file is part of Cuckoo Sandbox - http://www.cuckoosandbox.org 
  4  # See the file 'docs/LICENSE' for copying permission. 
  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__) 
24 25 -class XenServerMachinery(Machinery):
26 """Virtualization layer for XenServer using the XenAPI XML-RPC interface.""" 27 28 LABEL = "uuid" 29 30 # Power States. 31 RUNNING = "Running" 32 PAUSED = "Paused" 33 POWEROFF = "Halted" 34 ABORTED = "Suspended" 35
36 - def _initialize_check(self):
37 """Check XenServer configuration, initialize a Xen API connection, and 38 verify machine validity. 39 """ 40 self._sessions = {} 41 42 if not HAVE_XENAPI: 43 raise CuckooDependencyError("Unable to import XenAPI") 44 45 if not self.options.xenserver.user: 46 raise CuckooMachineError("XenServer username missing, please add " 47 "it to xenserver.conf.") 48 49 if not self.options.xenserver.password: 50 raise CuckooMachineError("XenServer password missing, please add " 51 "it to xenserver.conf") 52 53 if not self.options.xenserver.url: 54 raise CuckooMachineError("XenServer url missing, please add it to " 55 "xenserver.conf") 56 57 self._make_xenapi_session() 58 59 for machine in self.machines(): 60 uuid = machine.label 61 (ref, vm) = self._check_vm(uuid) 62 63 if machine.snapshot: 64 self._check_snapshot(uuid, machine.snapshot) 65 else: 66 self._check_disks_reset(vm) 67 68 super(XenServerMachinery, self)._initialize_check()
69 70 @property
71 - def session(self):
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
78 - def _make_xenapi_session(self, tid=None):
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
99 - def _get_vm_ref(self, uuid):
100 """Get a virtual machine reference. 101 @param uuid: vm uuid 102 """ 103 return self.session.xenapi.VM.get_by_uuid(uuid.lower())
104
105 - def _get_vm_record(self, ref):
106 """Get the virtual machine record. 107 @param ref: vm reference 108 """ 109 return self.session.xenapi.VM.get_record(ref)
110
111 - def _get_vm_power_state(self, ref):
112 """Get the virtual machine power state. 113 @param ref: vm reference 114 """ 115 return self.session.xenapi.VM.get_power_state(ref)
116
117 - def _check_vm(self, uuid):
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
139 - def _check_snapshot(self, vm_uuid, snapshot_uuid):
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
164 - def _check_disks_reset(self, vm):
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
190 - def _snapshot_from_vm_uuid(self, uuid):
191 """Get the snapshot uuid from a virtual machine. 192 @param uuid: vm uuid 193 """ 194 machine = self.db.view_machine_by_label(uuid) 195 return machine.snapshot
196
197 - def _is_halted(self, vm):
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
256 - def _list(self):
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
270 - def _status(self, label):
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