forked from p15670423/monkey
272 lines
9.9 KiB
Python
272 lines
9.9 KiB
Python
from connectors import NetControllerJob, NetControllerConnector
|
|
from pyVmomi import vim
|
|
from pyVim.connect import SmartConnect, Disconnect
|
|
|
|
class VCenterConnector(NetControllerConnector):
|
|
def __init__(self):
|
|
self._service_instance = None
|
|
self._properties = {
|
|
"address": "127.0.0.1",
|
|
"port": 0,
|
|
"username": "",
|
|
"password": "",
|
|
"monkey_template_name": "",
|
|
"monkey_vm_info": {
|
|
"datacenter_name": "",
|
|
"vm_folder": "",
|
|
"datastore_name": "",
|
|
"cluster_name": "",
|
|
"resource_pool": ""
|
|
}
|
|
}
|
|
self._cache = {
|
|
"vlans" : []
|
|
}
|
|
|
|
def connect(self):
|
|
import ssl
|
|
try:
|
|
self._service_instance = SmartConnect(host=self._properties["address"],
|
|
port=self._properties["port"],
|
|
user=self._properties["username"],
|
|
pwd=self._properties["password"])
|
|
except ssl.SSLError:
|
|
# some organizations use self-signed certificates...
|
|
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
|
self._service_instance = SmartConnect(host=self._properties["address"],
|
|
port=self._properties["port"],
|
|
user=self._properties["username"],
|
|
pwd=self._properties["password"],
|
|
sslContext=gcontext)
|
|
|
|
def is_connected(self):
|
|
if (self._service_instance == None):
|
|
return False
|
|
try:
|
|
self._service_instance.serverClock
|
|
except vim.fault.NotAuthenticated, e:
|
|
return False
|
|
|
|
def get_vlans_list(self):
|
|
if not self.is_connected():
|
|
self.connect()
|
|
if self._cache and self._cache.has_key("vlans") and self._cache["vlans"]:
|
|
return self._cache["vlans"]
|
|
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
|
vimtype = [vim.Network]
|
|
objview = vcontent.viewManager.CreateContainerView(vcontent.rootFolder, vimtype, True)
|
|
self._cache["vlans"] = [x.name for x in objview.view]
|
|
objview.Destroy()
|
|
return self._cache["vlans"]
|
|
|
|
def get_vm(self, vmname):
|
|
if not self.is_connected():
|
|
self.connect()
|
|
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
|
return self._get_obj(vcontent, [vim.VirtualMachine], vmname)
|
|
|
|
def deploy_monkey(self, vm_name):
|
|
if not self._properties["monkey_template_name"]:
|
|
raise Exception("Monkey template not configured")
|
|
|
|
if not self.is_connected():
|
|
self.connect()
|
|
|
|
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
|
monkey_template = self._get_obj(vcontent, [vim.VirtualMachine], self._properties["monkey_template_name"])
|
|
if not monkey_template:
|
|
raise Exception("Monkey template not found")
|
|
|
|
self.log("Cloning vm: (%s -> %s)" % (monkey_template, vm_name))
|
|
monkey_vm = self._clone_vm(vcontent, monkey_template, vm_name)
|
|
if not monkey_vm:
|
|
raise Exception("Error deploying monkey VM")
|
|
self.log("Finished cloning")
|
|
|
|
return monkey_vm
|
|
|
|
def set_network(self, vm_obj, vlan_name):
|
|
if not self.is_connected():
|
|
self.connect()
|
|
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
|
dvs_pg = self._get_obj(vcontent, [vim.dvs.DistributedVirtualPortgroup], vlan_name)
|
|
nic = self._get_vm_nic(vm_obj)
|
|
virtual_nic_spec = self._create_nic_spec(nic, dvs_pg)
|
|
dev_changes = [virtual_nic_spec]
|
|
spec = vim.vm.ConfigSpec()
|
|
spec.deviceChange = dev_changes
|
|
task = vm_obj.ReconfigVM_Task(spec=spec)
|
|
return self._wait_for_task(task)
|
|
|
|
def power_on(self, vm_obj):
|
|
task = vm_obj.PowerOnVM_Task()
|
|
return self._wait_for_task(task)
|
|
|
|
def power_off(self, vm_obj):
|
|
task = vm_obj.PowerOffVM_Task()
|
|
return self._wait_for_task(task)
|
|
|
|
def destroy(self, vm_obj):
|
|
task = vm_obj.Destroy_Task()
|
|
return self._wait_for_task(task)
|
|
|
|
def disconnect(self):
|
|
Disconnect(self._service_instance)
|
|
self._service_instance = None
|
|
|
|
def __del__(self):
|
|
if self._service_instance:
|
|
self.disconnect()
|
|
|
|
def _get_vm_nic(self, vm_obj):
|
|
for dev in vm_obj.config.hardware.device:
|
|
if isinstance(dev, vim.vm.device.VirtualEthernetCard):
|
|
return dev
|
|
return None
|
|
|
|
def _create_nic_spec(self, virtual_nic_device, dvs_pg):
|
|
virtual_nic_spec = vim.vm.device.VirtualDeviceSpec()
|
|
virtual_nic_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
|
|
virtual_nic_spec.device = virtual_nic_device
|
|
virtual_nic_spec.device.key = virtual_nic_device.key
|
|
virtual_nic_spec.device.macAddress = virtual_nic_device.macAddress
|
|
virtual_nic_spec.device.wakeOnLanEnabled = virtual_nic_device.wakeOnLanEnabled
|
|
|
|
virtual_nic_spec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
|
|
virtual_nic_spec.device.connectable.startConnected = True
|
|
virtual_nic_spec.device.connectable.connected = True
|
|
virtual_nic_spec.device.connectable.allowGuestControl = True
|
|
|
|
# configure port connection object on the requested dvs port group
|
|
dvs_port_connection = vim.dvs.PortConnection()
|
|
dvs_port_connection.portgroupKey = dvs_pg.key
|
|
dvs_port_connection.switchUuid = dvs_pg.config.distributedVirtualSwitch.uuid
|
|
|
|
# assign port to device
|
|
virtual_nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo()
|
|
virtual_nic_spec.device.backing.port = dvs_port_connection
|
|
|
|
return virtual_nic_spec
|
|
|
|
def _clone_vm(self, vcontent, vm, name):
|
|
|
|
# get vm target folder
|
|
if self._properties["monkey_vm_info"]["vm_folder"]:
|
|
destfolder = self._get_obj(vcontent, [vim.Folder], self._properties["monkey_vm_info"]["vm_folder"])
|
|
else:
|
|
datacenter = self._get_obj(vcontent, [vim.Datacenter], self._properties["monkey_vm_info"]["datacenter_name"])
|
|
destfolder = datacenter.vmFolder
|
|
|
|
# get vm target datastore
|
|
if self._properties["monkey_vm_info"]["datacenter_name"]:
|
|
datastore = self._get_obj(vcontent, [vim.Datastore], self._properties["monkey_vm_info"]["datacenter_name"])
|
|
else:
|
|
datastore = self._get_obj(vcontent, [vim.Datastore], vm.datastore[0].info.name)
|
|
|
|
# get vm target resource pool
|
|
if self._properties["monkey_vm_info"]["resource_pool"]:
|
|
resource_pool = self._get_obj(vcontent, [vim.ResourcePool], self._properties["monkey_vm_info"]["resource_pool"])
|
|
else:
|
|
cluster = self._get_obj(vcontent, [vim.ClusterComputeResource], self._properties["monkey_vm_info"]["cluster_name"])
|
|
resource_pool = cluster.resourcePool
|
|
|
|
# set relospec
|
|
relospec = vim.vm.RelocateSpec()
|
|
relospec.datastore = datastore
|
|
relospec.pool = resource_pool
|
|
|
|
clonespec = vim.vm.CloneSpec()
|
|
clonespec.location = relospec
|
|
|
|
self.log("Starting clone task with the following info: %s" % repr({"folder": destfolder, "name": name, "clonespec": clonespec}))
|
|
|
|
task = vm.Clone(folder=destfolder, name=name, spec=clonespec)
|
|
return self._wait_for_task(task)
|
|
|
|
def _wait_for_task(self, task):
|
|
""" wait for a vCenter task to finish """
|
|
task_done = False
|
|
while not task_done:
|
|
if task.info.state == 'success':
|
|
if task.info.result:
|
|
return task.info.result
|
|
else:
|
|
return True
|
|
|
|
if task.info.state == 'error':
|
|
self.log("Error waiting for task: %s" % repr(task.info))
|
|
return None
|
|
if task.info.state == 'success':
|
|
return task.info.result
|
|
return None
|
|
|
|
|
|
@staticmethod
|
|
def _get_obj(content, vimtype, name):
|
|
"""
|
|
Return an object by name, if name is None the
|
|
first found object is returned
|
|
"""
|
|
obj = None
|
|
container = content.viewManager.CreateContainerView(
|
|
content.rootFolder, vimtype, True)
|
|
for c in container.view:
|
|
if name:
|
|
if c.name == name:
|
|
obj = c
|
|
break
|
|
else:
|
|
obj = c
|
|
break
|
|
|
|
return obj
|
|
|
|
|
|
class VCenterJob(NetControllerJob):
|
|
connector_type = VCenterConnector
|
|
_vm_obj = None
|
|
_properties = {
|
|
"vlan": "",
|
|
"vm_name": "",
|
|
}
|
|
_enumerations = {
|
|
"vlan": "get_vlans_list",
|
|
}
|
|
|
|
def run(self):
|
|
if not self._connector:
|
|
return False
|
|
|
|
monkey_vm = self._connector.deploy_monkey(self._properties["vm_name"])
|
|
if not monkey_vm:
|
|
return False
|
|
|
|
self._vm_obj = monkey_vm
|
|
|
|
self.log("Setting vm network")
|
|
if not self._connector.set_network(monkey_vm, self._properties["vlan"]):
|
|
return False
|
|
|
|
self.log("Powering on vm")
|
|
if not self._connector.power_on(monkey_vm):
|
|
return False
|
|
|
|
return True
|
|
|
|
def stop(self):
|
|
if not self._connector:
|
|
return False
|
|
|
|
if not self._vm_obj:
|
|
self._vm_obj = self._connector.get_vm(self._properties["vm_name"])
|
|
|
|
if not self._vm_obj:
|
|
self.log("Error: Couldn't find VM %s" % self._properties["vm_name"])
|
|
return False
|
|
|
|
self.log("Stopping: %s" % self._properties["vm_name"])
|
|
self._connector.power_off(self._vm_obj)
|
|
self._connector.destroy(self._vm_obj)
|
|
|
|
return True
|