Author: Harper Joe
根据场景需要,自动化克隆虚拟机,减少运维工作量;
pip freeze | grep pyvmomi
检查版本,当前使用7.0.3。可以使用pip install --upgrade pyvmomi
升级https://github.com/vmware/pyvmomi
git clone https://github.com/vmware/pyvmomi-community-samples.git
# -*- coding: utf-8 -*-
"""
func: 批量克隆虚拟机
Author: CSDN.晴空万里长风微凉
"""
import json
import logging
import sys, time
import traceback
import atexit
try:
from pyVim.connect import SmartConnect, SmartConnectNoSSL, Disconnect
except ImportError:
from pyvim.connect import SmartConnect, SmartConnectNoSSL, Disconnect
from pyVmomi import vim
reload(sys)
sys.setdefaultencoding('utf8')
# create logger object
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger_handler = logging.StreamHandler(stream=sys.stdout)
logger_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(lineno)d] %(message)s', '%Y-%m-%d %H:%M:%S')
logger_handler.setFormatter(formatter)
logger.addHandler(logger_handler)
class VmManage(object):
def __init__(self, host, user, password, port, ssl):
self.host = host
self.user = user
self.pwd = password
self.port = port
self.sslContext = ssl
try:
self.client = SmartConnectNoSSL(host=host, # SmartConnectNoSSL: 不需要ssl证书验证
user=user,
pwd=password,
port=443
)
self.content = self.client.RetrieveContent()
self.result = True
except Exception as e:
self.result = False
self.message = e
def _get_all_objs(self, obj_type, folder=None):
"""
根据对象类型获取这一类型的所有对象
"""
if folder is None:
container = self.content.viewManager.CreateContainerView(self.content.rootFolder, obj_type, True)
else:
container = self.content.viewManager.CreateContainerView(folder, obj_type, True)
return container.view
def _get_obj(self, obj_type, name):
"""
根据对象类型和名称来获取具体对象
"""
obj = None
content = self.client.RetrieveContent()
container = content.viewManager.CreateContainerView(content.rootFolder, obj_type, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
def get_datacenters(self):
"""
返回所有的数据中心
"""
return self._get_all_objs([vim.Datacenter])
def get_datacenter_by_name(self, datacenter_name):
"""
根据数据中心名称获取数据中心对象
"""
return self._get_obj([vim.Datacenter], datacenter_name)
def get_datacenter_objs(self):
"""
:return: 获取数据中心下有多少集群、主机、目录(只获取数据中心当层数据)
"""
datacenter_objs = self._get_all_objs([vim.Datacenter])
data = []
for i in datacenter_objs:
datacenter_data = {'datacenter_name': i.name, # 数据中心
'data': {}
}
datacenter_data['data']['cluster_nums'] = 0
datacenter_data['data']['cluster_data'] = []
datacenter_data['data']['host_nums'] = 0
datacenter_data['data']['host_data'] = []
datacenter_data['data']['folder_nums'] = 0
datacenter_data['data']['folder_data'] = []
for j in i.hostFolder.childEntity:
if type(j) == vim.ClusterComputeResource:
datacenter_data['data']['cluster_nums'] += 1
datacenter_data['data']['cluster_data'].append(j.name)
elif type(j) == vim.HostSystem:
datacenter_data['data']['host_nums'] += 1
datacenter_data['data']['host_data'].append(j.name)
elif type(j) == vim.Folder:
datacenter_data['data']['folder_nums'] += 1
datacenter_data['data']['folder_data'].append(j.name)
data.append(datacenter_data)
return data
# ------------
# vcenter执行动作等待
def wait_for_task(self, task):
""" wait for a vCenter task to finish """
task_done = False
while not task_done:
print "task.....%s " % task.info.state
time.sleep(2)
if task.info.state == 'success':
return {'message': u'执行成功', 'status': True}
if task.info.state == 'error':
print "there was an error"
return {'message': task.info.error.msg, 'status': False}
def handleTask(self, tasks=None):
if tasks is None:
return False
else:
from pyvim.task import WaitForTasks
try:
WaitForTasks(tasks=tasks, si=self.client)
except Exception as e:
traceback.print_exc()
print str(e)
return False
def get_cluster_by_name(self, name=None, datacenter=None):
if datacenter:
folder = datacenter.hostFolder
else:
folder = self.content.rootFolder
container = self.content.viewManager.CreateContainerView(folder, [vim.ClusterComputeResource], True)
clusters = container.view
for cluster in clusters:
if cluster.name == name:
return cluster
return None
def get_datastore_by_name(self, name, datacenter):
datastores = datacenter.datastore
for datastore in datastores:
if datastore.name == name:
return datastore
return None
def get_host_by_name(self, name, datastore):
hosts = datastore.host
for host in hosts:
if host.key.summary.config.name == name:
return host.key
return None
def get_vms_by_cluster(self, vmFolder):
content = self.client.content
objView = content.viewManager.CreateContainerView(vmFolder, [vim.VirtualMachine], True)
vmList = objView.view
objView.Destroy()
return vmList
def get_customspec(self, vm_ip=None, vm_subnetmask=None, vm_gateway=None, vm_dns=None,
vm_domain=None, vm_hostname=None):
# guest NIC settings 有关dns和域名的配置错误 更改了
adaptermaps = []
guest_map = vim.vm.customization.AdapterMapping()
guest_map.adapter = vim.vm.customization.IPSettings()
guest_map.adapter.ip = vim.vm.customization.FixedIp()
guest_map.adapter.ip.ipAddress = vm_ip
guest_map.adapter.subnetMask = vm_subnetmask
guest_map.adapter.gateway = vm_gateway
if vm_domain:
guest_map.adapter.dnsDomain = vm_domain
adaptermaps.append(guest_map)
# DNS settings
globalip = vim.vm.customization.GlobalIPSettings()
if vm_dns:
globalip.dnsServerList = [vm_dns]
globalip.dnsSuffixList = vm_domain
# Hostname settings
ident = vim.vm.customization.LinuxPrep()
if vm_domain:
ident.domain = vm_domain
ident.hostName = vim.vm.customization.FixedName()
if vm_hostname:
ident.hostName.name = vm_hostname
customspec = vim.vm.customization.Specification()
customspec.nicSettingMap = adaptermaps
customspec.globalIPSettings = globalip
customspec.identity = ident
return customspec
def device_nic(self, vm, network_name, switch_type):
"""
:param vm: 虚拟机模板对象
:param network_name: 要修改的网络段名称
:param switch_type: 网络段类型
:return:
"""
device_change = []
no_vlan = False
for device in vm.config.hardware.device:
# 判断是否存在网络适配器
if isinstance(device, vim.vm.device.VirtualEthernetCard):
nicspec = vim.vm.device.VirtualDeviceSpec()
# 一定要是vim.vm.device.VirtualDeviceSpec.Operation.edit 代表编辑
nicspec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
nicspec.device = device
nicspec.device.wakeOnLanEnabled = True
if switch_type == 1:
# 标准交换机设置
nicspec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
nicspec.device.backing.network = self._get_obj([vim.Network], network_name)
nicspec.device.backing.deviceName = network_name
else:
# 判断网络段是否在分组交换机网络范围
network = self._get_obj([vim.dvs.DistributedVirtualPortgroup], network_name)
if network is None:
logger.error(u'分组交换机没有{0}网段'.format(network_name))
no_vlan = True
break
# 分布式交换机设置
dvs_port_connection = vim.dvs.PortConnection()
dvs_port_connection.portgroupKey = network.key
dvs_port_connection.switchUuid = network.config.distributedVirtualSwitch.uuid
nicspec.device.backing = vim.vm.device.VirtualEthernetCard.DistributedVirtualPortBackingInfo()
nicspec.device.backing.port = dvs_port_connection
# 网络段配置设置
nicspec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
nicspec.device.connectable.startConnected = True
nicspec.device.connectable.allowGuestControl = True
device_change.append(nicspec)
logger.info('网络适配器设置')
break
if device_change:
return device_change
else:
if not no_vlan:
logger.error(u'网络适配器不存在,无法修改网络')
return device_change
def add_disk(self, vm_obj, capacity):
"""
:param vm_obj:
:param capacity:
:return: 追加硬盘(配置列表)
"""
spec = vim.vm.ConfigSpec()
dev_changes = []
# capacity 为 存储盘容量将单位改为 G
new_disk_kb = capacity * 1024 * 1024
unit_number = 0
# 遍历所有的硬件设备,找合适的位置添加
for dev in vm_obj.config.hardware.device:
if hasattr(dev.backing, 'fileName'):
unit_number = int(dev.unitNumber) + 1
# unit_number 7 reserved for scsi controller
if unit_number == 7:
unit_number += 1
if unit_number >= 16:
logging.error('we don\'t support this many disks')
if isinstance(dev, vim.vm.device.VirtualSCSIController):
controller = dev
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.thinProvisioned = True
disk_spec.device.backing.diskMode = 'persistent'
disk_spec.device.unitNumber = unit_number
disk_spec.device.capacityInKB = new_disk_kb
disk_spec.device.controllerKey = controller.key
dev_changes.append(disk_spec)
spec.deviceChange = dev_changes
return dev_changes
def change_disk_size(self, vm_obj, vm_disk):
"""
:param vm_obj: 虚拟机对象(模板对象也适用)
:param vm_disk: 硬盘大小(单位:G)
:return: disk_change 配置列表
"""
virtual_disk_devices = []
virtual_disk_device = None
virtual_scsi_controller = None
# Find the disk device
for dev in vm_obj.config.hardware.device:
if isinstance(dev, vim.vm.device.VirtualSCSIController):
virtual_scsi_controller = dev
if isinstance(dev, vim.vm.device.VirtualDisk):
virtual_disk_devices.append(dev)
for dev in virtual_disk_devices:
if dev.controllerKey == virtual_scsi_controller.key:
virtual_disk_device = dev
new_disk_kb = int(vm_disk) * 1024 * 1024
virtual_disk_spec = vim.vm.device.VirtualDeviceSpec()
virtual_disk_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
virtual_disk_spec.device = virtual_disk_device
virtual_disk_spec.device.capacityInKB = new_disk_kb
disk_changes = []
disk_changes.append(virtual_disk_spec)
return disk_changes
def clone(self, template_name, vm_name, datacenter_name, datastore_name, vm_exi_ip,
vm_folder=None, cup_num=None, memory=None, vm_disk=None, vm_ip=None, vm_subnetmask=None,
vm_gateway=None, vm_dns=None, vm_domain=None, vm_hostname=None, vm_vlan=None):
# 获取模版
template = self._get_obj([vim.VirtualMachine], template_name)
if template is None: # 模版不存在
return {'message': u'克隆失败: 模版不存在', 'result': False}
# 选择[克隆的虚拟机存放位置],通过数据中心获取对象
datacenter = self._get_obj([vim.Datacenter], datacenter_name)
if datacenter is None: # 数据中心不存在
return {'message': u'克隆失败: 数据中心不存在', 'result': False}
# vm创建路径
if vm_folder:
vmfolder = self._get_obj([vim.Folder], vm_folder)
else:
vmfolder = datacenter.vmFolder
# vmfolder = self._get_obj([vim.Folder], vm_folder)
# print vmfolder
vmfolder = datacenter.vmFolder
# print vmfolder
# 获取存储
if datastore_name:
datastore = self.get_datastore_by_name(datastore_name, datacenter)
if datastore is None:
return {'message': u'克隆失败: 该数据中心下%s存储不存在' % datastore_name, 'result': False}
else:
datastore = self.get_datastore_by_name(template.datastore[0].info.name, datacenter)
if datastore is None:
return {'message': u'克隆失败: 该数据中心下%s模版不存在' % template_name, 'result': False}
# 获取宿主机
host = self.get_host_by_name(vm_exi_ip, datastore)
if host is None:
return {'message': u'克隆失败: 该存储下%s主机不存在' % vm_exi_ip, 'result': False}
# 获取宿主机下的vm
vms = host.vm
for vm in vms:
config = vm.summary.config
if vm_name == config.name:
return {'message': u'克隆失败: 虚拟机%s已经存在' % vm_name, 'result': False}
# 获取资源池
resourcepool = host.parent.resourcePool
relospec = vim.vm.RelocateSpec()
relospec.datastore = datastore
relospec.pool = resourcepool
relospec.host = host
# 配置Clone属性
clonespec = vim.vm.CloneSpec()
clonespec.location = relospec
clonespec.powerOn = True
device_change = []
# 设置网卡
# if len(template.network) == 0:
# logger.info('设置网卡')
# nic_change = self.add_nic('VM Network')
# device_change.extend(nic_change)
# 指定网络段配置
switch_type = 1 # 网络段类型
if vm_vlan:
device_nic_change = self.device_nic(
vm=template,
network_name=vm_vlan,
switch_type=switch_type
)
device_change.extend(device_nic_change)
# 修改硬盘大小
if vm_disk:
disk_change = self.add_disk(template, vm_disk)
if type(disk_change) is list:
device_change.extend(disk_change)
logger.info('追加硬盘设置')
else:
return {'message': disk_change, 'result': False}
# disk_change = self.change_disk_size(template, vm_disk)
# if type(disk_change) is list:
# device_change.extend(disk_change)
# else:
# return {'message': disk_change, 'result': False}
# 更新配置
vmconf = vim.vm.ConfigSpec(deviceChange=device_change)
# vmconf = vim.vm.ConfigSpec()
# 设置IP
if all([vm_ip, vm_subnetmask, vm_gateway]):
clonespec.customization = self.get_customspec(vm_ip, vm_subnetmask, vm_gateway, vm_dns, vm_domain,
vm_hostname)
logger.info('网卡信息设置, hostname设置')
# 更改cpu和内存
if cup_num:
vmconf.numCPUs = cup_num
logger.info('处理器核数设置')
if memory:
vmconf.memoryMB = memory * 1024
logger.info('内存设置')
if vmconf is not None:
clonespec.config = vmconf
# 开始克隆
task = template.Clone(folder=vmfolder, name=vm_name, spec=clonespec)
# [ 开始执行 ]记录执行日志.
result = self.wait_for_task(task)
if result['status']:
# data = {'message': u'克隆成功', 'result': True}
data = {
'message': u'克隆成功',
'result': True,
'vm_name': vm_name,
'vm_ip': vm_ip,
'vm_exi_ip': vm_exi_ip
}
else:
data = {'message': '克隆失败: %s' % result['message'], 'result': False}
# [ 开始执行 ]不记录vm日志.
# vm_task = {
# 'task': task,
# 'vm_name': vm_name,
# 'vm_ip': vm_ip,
# 'vm_exi_ip': vm_exi_ip,
# }
# data = {'message': u'任务下发成功', 'description': 'Task delivery succeeded!', 'result': True, 'data': vm_task}
return data
# 获取资源信息(每台需克隆机器的相关信息)
def gen_resource_info():
# VCSA登录信息
vm_vcsa_info = {}
vm_vcsa_info.update({
"vm_judge_clone": vm_judge_clone, # 是否自动克隆判断
"vm_vcsa_addr": vm_vcsa_addr, # VCSA地址
"vm_vcsa_user": vm_vcsa_user, # VCSA用户名
"vm_vcsa_passwd": vm_vcsa_passwd, # VCSA密码密钥键
"vm_datacenter_name": vm_datacenter_name, }) # 数据中心名称
# 资源表
resource_table_cl = [] # 每台申请虚拟机的信息,包括以下
resource_table = []
if resource_table_cl:
for r in resource_table_cl:
host_source_data_of_resource = {
"server_name": server_name, # 主机名
"host_server_use": host_server_use,# 主机用途
"host_node_config": host_node_config,# cpu核数、内存大小
"host_net_ip": host_net_ip,
"host_net_gateway": host_net_gateway,
"host_net_dns": host_net_dns,
"host_net_netmask": host_net_netmask,
"host_owner_name": host_owner_name, # 应用负责人
"disk_root_add": disk_root_add,# 系统盘扩容申请
"disk_root_num": disk_root_num, # 系统盘扩容大小
"vm_info": {
"vm_esxi_name": vm_esxi_name, # ESXI名称
"vm_template_name": vm_template_name, # 模版
"vm_storage_name": vm_storage_name, # 存储名称
},
}
resource_table.append(host_source_data_of_resource)
return vm_vcsa_info, resource_table
def app_run():
vm_vcsa_info, resource_info = gen_resource_info() # 资源表
# vcenter_login—check
vm_judge_clone = vm_vcsa_info["vm_judge_clone"] # 是否自动克隆判断
vm_vcsa_addr = vm_vcsa_info["vm_vcsa_addr"] # VCSA地址
vm_vcsa_user = vm_vcsa_info["vm_vcsa_user"] # VCSA用户名
vm_vcsa_passwd = vm_vcsa_info["vm_vcsa_passwd"] # VCSA密码
vm_datacenter_name = vm_vcsa_info["vm_datacenter_name"] # 数据中心名称
vm_port = 443
if isinstance(resource_info, list):
if vm_judge_clone == "是":
pass
else:
pass
vm = VmManage(host=vm_vcsa_addr, user=vm_vcsa_user, password=vm_vcsa_passwd, port=vm_port, ssl=None)
if vm.result:
logger.info("与VCSA连接成功, 准备读取table容器...") # 说明连接成功,可以使用vm.client等
else:
raise Exception("与VCSA连接失败,报错信息: %s" % vm.message)
atexit.register(Disconnect, vm) # 注册程序退出时的回调函数(断开时操作)
# clone
for i in resource_info:
# vm_info
vm_info = i["vm_info"]
# vm_folder_name = vm_info["vm_folder_name"] # 文件夹名称
vm_esxi_name = vm_info["vm_esxi_name"] # ESXI名称
vm_template_name = vm_info["vm_template_name"] # 模版
vm_storage_name = vm_info["vm_storage_name"] # 存储名称
# vm_Virtual
server_name = i["server_name"] # 主机名
host_server_use = i["host_server_use"] # 主机用途
host_node_config = i["host_node_config"] # cpu核数、内存大小
host_net_ip = i["host_net_ip"]
host_net_gateway = i["host_net_gateway"]
host_net_dns = i["host_net_dns"]
host_net_netmask = i["host_net_netmask"]
host_owner_name = i["host_owner_name"] # 应用负责人
disk_root_add = i["disk_root_add"] # 系统盘扩容申请
disk_root_num = i["disk_root_num"] # 系统盘扩容大小
try:
# clone
vm_hostname_comp = server_name + "-%s" % host_owner_name + "-%s" % host_net_ip
host_node_cpu = int(host_node_config.split("/")[0][:-1])
host_node_mem = int(host_node_config.split("/")[1][:-1])
host_network_port_group = '.'.join(host_net_ip.split('.')[:-1])
disk_increase = None
if disk_root_add == "是": # 磁盘追加
disk_increase = disk_root_num
data = vm.clone(
# vm_info —— 向vm中写入信息
template_name=vm_template_name,
vm_name=vm_hostname_comp,
datacenter_name=vm_datacenter_name,
datastore_name=vm_storage_name,
vm_exi_ip=vm_esxi_name,
# vm_folder=vm_folder_name,
# vm_Virtual —— 自定义虚拟机信息
cup_num=host_node_cpu,
memory=host_node_mem,
vm_disk=disk_increase,
vm_ip=host_net_ip,
vm_subnetmask=host_net_netmask,
vm_gateway=host_net_gateway,
vm_dns=host_net_dns,
vm_domain=None,
vm_hostname=server_name,
vm_vlan=host_network_port_group,
)
logger.info(data)
except Exception as e:
logger.error("%s 克隆出错!及时查看, info: %s" % (host_net_ip, e))
app_run()
# -*- coding:utf-8 -*-
# 参考https://github.com/vmware/pyvmomi/blob/master/sample/poweronvm.py
"""
func: 批量开启虚拟机
Author: CSDN.晴空万里长风微凉
"""
from __future__ import print_function
from pyvim.connect import SmartConnect, Disconnect, SmartConnectNoSSL
from pyVmomi import vim, vmodl
import logging
import argparse
import atexit
import getpass
import sys
import ssl
reload(sys)
sys.setdefaultencoding('utf8')
# create logger object
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger_handler = logging.StreamHandler(stream=sys.stdout)
logger_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(lineno)d] %(message)s', '%Y-%m-%d %H:%M:%S')
logger_handler.setFormatter(formatter)
logger.addHandler(logger_handler)
def GetArgs():
"""
Supports the command-line arguments listed below.
"""
parser = argparse.ArgumentParser(description='Process args for powering on a Virtual Machine')
parser.add_argument('-s', '--host', required=True, action='store', help='Remote host to connect to')
parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on')
parser.add_argument('-u', '--user', required=True, action='store', help='User name to use when connecting to host')
parser.add_argument('-p', '--password', required=False, action='store',
help='Password to use when connecting to host')
parser.add_argument('-v', '--vmname', required=True, action='append',
help='Names of the Virtual Machines to power on')
args = parser.parse_args()
return args
def WaitForTasks(tasks, si):
"""
Given the service instance si and tasks, it returns after all the
tasks are complete
"""
pc = si.content.propertyCollector
taskList = [str(task) for task in tasks]
# Create filter
objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
for task in tasks]
propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task,
pathSet=[], all=True)
filterSpec = vmodl.query.PropertyCollector.FilterSpec()
filterSpec.objectSet = objSpecs
filterSpec.propSet = [propSpec]
filter = pc.CreateFilter(filterSpec, True)
try:
version, state = None, None
# Loop looking for updates till the state moves to a completed state.
while len(taskList):
update = pc.WaitForUpdates(version)
for filterSet in update.filterSet:
for objSet in filterSet.objectSet:
task = objSet.obj
for change in objSet.changeSet:
if change.name == 'info':
state = change.val.state
elif change.name == 'info.state':
state = change.val
else:
continue
if not str(task) in taskList:
continue
if state == vim.TaskInfo.State.success:
# Remove task from taskList
taskList.remove(str(task))
elif state == vim.TaskInfo.State.error:
raise task.info.error
# Move to next version
version = update.version
finally:
if filter:
filter.Destroy()
# Start program
def main():
"""
Simple command-line program for powering on virtual machines on a system.
"""
# args = GetArgs()
# if args.password:
# password = args.password
# else:
# password = getpass.getpass(prompt='Enter password for host %s and user %s: ' % (args.host,args.user))
try:
# vmnames = args.vmname
# 将需要开机的vmwarem_name用逗号或者空格拼凑起来
vmnames = 'clone_auto_WB2'
if not len(vmnames):
print("No virtual machine specified for poweron")
sys.exit()
context = None
# si = SmartConnectNoSSL(host="192.168.0.0", # SmartConnectNoSSL: 不需要ssl证书验证
# user="u",
# pwd="",
# port=443)
if hasattr(ssl, '_create_unverified_context'):
context = ssl._create_unverified_context()
si = SmartConnect(host="vcsa/esxi_address",
user="user",
pwd="",
port=443,
sslContext=context)
if not si:
print("Cannot connect to specified host using specified username and password")
sys.exit()
atexit.register(Disconnect, si)
# 从目录对象中检索虚拟机列表
# 下面的rootFolder
content = si.content
objView = content.viewManager.CreateContainerView(content.rootFolder,
[vim.VirtualMachine],
True)
vmList = objView.view
objView.Destroy()
# Find the vm and power it on
# 遍历vmList拼凑任务
virtual_lists = [vm.name for vm in vmList]
logger.info("虚拟机列表: %s" % virtual_lists)
# for vm in vmList:
# print(vm.name)
tasks = [vm.PowerOn() for vm in vmList if vm.name in vmnames]
logger.info("虚拟机电源开启清单: %s" % tasks)
# Wait for power on to complete
# 启动任务
# WaitForTasks(tasks, si)
logger.info("Virtual Machine(s) have been powered on successfully")
except vmodl.MethodFault as e:
logger.info("Caught vmodl fault : " + e.msg)
except Exception as e:
logger.info("Caught Exception : " + str(e))
# Start program
if __name__ == "__main__":
main()
# -s vcenter 的ip地址
# -u vcenter账号 -p vcenter密码
# -v 需要开机的虚拟机hostname
# [root@Max_master:~#]$ python3 python_poweron.py -s IP -o 443 -u USERNAME -p PASSWORD -v VM_HOSTNAME
# -*- coding:utf-8 -*-
# 参考https://github.com/vmware/pyvmomi/blob/master/sample/poweronvm.py
"""
func: 批量关闭虚拟机
Author: CSDN.晴空万里长风微凉
"""
from __future__ import print_function
from pyvim.connect import SmartConnect, Disconnect, SmartConnectNoSSL
from pyVmomi import vim, vmodl
import logging
import argparse
import atexit
import getpass
import sys
import ssl
reload(sys)
sys.setdefaultencoding('utf8')
# create logger object
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger_handler = logging.StreamHandler(stream=sys.stdout)
logger_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(lineno)d] %(message)s', '%Y-%m-%d %H:%M:%S')
logger_handler.setFormatter(formatter)
logger.addHandler(logger_handler)
def GetArgs():
"""
Supports the command-line arguments listed below.
"""
parser = argparse.ArgumentParser(description='Process args for powering on a Virtual Machine')
parser.add_argument('-s', '--host', required=True, action='store', help='Remote host to connect to')
parser.add_argument('-o', '--port', type=int, default=443, action='store', help='Port to connect on')
parser.add_argument('-u', '--user', required=True, action='store', help='User name to use when connecting to host')
parser.add_argument('-p', '--password', required=False, action='store',
help='Password to use when connecting to host')
parser.add_argument('-v', '--vmname', required=True, action='append',
help='Names of the Virtual Machines to power on')
args = parser.parse_args()
return args
def WaitForTasks(tasks, si):
"""
Given the service instance si and tasks, it returns after all the
tasks are complete
"""
pc = si.content.propertyCollector
taskList = [str(task) for task in tasks]
# Create filter
objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task)
for task in tasks]
propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task,
pathSet=[], all=True)
filterSpec = vmodl.query.PropertyCollector.FilterSpec()
filterSpec.objectSet = objSpecs
filterSpec.propSet = [propSpec]
filter = pc.CreateFilter(filterSpec, True)
try:
version, state = None, None
# Loop looking for updates till the state moves to a completed state.
while len(taskList):
update = pc.WaitForUpdates(version)
for filterSet in update.filterSet:
for objSet in filterSet.objectSet:
task = objSet.obj
for change in objSet.changeSet:
if change.name == 'info':
state = change.val.state
elif change.name == 'info.state':
state = change.val
else:
continue
if not str(task) in taskList:
continue
if state == vim.TaskInfo.State.success:
# Remove task from taskList
taskList.remove(str(task))
elif state == vim.TaskInfo.State.error:
raise task.info.error
# Move to next version
version = update.version
finally:
if filter:
filter.Destroy()
# Start program
def main():
"""
Simple command-line program for powering on virtual machines on a system.
"""
# args = GetArgs()
# if args.password:
# password = args.password
# else:
# password = getpass.getpass(prompt='Enter password for host %s and user %s: ' % (args.host,args.user))
try:
# vmnames = args.vmname
# 将需要关机的vmwarem_name用逗号或者空格拼凑起来
vmnames = 'clone_auto_WB2'
if not len(vmnames):
print("No virtual machine specified for poweron")
sys.exit()
context = None
if hasattr(ssl, '_create_unverified_context'):
context = ssl._create_unverified_context()
si = SmartConnect(host="192.168.",
user='a',
pwd="",
port=443,
sslContext=context)
if not si:
print("Cannot connect to specified host using specified username and password")
sys.exit()
atexit.register(Disconnect, si)
# 从目录对象中检索虚拟机列表
# 下面的rootFolder
content = si.content
objView = content.viewManager.CreateContainerView(content.rootFolder,
[vim.VirtualMachine],
True)
vmList = objView.view
objView.Destroy()
# Find the vm and power it on
# 遍历vmList拼凑任务
virtual_lists = [vm.name for vm in vmList]
logger.info("虚拟机列表: %s" % virtual_lists)
# for vm in vmList:
# print(vm.name)
tasks = [vm.PowerOff() for vm in vmList if vm.name in vmnames]
logger.info("虚拟机电源开启清单: %s" % tasks)
# Wait for power on to complete
# 启动任务
# WaitForTasks(tasks, si)
logger.info("Virtual Machine(s) have been powered off successfully")
except vmodl.MethodFault as e:
logger.info("Caught vmodl fault : " + e.msg)
except Exception as e:
logger.info("Caught Exception : " + str(e))
# Start program
if __name__ == "__main__":
main()
# -s vcenter 的ip地址
# -u vcenter账号 -p vcenter密码
# -v 需要关机的虚拟机hostname
# [root@Max_master:~#]$ python3 python_poweroff.py -s IP -o 443 -u USERNAME -p PASSWORD -v VM_HOSTNAME
"""
func: 批量关闭虚拟机
Author: CSDN.晴空万里长风微凉
"""
# -*- coding:utf-8 -*-
import json
from pyvim.connect import SmartConnect, SmartConnectNoSSL, Disconnect
from pyVmomi import vim
import traceback
import atexit
import sys, time
import logging
reload(sys)
sys.setdefaultencoding('utf8')
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger_handler = logging.StreamHandler(stream=sys.stdout)
logger_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(lineno)d] %(message)s', '%Y-%m-%d %H:%M:%S')
logger_handler.setFormatter(formatter)
logger.addHandler(logger_handler)
class VmManage(object):
def __init__(self, host, user, password, port, ssl):
self.host = host
self.user = user
self.pwd = password
self.port = port
self.sslContext = ssl
try:
self.client = SmartConnectNoSSL(host=host, # SmartConnectNoSSL: 不需要ssl证书验证
user=user,
pwd=password,
port=443
)
self.content = self.client.RetrieveContent()
self.result = True
except Exception as e:
self.result = False
self.message = e
def _get_all_objs(self, obj_type, folder=None):
"""
根据对象类型获取这一类型的所有对象
"""
if folder is None:
container = self.content.viewManager.CreateContainerView(self.content.rootFolder, obj_type, True)
else:
container = self.content.viewManager.CreateContainerView(folder, obj_type, True)
return container.view
def _get_obj(self, obj_type, name):
"""
根据对象类型和名称来获取具体对象
"""
obj = None
content = self.client.RetrieveContent()
container = content.viewManager.CreateContainerView(content.rootFolder, obj_type, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
def wait_for_task(self, task):
""" wait for a vCenter task to finish """
task_done = False
while not task_done:
print "task.....%s " % task.info.state
time.sleep(2)
if task.info.state == 'success':
return {'message': u'执行成功', 'status': True}
if task.info.state == 'error':
print "there was an error"
return {'message': task.info.error.msg, 'status': False}
def add_disk(self, vm_obj, capacity):
spec = vim.vm.ConfigSpec()
dev_changes = []
# capacity 为 存储盘容量将单位改为 G
new_disk_kb = capacity * 1024 * 1024
unit_number = 0
# 遍历所有的硬件设备,找合适的位置添加
for dev in vm_obj.config.hardware.device:
if hasattr(dev.backing, 'fileName'):
unit_number = int(dev.unitNumber) + 1
# unit_number 7 reserved for scsi controller
if unit_number == 7:
unit_number += 1
if unit_number >= 16:
logging.error('we don\'t support this many disks')
if isinstance(dev, vim.vm.device.VirtualSCSIController):
controller = dev
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.thinProvisioned = True
disk_spec.device.backing.diskMode = 'persistent'
disk_spec.device.unitNumber = unit_number
disk_spec.device.capacityInKB = new_disk_kb
disk_spec.device.controllerKey = controller.key
dev_changes.append(disk_spec)
spec.deviceChange = dev_changes
task = vm_obj.ReconfigVM_Task(spec=spec)
result1 = self.wait_for_task(task)
if result1['status']:
data = {'message': u'硬盘添加成功', 'result': True}
else:
data = {'message': u'硬盘添加失败: %s' % result1['message'], 'result': False}
return data
if __name__ == '__main__':
# ------------------ ESXI/VcenterSA - 登录检查'Start ------------------ Top密码需要存入密钥加密
ip = 'vcsa/esxi address'
user = 'administrator@vsphere.local'
password = ''
port = 443
vm = VmManage(host=ip,
user=user,
password=password,
port=443, ssl=None)
if vm.result:
pass # 说明连接成功,可以使用vm.client等
else:
print vm.message
atexit.register(Disconnect, vm) # 注册程序退出时的回调函数(断开时操作)
# ------------------ ESXI/VcenterSA - 登录检查'End ------------------
# pyvmomi 登录设备
vm_name = "clone_auto_WB2" # 虚拟机名称
add_disk_capacity = 2 # GB
vm_obj = vm._get_obj([vim.VirtualMachine], vm_name)
# 虚拟机添加硬盘
vm_obj_add_disk = vm.add_disk(vm_obj, add_disk_capacity)
print(vm_obj_add_disk)