from .obj import PpBaseObject
-__version__ = '0.4.2'
+__version__ = '0.4.3'
LOG = logging.getLogger(__name__)
default_template_vm = 'template.pixelpark.com'
default_template_name = 'oracle-linux-7.4-template'
default_data_size_gb = 30.0
+ default_num_cpus = 2
+ default_ram_mb = 4 * 1024
default_network = '192.168.88.0_23'
+ default_mac_address = '00:50:56:01:af:fe'
# -------------------------------------------------------------------------
def __init__(
self.template_vm = self.default_template_vm
self.template_name = self.default_template_name
self.data_size_gb = self.default_data_size_gb
+ self.num_cpus = self.default_num_cpus
+ self.ram_mb = self.default_ram_mb
self.network = self.default_network
+ self.mac_address = self.default_mac_address
self.encoding = 'utf-8'
@property
def data_size_mb(self):
"""Size of template volume in MiB."""
- return int(self.data_size_gb) * 1024
+ return int(self.data_size_gb * 1024.0)
# -------------------------------------------------------------------------
@property
def data_size_kb(self):
"""Size of template volume in KiB."""
- return int(self.data_size_gb) * 1024 * 1024
+ return self.data_size_mb * 1024
# -------------------------------------------------------------------------
@property
def data_size(self):
"""Size of template volume in Bytes."""
- return int(self.data_size_gb) * 1024 * 1024 * 1024
+ return self.data_size_mb * 1024 * 1024
+
+ # -------------------------------------------------------------------------
+ @property
+ def ram_gb(self):
+ """Size of RAM in GiB."""
+ return float(self.ram_mb) / 1024
# -------------------------------------------------------------------------
def as_dict(self, short=True):
res['default_template_vm'] = self.default_template_vm
res['default_template_name'] = self.default_template_name
res['default_data_size_gb'] = self.default_data_size_gb
+ res['default_num_cpus'] = self.default_num_cpus
+ res['default_ram_mb'] = self.default_ram_mb
res['default_network'] = self.default_network
+ res['default_mac_address'] = self.default_mac_address
res['data_size_mb'] = self.data_size_mb
res['data_size_kb'] = self.data_size_kb
res['data_size'] = self.data_size
+ res['ram_gb'] = self.ram_gb
return res
self.data_size_gb = float(value) / 1024.0 / 1024.0
if key.lower() == 'data_size':
self.data_size_gb = float(value) / 1024.0 / 1024.0 / 1024.0
+ if key.lower() == 'num_cpus':
+ self.num_cpus = int(value)
+ if key.lower() == 'ram_gb':
+ self.ram_mb = int(float(value) * 1024.0)
+ if key.lower() == 'ram_mb':
+ self.ram_mb = int(value)
if key.lower() == 'network':
self.network = value.strip()
+ if key.lower() == 'mac_address':
+ v = value.strip().lower()
+ if v:
+ self.mac_address = v
# =============================================================================
import ssl
import re
import random
+import time
# Third party modules
import six
-from pyVmomi import vim
+from pyVmomi import vim, vmodl
from pyVim.connect import SmartConnect, Disconnect
# Own modules
+from .common import pp
+
from .errors import FunctionNotImplementedError, PpError
from .obj import PpBaseObject
from .config import CrTplConfiguration
-__version__ = '0.4.1'
+__version__ = '0.4.2'
LOG = logging.getLogger(__name__)
)
self.config = config
- self.server_instance = None
+ self.service_instance = None
self.tpl_vm_folder = None
self.tpl_data_store = None
self.tpl_network = None
if hasattr(ssl, '_create_unverified_context'):
ssl_context = ssl._create_unverified_context()
- self.server_instance = SmartConnect(
+ self.service_instance = SmartConnect(
host=self.config.vsphere_host, port=self.config.vsphere_port,
user=self.config.vsphere_user, pwd=self.config.password,
sslContext=ssl_context)
- if not self.server_instance:
+ if not self.service_instance:
raise CannotConnectError(
host=self.config.vsphere_host, port=self.config.vsphere_port,
user=self.config.vsphere_user)
self.check_for_temp_tpl_vm()
self.select_data_store()
self.check_network()
+ self.create_vm()
finally:
LOG.debug("Disconnecting from vSphere host {h}:{p} ...".format(
h=self.config.vsphere_host, p=self.config.vsphere_port))
- Disconnect(self.server_instance)
+ Disconnect(self.service_instance)
# -------------------------------------------------------------------------
def get_obj(self, content, vimtype, name):
return result
+ # -------------------------------------------------------------------------
+ def wait_for_tasks(self, tasks):
+
+ LOG.debug("Waiting for tasks to finish ...")
+
+ property_collector = self.service_instance.content.propertyCollector
+ task_list = [str(task) for task in tasks]
+ LOG.debug("Waiting for tasks {} to finish ...".format(task_list))
+ # Create filter
+ obj_specs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
+ for task in tasks]
+ property_spec = vmodl.query.PropertyCollector.PropertySpec(
+ type=vim.Task, pathSet=[], all=True)
+ filter_spec = vmodl.query.PropertyCollector.FilterSpec()
+ filter_spec.objectSet = obj_specs
+ filter_spec.propSet = [property_spec]
+ pcfilter = property_collector.CreateFilter(filter_spec, True)
+ try:
+ version, state = None, None
+ # Loop looking for updates till the state moves to a completed state.
+ while len(task_list):
+ update = property_collector.WaitForUpdates(version)
+ for filter_set in update.filterSet:
+ time.sleep(0.1)
+ LOG.debug("Waiting ...")
+ for obj_set in filter_set.objectSet:
+ task = obj_set.obj
+ for change in obj_set.changeSet:
+ if change.name == 'info':
+ state = change.val.state
+ elif change.name == 'info.state':
+ state = change.val
+ else:
+ continue
+
+ if not str(task) in task_list:
+ continue
+
+ if state == vim.TaskInfo.State.success:
+ # Remove task from taskList
+ task_list.remove(str(task))
+ elif state == vim.TaskInfo.State.error:
+ raise task.info.error
+ # Move to next version
+ version = update.version
+ finally:
+ if pcfilter:
+ pcfilter.Destroy()
+
# -------------------------------------------------------------------------
def get_cluster(self, content=None):
if not content:
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
cluster_list = self.get_obj_list(content, [vim.ClusterComputeResource])
if not len(cluster_list):
def get_tpl_folder(self, vm_folder=None):
if not vm_folder:
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
vm_folder = dc.vmFolder
# -------------------------------------------------------------------------
def ensure_vm_folder(self):
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
tpl_vm_folder = self.get_tpl_folder(dc.vmFolder)
# -------------------------------------------------------------------------
def get_temp_tpl_vm(self):
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
for child in dc.vmFolder.childEntity:
# -------------------------------------------------------------------------
def check_network(self):
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
LOG.debug("Checking existence of network {!r} ...".format(self.config.network))
"Selecting a SAN based datastore with at least {:0.1f} GiB available "
"space.").format(self.config.data_size_gb))
- content = self.server_instance.RetrieveContent()
+ content = self.service_instance.RetrieveContent()
dc = self.get_obj(content, [vim.Datacenter], self.config.dc)
ds_list = []
return
+ # -------------------------------------------------------------------------
+ def create_vm(self):
+
+ LOG.info("Creating VM {!r} ...".format(self.config.template_vm))
+
+ datastore_path = '[' + self.tpl_data_store.summary.name + '] ' + self.config.template_vm
+ LOG.debug("Datastore path: {!r}".format(datastore_path))
+
+ vm_file_info = vim.vm.FileInfo(
+ logDirectory=None, snapshotDirectory=None,
+ suspendDirectory=None, vmPathName=datastore_path)
+
+ dev_changes = []
+
+ # Creating SCSI Controller and disk
+ scsi_ctr_spec = vim.vm.device.VirtualDeviceSpec()
+ scsi_ctr_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
+ scsi_ctr_spec.device = vim.vm.device.VirtualLsiLogicController()
+ scsi_ctr_spec.device.key = 0
+ #scsi_ctr_spec.device.controllerKey = 1000
+ scsi_ctr_spec.device.unitNumber = 1
+ scsi_ctr_spec.device.sharedBus = 'noSharing'
+ controller = scsi_ctr_spec.device
+
+ dev_changes.append(scsi_ctr_spec)
+
+ disk_spec = vim.vm.device.VirtualDeviceSpec()
+ disk_spec.fileOperation = "create"
+ disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
+ disk_spec.device = vim.vm.device.VirtualDisk()
+ disk_spec.device.backing = vim.vm.device.VirtualDisk.FlatVer2BackingInfo()
+ disk_spec.device.backing.diskMode = 'persistent'
+ disk_spec.device.backing.fileName = '{ds}/{vm}-sda.vmdk'.format(
+ ds=datastore_path, vm=self.config.template_vm)
+ disk_spec.device.unitNumber = 1
+ disk_spec.device.key = 1
+ disk_spec.device.capacityInKB = self.config.data_size_kb
+ disk_spec.device.controllerKey = controller.key
+
+ dev_changes.append(disk_spec)
+
+ # Creating network adapter
+ nic_spec = vim.vm.device.VirtualDeviceSpec()
+ nic_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
+ nic_spec.device = vim.vm.device.VirtualVmxnet3()
+ nic_spec.device.deviceInfo = vim.Description()
+ nic_spec.device.deviceInfo.label = 'eth0'
+ nic_spec.device.deviceInfo.summary = 'Primary network device'
+
+ nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
+ nic_spec.device.backing.useAutoDetect = False
+ nic_spec.device.backing.network = self.tpl_network
+ nic_spec.device.backing.deviceName = self.config.network
+
+ nic_spec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
+ nic_spec.device.connectable.startConnected = True
+ nic_spec.device.connectable.allowGuestControl = True
+ nic_spec.device.wakeOnLanEnabled = False
+ nic_spec.device.addressType = 'assigned'
+ nic_spec.device.macAddress = self.config.mac_address
+
+ dev_changes.append(nic_spec)
+
+ # Graphic Card
+ video_spec = vim.vm.device.VirtualDeviceSpec()
+ video_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.add
+ video_spec.device = vim.vm.device.VirtualVideoCard()
+ video_spec.device.enable3DSupport = False
+ video_spec.device.graphicsMemorySizeInKB = 256 * 1024
+ video_spec.device.numDisplays = 1
+ video_spec.device.use3dRenderer = 'automatic'
+ video_spec.device.videoRamSizeInKB = 32 * 1024
+
+ dev_changes.append(video_spec)
+
+ # Some other flags
+ vm_flags = vim.vm.FlagInfo()
+ vm_flags.diskUuidEnabled = True
+
+ # Some extra options and properties
+ extra_opts = []
+ created_opt = vim.option.OptionValue()
+ created_opt.key = 'created'
+ created_opt.value = int(time.time())
+ extra_opts.append(created_opt)
+
+ config = vim.vm.ConfigSpec(
+ name=self.config.template_vm, deviceChange=dev_changes,
+ flags=vm_flags, extraConfig=extra_opts,
+ memoryMB=self.config.ram_mb, memoryHotAddEnabled=True,
+ numCPUs=self.config.num_cpus, cpuHotAddEnabled=True,
+ files=vm_file_info)
+ #files=vm_file_info, guestId='OracleLinux7_Guest')
+ #files=vm_file_info, guestId='OracleLinux7_Guest', version='oel7-4')
+
+ if self.verbose > 2:
+ LOG.debug("Generated VM config:\n{}".format(pp(config)))
+
+ LOG.debug("Start Creating VM ...")
+ task = self.tpl_vm_folder.CreateVM_Task(
+ config=config, pool=self.tpl_cluster.resourcePool)
+
+ self.wait_for_tasks([task])
+
# =============================================================================