共计 13291 个字符,预计需要花费 34 分钟才能阅读完成。
写在后面
接上篇,上篇分享了 openstack 的 api 应用套路,本篇分享 vmware 的 api 应用套路,心愿能够帮忙到有须要的盆友。
在观看本文之前,也是最重要的一点,就是请确保你曾经搭建好了用于测试的 vsphere 环境(esxi 和 vcenter)。
我的测试环境:
API 文档浏览套路 & 实战
首次浏览 vsphere api 文档的话,可能会有点懵,上面我把最须要关注的点,以及浏览套路给说分明,搞明确之后,其实也都够用了。
官网 API 文档:https://developer.vmware.com/…
1. 对于 vsphere 的能力,咱们更关注的是 vSphere Web Services API
2. 依据 vsphere 版本抉择绝对应的 API 版本
3. 对象类型
如上图,All Types 蕴含了上面几种类型,只是做了分类而已:
- Managed Object Types
- Data Object Types
- Enumerated Types
- Fault Types
Managed Object Types 是最罕用的,有虚拟机(VirtualMachine)、存储(Datastore)、宿主机(HostSystem)、网络(Network)等等,那平时怎么应用它呢?假如,当失去一个虚拟机实例对象时,想晓得它都能获取到什么属性,那么就能够在 Property 进行查阅。
![图片]()
还有一个特地留神的中央,就是 vim.VirtualMachine,它其实是某种对象类型的示意办法或者说是标识。比方,应用 python 的 pyvmomi 库,就须要指定查找的对象类型。如果是应用 go,则是指定 ”VirtualMachine”
应用 Go 编码,获取虚拟机属性:
package main
import (
"context"
"flag"
"fmt"
"log"
"net/url"
"os"
"strings"
"github.com/vmware/govmomi/session/cache"
"github.com/vmware/govmomi/simulator"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
)
func getEnvString(v string, def string) string {r := os.Getenv(v)
if r == "" {return def}
return r
}
func getEnvBool(v string, def bool) bool {r := os.Getenv(v)
if r == "" {return def}
switch strings.ToLower(r[0:1]) {
case "t", "y", "1":
return true
}
return false
}
const (
envURL = "GOVMOMI_URL"
envUserName = "GOVMOMI_USERNAME"
envPassword = "GOVMOMI_PASSWORD"
envInsecure = "GOVMOMI_INSECURE"
)
var urlDescription = fmt.Sprintf("ESX or vCenter URL [%s]", envURL)
var urlFlag = flag.String("url", getEnvString(envURL, ""), urlDescription)
var insecureDescription = fmt.Sprintf("Don't verify the server's certificate chain [%s]", envInsecure)
var insecureFlag = flag.Bool("insecure", getEnvBool(envInsecure, false), insecureDescription)
func processOverride(u *url.URL) {envUsername := os.Getenv(envUserName)
envPassword := os.Getenv(envPassword)
if envUsername != "" {
var password string
var ok bool
if u.User != nil {password, ok = u.User.Password()
}
if ok {u.User = url.UserPassword(envUsername, password)
} else {u.User = url.User(envUsername)
}
}
if envPassword != "" {
var username string
if u.User != nil {username = u.User.Username()
}
u.User = url.UserPassword(username, envPassword)
}
}
func NewClient(ctx context.Context) (*vim25.Client, error) {u, err := soap.ParseURL(*urlFlag)
if err != nil {return nil, err}
processOverride(u)
s := &cache.Session{
URL: u,
Insecure: *insecureFlag,
}
c := new(vim25.Client)
err = s.Login(ctx, c, nil)
if err != nil {return nil, err}
return c, nil
}
func Run(f func(context.Context, *vim25.Client) error) {flag.Parse()
var err error
var c *vim25.Client
if *urlFlag == "" {err = simulator.VPX().Run(f)
} else {ctx := context.Background()
c, err = NewClient(ctx)
if err == nil {err = f(ctx, c)
}
}
if err != nil {log.Fatal(err)
}
}
const (vimVirtualMachine = "VirtualMachine")
func a(ctx context.Context, c *vim25.Client) error {m := view.NewManager(c)
v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{vimVirtualMachine}, true)
if err != nil {return err}
defer v.Destroy(ctx)
var vms []mo.VirtualMachine
err = v.Retrieve(ctx, []string{vimVirtualMachine}, []string{"summary"}, &vms)
if err != nil {return err}
for _, vm := range vms {fmt.Println(vm.Summary.Guest.HostName, vm.Summary.Runtime.PowerState)
}
return nil
}
func main() {Run(a)
}
设置好环境变量:
export GOVMOMI_URL="192.168.11.104"
export GOVMOMI_USERNAME="administrator@vsphere.local"
export GOVMOMI_PASSWORD="1qaz#EDC"
export GOVMOMI_INSECURE="y"
测试运行并输入后果:
[root@devhost vmware]# go run coll-vsphere.go
192.168.11.104 poweredOn
photon3-hdcs poweredOn
应用 Python 编码,获取虚拟机属性:
import ssl
import atexit
from pyVim.connect import SmartConnect, Disconnect
from pyVmomi import vim
def main():
si = None
ssl_context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
ssl_context.verify_mode = ssl.CERT_NONE
si = SmartConnect(
host="192.168.11.104",
user="administrator@vsphere.local",
pwd="1qaz#EDC",
port=int(443),
sslContext=ssl_context
)
atexit.register(Disconnect, si)
content = si.RetrieveContent()
container = content.rootFolder
viewType = [vim.VirtualMachine]
recursive = True
containerView = content.viewManager.CreateContainerView(container, viewType, recursive)
children = containerView.view
for child in children:
# print(child.summary.config.name)
print(child.guest.hostName)
if __name__ == "__main__":
main()
运行并输入后果:
[root@devhost cloud-collect]# /usr/local/python2.7.13/bin/python vmcollect.py
192.168.11.104
photon3-hdcs
4. 办法
持续拿 VirtualMachine 对象来看看它都有哪些办法,通过文档可看到虚拟机对象反对很多办法,创立、克隆、开机、关机、增加磁盘、增加网卡等等。每一个办法都详细描述了所须要的参数。在每个具体的对象类型中,都形容了所反对的办法,这些办法也能够在“All Methods”里查到。
上面应用 Python 编码,从模板克隆虚构,代码如下:
import atexit
from pyVmomi import vim
from pyVim.connect import SmartConnectNoSSL, Disconnect
vcenterhost = '192.168.11.104'
vcenteruser = 'administrator@vsphere.local'
vcenterpassword = '1qaz#EDC'
vcenterport = 443
templatename = 'centos7_ttr_temp'
vmname = 'DEMO-13'
parserCpu = 1
parserMem = 128
parserIpaddress = "192.168.11.90"
parserNetmask = "255.255.255.0"
parserGateway = "192.168.11.2"
parserDnsServer = ["8.8.8.8"]
parserDnsdomain = "local.com"
parserPortgroup = "VM Network"
parserDatacenter_name = 'Datacenter'
parserVm_folder = None
parserDatastore_name = 'datastore1'
parserCluster_name = 'DEMO 环境'
parserResource_pool = None
parserPower_on = True
parserDatastorecluster_name = None
def wait_for_task(task):
print('工作创立工夫 {}, 工作 ID: {}'.format(task.info.queueTime, task.info.key))
while True:
if task.info.state == 'error':
print('创立过程中产生了谬误或正告,音讯:{}'.format(task.info.error))
print('创立进度 {}%'.format(task.info.progress)) # 如果工作状态为“正在运行”,则此属性蕴含进度度量,示意为从 0 到 100 的实现百分比。如果未设置此属性,则该命令不会报告进度。if task.info.completeTime: # 判断进度条是否存在
print('创立工作进度终止,谬误音讯:{}'.format(task.info.error))
break
else:
if task.info.state == 'success':
print('虚拟机创立胜利,VM 对象:{}'.format(task.info.result))
break
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
def clone_vm(content, template, vm_name, si, datacenter_name, vm_folder, datastore_name,
cluster_name, resource_pool, power_on, datastorecluster_name, is_cards):
"""
Clone a VM from a template/VM, datacenter_name, vm_folder, datastore_name
cluster_name, resource_pool, and power_on are all optional.
"""
# if none git the first one
datacenter = get_obj(content, [vim.Datacenter], datacenter_name)
if vm_folder:
destfolder = get_obj(content, [vim.Folder], vm_folder)
else:
destfolder = datacenter.vmFolder
if datastore_name:
datastore = get_obj(content, [vim.Datastore], datastore_name)
else:
datastore = get_obj(content, [vim.Datastore], template.datastore[0].info.name)
# if None, get the first one
cluster = get_obj(content, [vim.ClusterComputeResource], cluster_name)
if resource_pool:
resource_pool = get_obj(content, [vim.ResourcePool], resource_pool)
else:
resource_pool = cluster.resourcePool
vmconf = vim.vm.ConfigSpec()
if datastorecluster_name:
podsel = vim.storageDrs.PodSelectionSpec()
pod = get_obj(content, [vim.StoragePod], datastorecluster_name)
podsel.storagePod = pod
storagespec = vim.storageDrs.StoragePlacementSpec()
storagespec.podSelectionSpec = podsel
storagespec.type = 'create'
storagespec.folder = destfolder
storagespec.resourcePool = resource_pool
storagespec.configSpec = vmconf
try:
rec = content.storageResourceManager.RecommendDatastores(storageSpec=storagespec)
rec_action = rec.recommendations[0].action[0]
real_datastore_name = rec_action.destination.name
except:
real_datastore_name = template.datastore[0].info.name
datastore = get_obj(content, [vim.Datastore], real_datastore_name)
# set relospec
relospec = vim.vm.RelocateSpec()
relospec.datastore = datastore
relospec.pool = resource_pool
nic_changes = []
if is_cards:
# 编辑现有网卡连贯指定的端口组
nic_prefix_label = 'Network adapter'
# nic_label = nic_prefix_label + str(1)
nic_label = 'Network adapter 1'
virtual_nic_device = None
for dev in template.config.hardware.device:
if isinstance(dev, vim.vm.device.VirtualEthernetCard) \
and dev.deviceInfo.label == nic_label:
virtual_nic_device = dev
virtual_nic_spec = vim.vm.device.VirtualDeviceSpec()
virtual_nic_spec.operation = vim.vm.device.VirtualDeviceSpec.Operation.edit
virtual_nic_spec.device = virtual_nic_device
content = si.RetrieveContent()
network = get_obj(content, [vim.Network], parserPortgroup)
virtual_nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
virtual_nic_spec.device.backing.deviceName = parserPortgroup
virtual_nic_spec.device.backing.network = network
virtual_nic_spec.device.connectable = vim.vm.device.VirtualDevice.ConnectInfo()
virtual_nic_spec.device.connectable.startConnected = True
virtual_nic_spec.device.connectable.allowGuestControl = True
virtual_nic_spec.device.connectable.connected = True
virtual_nic_spec.device.connectable.status = 'untried'
nic_changes.append(virtual_nic_spec)
else:
# 增加网卡并设置连贯端口组
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.summary = 'vCenter API test'
content = si.RetrieveContent()
network = get_obj(content, [vim.Network], parserPortgroup)
nic_spec.device.backing = vim.vm.device.VirtualEthernetCard.NetworkBackingInfo()
nic_spec.device.backing.deviceName = parserPortgroup
nic_spec.device.backing.network = 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.connectable.connected = True
nic_spec.device.connectable.status = 'untried'
nic_spec.device.wakeOnLanEnabled = True
nic_spec.device.addressType = 'assigned'
nic_changes.append(nic_spec)
# set
vmconf = vim.vm.ConfigSpec(numCPUs=parserCpu, memoryMB=parserMem, deviceChange=nic_changes)
# Network adapter settings
adaptermap = vim.vm.customization.AdapterMapping()
globalip = vim.vm.customization.GlobalIPSettings()
adaptermap.adapter = vim.vm.customization.IPSettings()
adaptermap.adapter.ip = vim.vm.customization.FixedIp()
adaptermap.adapter.ip.ipAddress = parserIpaddress
adaptermap.adapter.subnetMask = parserNetmask
adaptermap.adapter.gateway = parserGateway
adaptermap.adapter.dnsDomain = parserDnsdomain
adaptermap.adapter.dnsServerList = parserDnsServer
# 主机名设置
ident = vim.vm.customization.LinuxPrep(domain=parserDnsdomain, hostName=vim.vm.customization.FixedName(name=vmname))
# 将所有这些部件放在一起以自定义规格
customspec = vim.vm.customization.Specification(nicSettingMap=[adaptermap], globalIPSettings=globalip,identity=ident)
clonespec = vim.vm.CloneSpec(customization=customspec, config=vmconf)
clonespec.location = relospec
clonespec.powerOn = power_on
task = template.Clone(folder=destfolder, name=vm_name, spec=clonespec)
wait_for_task(task)
def main():
si = SmartConnectNoSSL(host=vcenterhost, user=vcenteruser, pwd=vcenterpassword, port=vcenterport)
atexit.register(Disconnect, si)
content = si.RetrieveContent()
template = get_obj(content, [vim.VirtualMachine], templatename)
if template:
num_cards = template.summary.config.numEthernetCards # 获取网卡数量
if num_cards:
print('模板有网卡')
clone_vm(
content, template, vmname, si,
parserDatacenter_name, parserVm_folder,
parserDatastore_name, parserCluster_name,
parserResource_pool, parserPower_on, parserDatastorecluster_name, is_cards=True)
else:
print('模板无网卡')
clone_vm(
content, template, vmname, si,
parserDatacenter_name, parserVm_folder,
parserDatastore_name, parserCluster_name,
parserResource_pool, parserPower_on, parserDatastorecluster_name, is_cards=False)
else:
print("模板没有找到")
if __name__ == "__main__":
main()
写在最初
本次分享就到这里,心愿本文能够帮忙到有须要的盆友,对于代码,上面分享一下官网的参考资料。
Golang:
- https://pkg.go.dev/github.com…
- https://github.com/vmware/gov…
Python:
- https://pypi.org/project/pyvm…
- https://github.com/vmware/vsp…
- https://github.com/vmware/pyv…
本文转载于(喜爱的盆友关注咱们):https://mp.weixin.qq.com/s/yb…