implement function watch dog
This commit is contained in:
parent
cf5b63a189
commit
932d49edb1
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,3 +22,5 @@
|
||||
go.work
|
||||
|
||||
.idea
|
||||
|
||||
config.yaml
|
||||
|
35
cmd/watchdog/config.go
Executable file
35
cmd/watchdog/config.go
Executable 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
92
cmd/watchdog/main.go
Executable 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
15
go.mod
@ -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
21
go.sum
Executable 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
23
vmomi/connector.go
Executable 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
36
vmomi/utils.go
Executable 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
76
vmomi/vm.go
Executable 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user