Merge pull request #22729 from nmadhok/vmware-cloud-driver

Adding list_nodes_select(), create_datacenter() and create_cluster() in vmware salt cloud driver
This commit is contained in:
Thomas S Hatch 2015-04-16 11:54:56 -06:00
commit 58617f9a7b

View File

@ -421,7 +421,7 @@ def _wait_for_ip(vm, max_wait_minute):
time_counter = 0 time_counter = 0
max_wait_second = int(max_wait_minute * 60) max_wait_second = int(max_wait_minute * 60)
while time_counter < max_wait_second: while time_counter < max_wait_second:
log.info("Waiting to get IP information [{0} s]".format(time_counter)) log.info("[ {0} ] Waiting to get IP information [{1} s]".format(vm.name, time_counter))
for net in vm.guest.net: for net in vm.guest.net:
if net.ipConfig.ipAddress: if net.ipConfig.ipAddress:
for current_ip in net.ipConfig.ipAddress: for current_ip in net.ipConfig.ipAddress:
@ -433,6 +433,26 @@ def _wait_for_ip(vm, max_wait_minute):
return False return False
def _wait_for_task(task, vm_name, task_type, sleep_seconds=1, log_level='debug'):
time_counter = 0
while task.info.state == 'running':
message = "[ {0} ] Waiting for {1} task to finish [{2} s]".format(vm_name, task_type, time_counter)
if log_level == 'info':
log.info(message)
else:
log.debug(message)
time.sleep(int(sleep_seconds))
time_counter += int(sleep_seconds)
if task.info.state == 'success':
message = "[ {0} ] Successfully completed {1} task in {2} seconds".format(vm_name, task_type, time_counter)
if log_level == 'info':
log.info(message)
else:
log.debug(message)
else:
raise task.info.error
def _format_instance_info(vm): def _format_instance_info(vm):
device_full_info = {} device_full_info = {}
disk_full_info = {} disk_full_info = {}
@ -490,21 +510,21 @@ def _format_instance_info(vm):
} }
vm_full_info = { vm_full_info = {
'id': vm['name'],
'image': "{0} (Detected)".format(vm["config.guestFullName"]),
'size': u"cpu: {0}\nram: {1}MB".format(vm["config.hardware.numCPU"], vm["config.hardware.memoryMB"]),
'state': str(vm["summary.runtime.powerState"]),
'private_ips': network_full_info["ip_addresses"] if "ip_addresses" in network_full_info else [],
'public_ips': [],
'devices': device_full_info, 'devices': device_full_info,
'storage': storage_full_info, 'storage': storage_full_info,
'files': file_full_info, 'files': file_full_info,
'guest_full_name': vm["config.guestFullName"],
'guest_id': vm["config.guestId"], 'guest_id': vm["config.guestId"],
'hostname': vm["object"].guest.hostName, 'hostname': vm["object"].guest.hostName,
'ip_address': vm["object"].guest.ipAddress,
'mac_address': network_full_info["mac_address"] if "mac_address" in network_full_info else None, 'mac_address': network_full_info["mac_address"] if "mac_address" in network_full_info else None,
'memory_mb': vm["config.hardware.memoryMB"],
'name': vm['name'],
'net': [network_full_info], 'net': [network_full_info],
'num_cpu': vm["config.hardware.numCPU"],
'path': vm["config.files.vmPathName"], 'path': vm["config.files.vmPathName"],
'status': vm["summary.runtime.powerState"], 'tools_status': str(vm["guest.toolsStatus"]),
'tools_status': vm["guest.toolsStatus"],
} }
return vm_full_info return vm_full_info
@ -559,10 +579,9 @@ def list_datacenters(kwargs=None, call=None):
salt-cloud -f list_datacenters my-vmware-config salt-cloud -f list_datacenters my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_datacenters function must be called with -f or --function.' 'The list_datacenters function must be called with -f or --function.'
) )
return False
datacenters = [] datacenters = []
datacenter_properties = ["name"] datacenter_properties = ["name"]
@ -586,10 +605,9 @@ def list_clusters(kwargs=None, call=None):
salt-cloud -f list_clusters my-vmware-config salt-cloud -f list_clusters my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_clusters function must be called with -f or --function.' 'The list_clusters function must be called with -f or --function.'
) )
return False
clusters = [] clusters = []
cluster_properties = ["name"] cluster_properties = ["name"]
@ -613,10 +631,9 @@ def list_datastore_clusters(kwargs=None, call=None):
salt-cloud -f list_datastore_clusters my-vmware-config salt-cloud -f list_datastore_clusters my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_datastore_clusters function must be called with -f or --function.' 'The list_datastore_clusters function must be called with -f or --function.'
) )
return False
datastore_clusters = [] datastore_clusters = []
datastore_cluster_properties = ["name"] datastore_cluster_properties = ["name"]
@ -640,10 +657,9 @@ def list_datastores(kwargs=None, call=None):
salt-cloud -f list_datastores my-vmware-config salt-cloud -f list_datastores my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_datastores function must be called with -f or --function.' 'The list_datastores function must be called with -f or --function.'
) )
return False
datastores = [] datastores = []
datastore_properties = ["name"] datastore_properties = ["name"]
@ -667,10 +683,9 @@ def list_hosts(kwargs=None, call=None):
salt-cloud -f list_hosts my-vmware-config salt-cloud -f list_hosts my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_hosts function must be called with -f or --function.' 'The list_hosts function must be called with -f or --function.'
) )
return False
hosts = [] hosts = []
host_properties = ["name"] host_properties = ["name"]
@ -694,10 +709,9 @@ def list_resourcepools(kwargs=None, call=None):
salt-cloud -f list_resourcepools my-vmware-config salt-cloud -f list_resourcepools my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_resourcepools function must be called with -f or --function.' 'The list_resourcepools function must be called with -f or --function.'
) )
return False
resource_pools = [] resource_pools = []
resource_pool_properties = ["name"] resource_pool_properties = ["name"]
@ -721,10 +735,9 @@ def list_networks(kwargs=None, call=None):
salt-cloud -f list_networks my-vmware-config salt-cloud -f list_networks my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_networks function must be called with -f or --function.' 'The list_networks function must be called with -f or --function.'
) )
return False
networks = [] networks = []
network_properties = ["name"] network_properties = ["name"]
@ -777,7 +790,8 @@ def list_nodes(kwargs=None, call=None):
"guest.ipAddress", "guest.ipAddress",
"config.guestFullName", "config.guestFullName",
"config.hardware.numCPU", "config.hardware.numCPU",
"config.hardware.memoryMB" "config.hardware.memoryMB",
"summary.runtime.powerState"
] ]
vm_list = _get_mors_with_properties(vim.VirtualMachine, vm_properties) vm_list = _get_mors_with_properties(vim.VirtualMachine, vm_properties)
@ -785,10 +799,11 @@ def list_nodes(kwargs=None, call=None):
for vm in vm_list: for vm in vm_list:
vm_info = { vm_info = {
'id': vm["name"], 'id': vm["name"],
'ip_address': vm["guest.ipAddress"] if "guest.ipAddress" in vm else None, 'image': "{0} (Detected)".format(vm["config.guestFullName"]),
'guest_fullname': vm["config.guestFullName"], 'size': u"cpu: {0}\nram: {1}MB".format(vm["config.hardware.numCPU"], vm["config.hardware.memoryMB"]),
'cpus': vm["config.hardware.numCPU"], 'state': str(vm["summary.runtime.powerState"]),
'ram': vm["config.hardware.memoryMB"], 'private_ips': [vm["guest.ipAddress"]] if "guest.ipAddress" in vm else [],
'public_ips': []
} }
ret[vm_info['id']] = vm_info ret[vm_info['id']] = vm_info
@ -828,11 +843,28 @@ def list_nodes_full(kwargs=None, call=None):
for vm in vm_list: for vm in vm_list:
vm_full_info = _format_instance_info(vm) vm_full_info = _format_instance_info(vm)
ret[vm_full_info['name']] = vm_full_info ret[vm_full_info['id']] = vm_full_info
return ret return ret
def list_nodes_select(call=None):
'''
Return a list of all VMs and templates that are on the provider, with fields specified
in the ``query.selection`` option in ``/etc/salt/cloud``
CLI Example:
.. code-block:: bash
salt-cloud -f list_nodes_select my-vmware-config
'''
return salt.utils.cloud.list_nodes_select(
list_nodes_full('function'), __opts__.get('query.selection'), call,
)
def show_instance(name, call=None): def show_instance(name, call=None):
''' '''
List all available details of the specified VM List all available details of the specified VM
@ -918,10 +950,9 @@ def list_folders(kwargs=None, call=None):
salt-cloud -f list_folders my-vmware-config salt-cloud -f list_folders my-vmware-config
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_folders function must be called with -f or --function.' 'The list_folders function must be called with -f or --function.'
) )
return False
folders = [] folders = []
folder_properties = ["name"] folder_properties = ["name"]
@ -956,10 +987,9 @@ def list_snapshots(kwargs=None, call=None):
salt-cloud -f list_snapshots my-vmware-config name="vmname" salt-cloud -f list_snapshots my-vmware-config name="vmname"
''' '''
if call != 'function': if call != 'function':
log.error( raise SaltCloudSystemExit(
'The list_snapshots function must be called with -f or --function.' 'The list_snapshots function must be called with -f or --function.'
) )
return False
ret = {} ret = {}
vm_properties = [ vm_properties = [
@ -1171,14 +1201,12 @@ def destroy(name, call=None):
try: try:
log.info('Powering Off VM {0}'.format(name)) log.info('Powering Off VM {0}'.format(name))
task = vm["object"].PowerOff() task = vm["object"].PowerOff()
while task.info.state != 'success': _wait_for_task(task, name, "power off")
log.debug("Waiting for Power off task to finish")
except Exception as exc: except Exception as exc:
log.error('Could not destroy VM {0}: {1}'.format(name, exc)) log.error('Could not destroy VM {0}: {1}'.format(name, exc))
return 'failed to destroy' return 'failed to destroy'
task = vm["object"].Destroy_Task() task = vm["object"].Destroy_Task()
while task.info.state != 'success': _wait_for_task(task, name, "destroy")
log.debug("Waiting for destroy task to finish")
salt.utils.cloud.fire_event( salt.utils.cloud.fire_event(
'event', 'event',
@ -1278,8 +1306,9 @@ def create(vm_):
cluster_ref = _get_mor_by_property(vim.ClusterComputeResource, cluster) cluster_ref = _get_mor_by_property(vim.ClusterComputeResource, cluster)
resourcepool_ref = cluster_ref.resourcePool resourcepool_ref = cluster_ref.resourcePool
elif clone_type == "template": elif clone_type == "template":
log.error('You must either specify a cluster, a host or a resource pool') raise SaltCloudSystemExit(
return False 'You must either specify a cluster, a host or a resource pool'
)
# Either a datacenter or a folder can be optionally specified # Either a datacenter or a folder can be optionally specified
# If not specified, the existing VM/template\'s parent folder is used. # If not specified, the existing VM/template\'s parent folder is used.
@ -1369,11 +1398,7 @@ def create(vm_):
) )
task = object_ref.Clone(folder_ref, vm_name, clone_spec) task = object_ref.Clone(folder_ref, vm_name, clone_spec)
time_counter = 0 _wait_for_task(task, vm_name, "clone", 5, 'info')
while task.info.state == 'running':
log.info("Waiting for clone task to finish [{0} s]".format(time_counter))
time.sleep(5)
time_counter += 5
except Exception as exc: except Exception as exc:
log.error( log.error(
'Error creating {0}: {1}'.format( 'Error creating {0}: {1}'.format(
@ -1419,3 +1444,125 @@ def create(vm_):
return False return False
return {vm_name: data} return {vm_name: data}
def create_datacenter(kwargs=None, call=None):
'''
Create a new data center in this VMware environment
CLI Example:
.. code-block:: bash
salt-cloud -f create_datacenter my-vmware-config name="MyNewDatacenter"
'''
if call != 'function':
raise SaltCloudSystemExit(
'The create_datacenter function must be called with -f or --function.'
)
datacenter_name = kwargs.get('name')
if not datacenter_name:
raise SaltCloudSystemExit(
'You must pass a name for the new datacenter to be created.'
)
if len(datacenter_name) >= 80 or len(datacenter_name) <= 0:
raise SaltCloudSystemExit(
'The datacenter name must be a non empty string of less than 80 characters.'
)
# Check if datacenter already exists
datacenter_ref = _get_mor_by_property(vim.Datacenter, datacenter_name)
if datacenter_ref:
return {datacenter_name: 'datacenter already exists'}
# Get the service instance
si = _get_si()
folder = si.content.rootFolder
# Verify that the folder is of type vim.Folder
if isinstance(folder, vim.Folder):
try:
folder.CreateDatacenter(name=datacenter_name)
except Exception as exc:
log.error(
'Error creating datacenter {0}: {1}'.format(
datacenter_name,
exc
),
# Show the traceback if the debug logging level is enabled
exc_info_on_loglevel=logging.DEBUG
)
return False
log.debug("Created datacenter {0}".format(datacenter_name))
return {datacenter_name: 'created'}
return False
def create_cluster(kwargs=None, call=None):
'''
Create a new cluster under the specified datacenter in this VMware environment
CLI Example:
.. code-block:: bash
salt-cloud -f create_cluster my-vmware-config name="MyNewCluster" datacenter="DatacenterName"
'''
if call != 'function':
raise SaltCloudSystemExit(
'The create_cluster function must be called with -f or --function.'
)
cluster_name = kwargs.get('name')
datacenter = kwargs.get('datacenter')
if not cluster_name:
raise SaltCloudSystemExit(
'You must pass a name for the new cluster to be created.'
)
if not datacenter:
raise SaltCloudSystemExit(
'You must pass a name for the datacenter where the cluster should be created.'
)
if not isinstance(datacenter, vim.Datacenter):
datacenter = _get_mor_by_property(vim.Datacenter, datacenter)
if not datacenter:
raise SaltCloudSystemExit(
'The specified datacenter does not exist.'
)
# Check if cluster already exists
cluster_ref = _get_mor_by_property(vim.ClusterComputeResource, cluster_name)
if cluster_ref:
return {cluster_name: 'cluster already exists'}
cluster_spec = vim.cluster.ConfigSpecEx()
folder = datacenter.hostFolder
# Verify that the folder is of type vim.Folder
if isinstance(folder, vim.Folder):
try:
folder.CreateClusterEx(name=cluster_name, spec=cluster_spec)
except Exception as exc:
log.error(
'Error creating cluster {0}: {1}'.format(
cluster_name,
exc
),
# Show the traceback if the debug logging level is enabled
exc_info_on_loglevel=logging.DEBUG
)
return False
log.debug("Created cluster {0} under datacenter {1}".format(cluster_name, datacenter.name))
return {cluster_name: 'created'}
return False