上一篇文章提到了如何使用 python 和 vsphere 進行交互,我只能說我知道 govmomi 太晚了,否則怎麼着都不會使用 python 的,畢竟 python 性能太差,併發用起來太蹩腳。在知道 govmomi 以後就有些蠢蠢欲動,因而抽空研究了下,並記錄了下它的一些簡單用法。html
govmomi 和 pyvmomi 雖然都是基於 VMware 的 api 實現的,可是因爲語言的不一樣,它們使用起來仍是區別很大的。除了性能上的優點以外,govmomi 不只可使用全部操縱虛擬機的功能,還支持從內容庫直接部署虛擬機,這就比我以前文章使用 vsphere-automation-sdk-python + pyvmomi 這種蹩腳的用法要強不少了。不過 govmomi 既然支持內容庫,沒理由 pyvmomi 不支持,莫非是我孤陋寡聞了?不過這些都不是重點,重點是 govmomi。python
govmomi 其實用起來還好,可是坑必定是存在的,這個接下來會提到。咱們先安裝它。git
推薦大家直接訪問它的 github,上面有它的一些說明。上面也提到了安裝的方式:github
go get -u github.com/vmware/govmomi 複製代碼
govcvcsimtoolbox
其中 govc 的源碼是咱們須要密切關注的,由於 govmomi 自己能夠說沒有任何的示例告訴你如何使用,可是你須要的功能 govc 都提供了。因此你要實現什麼功能就看 govc 對應的源碼就好了。最重要的是,govc 源碼的文件很是清晰明瞭,你要什麼功能看對應的文件就行,這個接下來會講到。vim
ok,安裝安裝後,咱們首先須要登陸 vsphere。api
登陸
govmomi 的登陸頗有特點,是我第一次見到的登陸類型,只能說不夠直接,有些遮遮掩掩的感受,不是個人菜。bash
登陸的方式有兩種,第一種是經過環境變量,它須要以下環境變量:markdown
GOVMOMI_URLGOVMOMI_USERNAMEGOVMOMI_PASSWORDGOVMOMI_INSECURE
貌似還有其餘環境變量,可是這四個是咱們登陸須要的。這種登陸方式更多的是測試性質的,沒法正式使用。由於使用這種方式意味着你須要將密碼寫入環境變量,而且在你須要登陸多個 vsphere 時就沒有辦法了。固然,你能夠嘗試在代碼內對環境變量進行修改,試他一把,但我推薦使用第二種方式。併發
第二種方式是經過 url 的方式,將用戶名和密碼都寫入到 url 中。你們知道,http url 的定義是這樣的:
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag> 複製代碼
:/
url 的最終格式以下:
https://user:password@IP/sdk 複製代碼
所以,咱們能夠這麼作:
u := &url.URL{
Scheme: "https",
Host: ip,
Path: "/sdk",
}
u.User = url.UserPassword(user, password)
複製代碼
fmt.Println(u)
ctx := context.Background()
client, err := govmomi.NewClient(p.ctx, u, true)
if err != nil {
panic(err)
}
複製代碼
基本上全部 govmomi 操做都會接收 context 做爲上下文,便於操做取消,所以首先須要建立一個 context 對象。
GOVMOMI_INSECURE
完整寫法:
package main
import (
"context"
"fmt"
"github.com/vmware/govmomi"
"net/url"
)
const (
ip = ""
user = ""
password = ""
)
func main() {
u := &url.URL{
Scheme: "https",
Host: ip,
Path: "/sdk",
}
ctx := context.Background()
u.User = url.UserPassword(user, password)
client, err := govmomi.NewClient(ctx, u, true)
if err != nil {
panic(err)
}
fmt.Println(client)
}
複製代碼
使用 govc
在使用以前,咱們先使用 govc,先要了解它的功能。由於 govc 基本上實現了 govmomi 的全部功能,因此咱們徹底能夠將 govc 的源碼做爲參考,當咱們須要實現相應的功能時,就能夠直接看 govc 的源碼。
首先編譯 govc:
go build github.com/vmware/govmomi/govc/ 複製代碼
要經過定義環境變量來使用它,注意它的環境變量和上面的 govmomi 的環境變量的名稱並不同(意思同樣),不要搞混了。咱們首先定義環境變量:
export GOVC_URL="" export GOVC_USERNAME="" export GOVC_PASSWORD="" export GOVC_INSECURE="true" 複製代碼
我只列出這四個我會用到的,更多的點擊這裏查看。
定義完成以後就可使用了,好比查找當前的 vsphere 上有哪些文件夾:
./govc find / -type f 複製代碼
./govc -hhost.shutdown$GOPATH/src/github.com/vmware/govmomi/govc/host/shutdown.go
查找虛擬機
登陸成功以後,咱們通常作的就是查找虛擬機了,虛擬機的查找有多種方式,能夠經過名稱查、ip 查、文件夾路徑查、uuid 查等。不一樣的查找方式效果不一樣,性能也不一樣。虛擬機有兩種表現形式,不一樣方式查找到的虛擬機形式也不一樣,不過它們能夠相互進行轉換。
經過名稱查找
首先進行最 low 的查找方式,這種就是遍歷全部虛擬機,而後判斷主機名是否相同。
// 這裏的 c 就是上面登陸後 client 的 Client 屬性
func findVMByName(ctx context.Context, c *vim25.Client, vmName string) {
m := view.NewManager(c)
v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, []string{"VirtualMachine"}, true)
if err != nil {
panic(err)
}
defer v.Destroy(ctx)
// Retrieve summary property for all machines
// Reference: http://pubs.vmware.com/vsphere-60/topic/com.vmware.wssdk.apiref.doc/vim.VirtualMachine.html
var vms []mo.VirtualMachine
err = v.Retrieve(ctx, []string{"VirtualMachine"}, []string{"summary"}, &vms)
if err != nil {
panic(err)
}
// Print summary per vm (see also: govc/vm/info.go)
for _, vm := range vms {
// 判斷虛擬機名稱是否相同,相同的話,vm 就是查找到主機
if vm.Summary.Config.Name == vmName {
fmt.Printf("%s: %s\n", vm.Summary.Config.Name, vm.Summary.Config.GuestFullName)
break
}
}
}
複製代碼
mo.VirtualMachine
經過 ip 查找
使用 ip 查找須要虛擬機安裝了 vmtools,且能夠在 web 界面上可以看到它的 ip,所以虛擬機必須處於開機狀態。
func findVMByIP(ctx context.Context, c *vim25.Client, ip string) {
searchIndex := object.NewSearchIndex(c)
// nil 是數據中心,你若是要指定的話,須要構造數據中心的結構體,這裏就不指定了
// ip 是你虛擬機的 ip
// true 的意思我沒搞懂
reference, err := searchIndex.FindByIp(ctx, nil, ip, true)
// 之因此只對 reference 進行判斷而非對 err 是由於沒有找到不算是 error
// 也就是說 err 爲 nil 並不表明就找到了,可是沒找到 reference 必定爲 nil
if reference == nil {
panic("vm not found")
}
// 這類的查找的對象都是 object.Reference,你須要經過對應的方法將其轉換爲相應的對象
// 好比虛擬機、文件夾、模板等~
vm := object.NewVirtualMachine(c, reference.Reference())
fmt.Println(vm)
}
複製代碼
*object.VirtualMachinemo.VirtualMachine
經過文件夾路徑查找
這是根據虛擬機所處的文件夾路徑來查找,前提是你知道你的文件夾的路徑。這個路徑並非你在 web 界面上看到的,你看到的只是路徑的一部分。那麼如何才能知道具體的文件夾路徑是啥呢?你可使用 govc 進行查看。
/數據中心/vm
func findVMByPath(ctx context.Context, c *vim25.Client, folderPath, vmName string) {
searchIndex := object.NewSearchIndex(c)
// 經過 path.Join 將文件夾路徑和虛擬機名稱拼接成完整的虛擬機路徑
reference, err := searchIndex.FindByInventoryPath(ctx, path.Join(folderPath, vmName))
if reference == nil {
panic("vm not found")
}
vm := object.NewVirtualMachine(c, reference.Reference())
fmt.Println(vm)
}
複製代碼
虛擬機類型和上面相同,由於查找的方式相似。
經過 uuid 查找
uuid 查找是惟一的,查找方式和上面幾乎同樣,除非你知道虛擬機的 uuid,不然也沒法使用。
func findVMByUuid(ctx context.Context, c *vim25.Client, uuid string) {
searchIndex := object.NewSearchIndex(c)
// 第一個 nil 指的是數據中心
// true 和以前的 true 意義同樣,只不過我不知道是什麼意思
// 最後一個 nil 我也不知道是啥意思
reference, err := searchIndex.FindByUuid(ctx, nil, uuid, true, nil)
if reference == nil {
panic("vm not found")
}
vm := object.NewVirtualMachine(c, reference.Reference())
fmt.Println(vm)
}
複製代碼
虛擬機類型和上面相同。固然虛擬機的查找方式確定不止這四種,這裏只列出了經常使用的,有興趣的能夠了解其餘的用法。
經常使用的功能
這裏只是簡單的列出了一些經常使用的功能,有其餘需求的能夠直接查看 govc 的源碼,源碼都還挺容易懂的。
兩種虛擬機類型轉換
第一種查找到的虛擬機類型和後面三種的不同,不一樣的虛擬機類型有不一樣的屬性和方法,所以它們存在轉換的需求。
mo.VirtualMachine*object.VirtualMachine
func vmConv(c *vim25.Client, mvm mo.VirtualMachine) {
vm := object.NewVirtualMachine(c, mvm.Reference())
fmt.Println(vm)
}
複製代碼
mo.VirtualMachine*object.VirtualMachinemo.VirtualMachine
func x(ctx context.Context, vm *object.VirtualMachine, c *vim25.Client) {
var mvm mo.VirtualMachine
pc := property.DefaultCollector(c)
// 若是想要所有屬性,能夠傳一個空的字串切片
err := pc.RetrieveOne(ctx, vm.Reference(), []string{"runtime.host", "config.uuid"}, &mvm)
}
複製代碼
也能這麼作:
func x(ctx context.Context, vm *object.VirtualMachine, c *vim25.Client) {
var o mo.VirtualMachine
if err := vm.Properties(ctx, vm.Reference(), []string{"config.uuid"}, &o); err != nil {
panic(err)
}
}
複製代碼
關機
*object.VirtualMachine
func vmShutdown(ctx context.Context, vm *object.VirtualMachine) {
// 第一個返回值是 task,我認爲不必處理,若是你要處理的話能夠接收後處理
_, err := vm.PowerOff(ctx)
if err != nil {
panic(err)
}
}
複製代碼
刪除
*object.VirtualMachine
func vmDelete(ctx context.Context, vm *object.VirtualMachine) {
// task 能夠處理,也能夠不處理
task, err := vm.Destroy(ctx)
if err != nil {
panic(err)
}
if task.Wait(ctx) != nil {
panic(err)
}
}
複製代碼
斷開虛擬機網卡
這方面比 pyvmomi 更簡單。
func disconnectNic(ctx context.Context, vm *object.VirtualMachine) {
devidelst, err := vm.Device(ctx)
if err != nil {
panic("獲取虛擬機的設備列表失敗," + err.Error())
}
for _, device := range devidelst {
switch device.(type) {
case *types.VirtualVmxnet3:
if devidelst.Disconnect(device) != nil {
panic("斷開網卡鏈接失敗," + err.Error())
}
if vm.EditDevice(p.ctx, device) != nil {
panic("斷開網卡鏈接失敗," + err.Error())
}
}
}
}
複製代碼
更改虛擬機所屬文件夾
將虛擬機移動到另外一個文件夾。
// 先經過目標文件夾來找到其文件夾對象,而後將虛擬機移動到這個對象中
func vmMove(ctx context.Context, destDir string, c *vim25.Client, vm *object.VirtualMachine, searchIndex *object.SearchIndex) {
reference, _ := searchIndex.FindByInventoryPath(ctx, destDir)
if reference == nil {
panic("目標目錄 " + destDir + " 不存在")
}
folder := object.NewFolder(c, reference.Reference())
task, err := folder.MoveInto(ctx, []types.ManagedObjectReference{vm.Reference()})
if err != nil {
panic(err)
}
if err := task.Wait(ctx); err != nil {
panic(err)
}
}
複製代碼
就寫這麼多了,你們有須要的話,能夠直接看 govc 的源碼。