implement function watch dog

This commit is contained in:
tursom 2023-07-04 16:36:42 +08:00
parent cf5b63a189
commit 932d49edb1
8 changed files with 299 additions and 1 deletions

2
.gitignore vendored
View File

@ -22,3 +22,5 @@
go.work
.idea
config.yaml

35
cmd/watchdog/config.go Executable file
View File

@ -0,0 +1,35 @@
package main
import (
"io"
"os"
"gopkg.in/yaml.v3"
)
type (
config struct {
User string `yaml:"user"`
Password string `yaml:"password"`
Watch []*watchVm `yaml:"watch"`
}
watchVm struct {
Name string `yaml:"name"`
Addr string `yaml:"addr"`
}
)
func parseConfig(file string) (*config, error) {
cfgFile, err := os.Open(file)
if err != nil {
return nil, err
}
cfgBytes, err := io.ReadAll(cfgFile)
if err != nil {
return nil, err
}
var cfg config
return &cfg, yaml.Unmarshal(cfgBytes, &cfg)
}

92
cmd/watchdog/main.go Executable file
View File

@ -0,0 +1,92 @@
package main
import (
"context"
"fmt"
"os"
"time"
"github.com/go-ping/ping"
_ "github.com/go-ping/ping"
"github.com/tursom/esxi-monitor/vmomi"
)
func main() {
cfg, err := parseConfig("config.yaml")
if err != nil {
panic(err)
}
watchTargets := make(map[string]*watchVm)
for _, watch := range cfg.Watch {
watchTargets[watch.Name] = watch
}
client, err := vmomi.Connect("https://esxi/sdk", cfg.User, cfg.Password)
if err != nil {
panic(err)
}
vms, err := vmomi.ListVms(client.Client)
if err != nil {
panic(err)
}
// ip -> vm instance
watches := make(map[string]*vmomi.VirtualMachine)
for _, vm := range vms {
target, contains := watchTargets[vm.Name()]
if !contains {
continue
}
fmt.Printf("watching virtual machine: addr=%s, name=%s\n", target.Addr, vm.Name())
watches[target.Addr] = vm
}
doWatch(watches)
}
// watches map ip -> vm instance
func doWatch(watches map[string]*vmomi.VirtualMachine) {
t := time.NewTicker(time.Minute)
for {
<-t.C
for ip, vm := range watches {
pinger, err := ping.NewPinger(ip)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ping to target failed: %s\n", err)
continue
}
pinger.Count = 4
err = pinger.Run()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "ping to target failed: %s\n", err)
continue
}
statistics := pinger.Statistics()
if statistics.PacketsRecv == 0 {
fmt.Printf("restarting vm %s(%s)", ip, vm.Name())
task, err := vm.Reset()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "restart vm failed: %s\n", err)
continue
}
ctx, _ := context.WithTimeout(context.Background(), time.Minute)
err = task.Wait(ctx)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "restart vm failed: %s\n", err)
continue
}
}
}
}
}

15
go.mod
View File

@ -1,3 +1,16 @@
module esxi-monitor
module github.com/tursom/esxi-monitor
go 1.20
require (
github.com/go-ping/ping v1.1.0
github.com/vmware/govmomi v0.30.5
gopkg.in/yaml.v3 v3.0.1
)
require (
github.com/google/uuid v1.3.0 // indirect
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005 // indirect
)

21
go.sum Executable file
View File

@ -0,0 +1,21 @@
github.com/go-ping/ping v1.1.0 h1:3MCGhVX4fyEUuhsfwPrsEdQw6xspHkv5zHsiSoDFZYw=
github.com/go-ping/ping v1.1.0/go.mod h1:xIFjORFzTxqIV/tDVGO4eDy/bLuSyawEeojSm3GfRGk=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/vmware/govmomi v0.30.5 h1:p4sFypY4AJlFRiS2OFEGh9DCzufBrexbtPL5DB9Pxw0=
github.com/vmware/govmomi v0.30.5/go.mod h1:F7adsVewLNHsW/IIm7ziFURaXDaHEwcc+ym4r3INMdY=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 h1:b0LrWgu8+q7z4J+0Y3Umo5q1dL7NXBkKBWkaVkAq17E=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005 h1:pDMpM2zh2MT0kHy037cKlSby2nEhD50SYqwQk76Nm40=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

23
vmomi/connector.go Executable file
View File

@ -0,0 +1,23 @@
package vmomi
import (
"context"
url2 "net/url"
"github.com/vmware/govmomi"
)
func Connect(url, user, password string) (*govmomi.Client, error) {
esxiUri, err := url2.Parse(url)
if err != nil {
panic(err)
}
esxiUri.User = url2.UserPassword(user, password)
return govmomi.NewClient(
context.Background(),
esxiUri,
true,
)
}

36
vmomi/utils.go Executable file
View File

@ -0,0 +1,36 @@
package vmomi
import (
"context"
"github.com/vmware/govmomi/view"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
)
func ListVms(client *vim25.Client) ([]*VirtualMachine, error) {
manager := view.NewManager(client)
v, err := manager.CreateContainerView(
context.Background(),
client.ServiceContent.RootFolder,
[]string{"VirtualMachine"},
true,
)
if err != nil {
return nil, err
}
var vms []mo.VirtualMachine
err = v.Retrieve(context.Background(), []string{"VirtualMachine"}, []string{}, &vms)
if err != nil {
return nil, err
}
var dist []*VirtualMachine
for i := range vms {
dist = append(dist, makeVirtualMachine(client, (*MoVirtualMachine)(&vms[i])))
}
return dist, nil
}

76
vmomi/vm.go Executable file
View File

@ -0,0 +1,76 @@
package vmomi
import (
"context"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
)
type (
MoVirtualMachine mo.VirtualMachine
ObjectVirtualMachine object.VirtualMachine
VirtualMachine struct {
c *vim25.Client
mvm *MoVirtualMachine
ovm *ObjectVirtualMachine
}
)
func makeVirtualMachine(c *vim25.Client, vm *MoVirtualMachine) *VirtualMachine {
return &VirtualMachine{
c: c,
mvm: vm,
ovm: vm.GetOvm(c),
}
}
func (v *VirtualMachine) Ovm() *ObjectVirtualMachine {
return v.ovm
}
func (v *VirtualMachine) Mvm() *MoVirtualMachine {
return v.mvm
}
func (v *VirtualMachine) Name() string {
return v.mvm.Summary.Config.Name
}
func (v *VirtualMachine) Uuid() string {
return v.mvm.Summary.Config.Uuid
}
func (v *VirtualMachine) PowerOn() (*object.Task, error) {
return v.ovm.GetOvm().PowerOn(context.Background())
}
func (v *VirtualMachine) PowerOff() (*object.Task, error) {
return v.ovm.GetOvm().PowerOff(context.Background())
}
func (v *VirtualMachine) Reset() (*object.Task, error) {
return v.ovm.GetOvm().Reset(context.Background())
}
func (vm *MoVirtualMachine) GetMvm() *mo.VirtualMachine {
return (*mo.VirtualMachine)(vm)
}
func (vm *MoVirtualMachine) GetOvm(c *vim25.Client) *ObjectVirtualMachine {
return (*ObjectVirtualMachine)(object.NewVirtualMachine(c, vm.Reference()))
}
func (ovm *ObjectVirtualMachine) GetOvm() *object.VirtualMachine {
return (*object.VirtualMachine)(ovm)
}
func (ovm *ObjectVirtualMachine) GetMvm(c *vim25.Client) (*MoVirtualMachine, error) {
var mvm mo.VirtualMachine
pc := property.DefaultCollector(c)
return (*MoVirtualMachine)(&mvm), pc.RetrieveOne(context.Background(), ovm.Reference(), []string{}, &mvm)
}