Compare commits

...

50 Commits

Author SHA1 Message Date
Jeff Carr 687e97ab09 zood upgrade worked for the first time. added Kuma check 2025-03-12 15:34:07 -05:00
Jeff Carr 767380abd0 the forgotten patch 2025-03-12 13:17:19 -05:00
Jeff Carr bb4a6a01df try to fix zood update 2025-03-06 07:54:56 -06:00
Jeff Carr 76c5626d0a trigger apt upgrade 2025-03-06 05:34:25 -06:00
Jeff Carr e85a8ae69f talking with zood again 2025-03-06 05:34:25 -06:00
Jeff Carr 8c7f6c3c1b more gui buttons 2025-03-06 05:34:25 -06:00
Jeff Carr 8edebe18e1 cleaner window code 2025-03-06 05:34:25 -06:00
Jeff Carr f97e2a48c6 1st really awesome table with auto updates 2025-03-06 05:34:25 -06:00
Jeff Carr 40fedc09b4 autogenpb changes 2025-03-05 22:14:21 -06:00
Jeff Carr 53dbe44d38 fixes for 'go vet' 2025-03-05 13:33:04 -06:00
Jeff Carr d214d670ac continue locally now 2025-03-05 12:42:50 -06:00
Jeff Carr b621bba629 testing code 2025-03-05 12:42:50 -06:00
Jeff Carr a57b2875af protobuf update works 2025-03-05 12:42:50 -06:00
Jeff Carr 46f69bee21 rm old code 2025-02-22 14:46:17 -06:00
Jeff Carr c5f840ec2f fixes for go-args 2025-02-22 14:31:08 -06:00
Jeff Carr 7e19f3b9ae rm old code. long live generic protobuf tables 2025-02-22 13:50:27 -06:00
Jeff Carr 49d2653fd4 convert to pb grid 2025-02-22 13:50:27 -06:00
Jeff Carr e9f7b99846 time in a table works 2025-02-20 03:23:14 -06:00
Jeff Carr d667d8c26a attempt a table string func 2025-02-19 17:39:45 -06:00
Jeff Carr 3a42f0f9a5 string rows 2025-02-19 17:39:45 -06:00
Jeff Carr 58ff04ba4d more table tests 2025-02-19 17:39:45 -06:00
Jeff Carr 656f706aa1 testing close window 2025-02-19 17:39:44 -06:00
Jeff Carr b53e71ed9e app works again 2025-02-16 12:05:28 -06:00
Jeff Carr 97f29457db runs and saves config 2025-02-15 12:21:32 -06:00
Jeff Carr 8eed7faa7c try to debug Unmarshal() panic 2025-02-15 12:21:28 -06:00
Jeff Carr 8ad5e77931 show some more details in the table 2025-02-15 07:28:42 -06:00
Jeff Carr d3b6c1725d preliminary table 2025-02-15 07:28:39 -06:00
Jeff Carr 875da60adb adds machines to table 2025-02-15 07:28:36 -06:00
Jeff Carr 25bc18c55f start a table window 2025-02-15 07:28:34 -06:00
Jeff Carr 940d259bbf start a gui 2025-02-15 07:28:30 -06:00
Jeff Carr 6b3651edb7 minor autogenpb api change 2025-02-08 19:01:02 -06:00
Jeff Carr b7368c92fd func name change 2025-02-07 04:41:04 -06:00
Jeff Carr 08bf0f5703 fix build 2025-01-18 15:48:34 -06:00
Jeff Carr d9fa76289d trash git notes 2025-01-18 03:59:25 -06:00
Jeff Carr 53b9ce8a11 Merge branch 'jcarr' of gitea.wit.com:jcarr/zookeeper into jcarr 2025-01-18 03:56:22 -06:00
Jeff Carr 128591a3b9 notsure on this thing. still probably do something else 2024-12-30 04:40:00 -06:00
Jeff Carr cea50e3541 do targets some other way
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-12-30 01:35:32 -06:00
Jeff Carr 95fe5a4eab Merge branch 'jcarr' of gitea.wit.com:jcarr/zookeeper into jcarr 2024-12-29 23:21:46 -06:00
Jeff Carr d62931e46a do targets some other way
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-12-29 23:21:21 -06:00
Jeff Carr 1abcc862fe code is better because of autogenpb 2024-12-04 02:25:46 -06:00
Jeff Carr 5d9eb5add6 runs and reports versions
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-11-24 23:22:52 -06:00
Jeff Carr 4e0dc17202 save config file kinda works
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-11-19 05:44:16 -06:00
Jeff Carr 0ad4ffd0c6 stuff
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-11-18 20:13:22 -06:00
Jeff Carr 82c559e657 apt update triggers
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-11-18 07:49:34 -06:00
Jeff Carr 0b78c1f2d1 add log flags
Signed-off-by: Jeff Carr <jcarr@wit.com>
2024-11-17 23:23:02 -06:00
Jeff Carr 375e4f2117 fixes to the packaging 2024-11-16 04:57:40 -06:00
Jeff Carr c65d006423 ready to package 2024-11-15 21:51:25 -06:00
Jeff Carr 7dd5d6d2b1 sending a machine protobuf 2024-11-15 20:59:23 -06:00
Jeff Carr 141d3024fd zoo daemon sends package list over wire
man. long live google protobuf. It's amazing. This
	thing just sent all 3k of the package info over http in raw
	wire format. I'm sure this isn't neat to anyone young but
	to old hacks like me, it's fucking magic how wonderfully
	advanced the language and codebase is. It just reminds
	you how there are actually beautiful things in the world.
2024-11-15 19:49:48 -06:00
Jeff Carr 9d265e0445 zood connects 2024-11-15 19:24:57 -06:00
16 changed files with 688 additions and 137 deletions

View File

@ -7,12 +7,24 @@ BUILDTIME = $(shell date +%Y.%m.%d_%H%M)
# REDOMOD = $(shell if [ -e go.mod ]; then echo go.mod; else echo no go mod; fi) # REDOMOD = $(shell if [ -e go.mod ]; then echo go.mod; else echo no go mod; fi)
REDOMOD = $(shell if [ -e go.sum ]; then echo go.sum exists; else GO111MODULE= go mod init; GO111MODULE= go mod tidy; fi) REDOMOD = $(shell if [ -e go.sum ]; then echo go.sum exists; else GO111MODULE= go mod init; GO111MODULE= go mod tidy; fi)
all: build all: goimports gocui-debugging
#./zookeeper # ./zookeeper
./zookeeper --version
build: vet:
GO111MODULE=off go build \ @GO111MODULE=off go vet
@echo this go binary package builds okay
nogui:
./zookeeper --gui nocui
gocui: build
./zookeeper --gui gocui
gocui-debugging: build
./zookeeper --gui gocui --gui-file ~/go/src/go.wit.com/toolkits/gocui/gocui.so >/tmp/forge.log 2>&1
build: goimports vet
GO111MODULE=off go build -v -x \
-ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}" -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
install: install:
@ -26,7 +38,7 @@ release-build:
# makes a .deb package # makes a .deb package
debian: debian:
go-deb --no-gui --repo go.wit.com/apps/zookeeper go-deb --auto --repo go.wit.com/apps/zookeeper
goimports: goimports:
goimports -w *.go goimports -w *.go
@ -39,11 +51,18 @@ redomod:
clean: clean:
rm -f go.* rm -f go.*
rm -f zookeeper rm -f zookeeper
go-mod-clean --purge
# git clone the sources and all the golang dependancies into ~/go/src # git clone the sources and all the golang dependancies into ~/go/src
# if you don't have go-clone, you can get it from http://go.wit.com/ # if you don't have go-clone, you can get it from http://go.wit.com/
git-clone: git-clone:
go-clone --recursive go.wit.com/apps/zookeeper go-clone --recursive go.wit.com/apps/zookeeper
http-list-packages: http-toogle-ZOOD:
curl --silent http://localhost:2521/list?hostname=zookeeper.wit.com curl --silent http://localhost:8080/flag?flag=ZOOD
http-list-machines:
curl --silent http://localhost:8080/list
http-uptime:
curl --silent http://localhost:8080/uptime

47
apt.go
View File

@ -1,3 +1,6 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
import ( import (
@ -21,53 +24,15 @@ func initPackages() {
new1 := new(zoopb.Package) new1 := new(zoopb.Package)
new1.Name = pkg new1.Name = pkg
new1.Version = version new1.Version = version
if me.packages.Append(new1) { me.packages.Append(new1)
// log.Info("added", new1.Name, "ok")
} else {
log.Info("added", new1.Name, "failed")
}
} }
log.Info(me.hostname, "has distro", me.distro, "with", me.packages.Len(), "packages installed") log.Info(me.hostname, "has distro", me.distro, "with", me.packages.Len(), "packages installed")
} }
func addNew(name string, version string) bool { func addNew(name string, version string) {
new1 := new(zoopb.Package) new1 := new(zoopb.Package)
new1.Name = name new1.Name = name
new1.Version = version new1.Version = version
return me.packages.Append(new1) me.packages.Append(new1)
}
func updatePackages() {
// Get the list of installed packages for the detected distro
newP, err := getPackageList(me.distro)
if err != nil {
fmt.Println("Error:", err)
return
}
var newCounter, changeCounter int
// Print the installed packages and their versions
for pkg, version := range newP {
found := me.packages.FindByName(pkg)
if found == nil {
log.Info("adding new", pkg, version)
addNew(pkg, version)
newCounter += 1
} else {
found.Version = version
if me.packages.Update(found) {
changeCounter += 1
}
}
}
footer := fmt.Sprintf("%s has distro %s with %d packages installed",me.hostname, me.distro, me.packages.Len())
if changeCounter != 0 {
footer += fmt.Sprintf(" (%d changed)", changeCounter)
}
if newCounter != 0 {
footer += fmt.Sprintf(" (%d new)", newCounter)
}
log.Info(footer)
} }

View File

@ -1,3 +1,6 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
import ( import (

29
argv.go
View File

@ -1,3 +1,6 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
/* /*
@ -6,26 +9,44 @@ package main
*/ */
import ( import (
"go.wit.com/dev/alexflint/arg" "go.wit.com/log"
) )
var argv args var argv args
type args struct { type args struct {
Daemon bool `arg:"--daemon" default:"false" help:"run in daemon mode"` Verbose bool `arg:"--verbose" default:"false" help:"talk more"`
Port int `arg:"--port" default:"2521" help:"port to run on"` Daemon bool `arg:"--daemon" default:"false" help:"run in daemon mode"`
Port int `arg:"--port" default:"8080" help:"port to run on"`
} }
func (args) Version() string { func (args) Version() string {
return "zood " + VERSION + " Built on: " + BUILDTIME return "zookeeper " + VERSION + " Built on: " + BUILDTIME
} }
/*
func init() { func init() {
arg.MustParse(&argv) arg.MustParse(&argv)
} }
*/
func (a args) Description() string { func (a args) Description() string {
return ` return `
this daemon talks to zookeeper this daemon talks to zookeeper
` `
} }
var NOW *log.LogFlag
var INFO *log.LogFlag
var ZOOD *log.LogFlag
var WARN *log.LogFlag
func init() {
full := "go.wit.com/apps/zookeeper"
short := "zookeeper"
NOW = log.NewFlag("NOW", true, full, short, "useful while doing debugging")
INFO = log.NewFlag("INFO", false, full, short, "general zookeeper")
ZOOD = log.NewFlag("ZOOD", false, full, short, "show reporting from zood")
WARN = log.NewFlag("WARN", true, full, short, "bad things")
}

15
control
View File

@ -1,8 +1,15 @@
Source: zood Source: zookeeper-go
Build-Depends: golang Build-Depends: golang
Package: zood Package: zookeeper-go
Conflicts: zookeeper
Breaks: zookeeper
Replaces: zookeeper
Maintainer: Jeff Carr <jcarr@wit.com> Maintainer: Jeff Carr <jcarr@wit.com>
Architecture: amd64 Architecture: amd64
Depends: Depends:
URL: https://go.wit.com/lib/daemons/zood URL: https://go.wit.com/apps/zookeeper
Description: the zookeeper daemon Description: zookeeper for homelab grids
keeps track of things in a grid. Maybe
this is similar to the apache project by
the same name, but in any case, this is
customized for the grid here at WIT

View File

@ -1,4 +1,7 @@
// Copyright 2016 The go-qemu Authors. // Copyright 2016 The go-qemu Authors.
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.

88
doGui.go Normal file
View File

@ -0,0 +1,88 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
// An app to submit patches for the 30 GO GUI repos
import (
"os"
"time"
"go.wit.com/gui"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/protobuf/zoopb"
"go.wit.com/log"
)
// refresh the windows & tables the user has open
func refresh() {
if argv.Verbose {
log.Info("zookeeper scan here")
}
if me.zood != nil {
me.zood.doMachinesUpgradeTable(me.machines)
all := me.machines.All()
for all.Scan() {
m := all.Next()
if me.hostname == m.Hostname {
// this is me! This is the version of zood that should be installed everywhere
v := findVersion(m, "zood")
me.zood.version = v
me.zood.versionL.SetText(v)
}
}
}
}
func doGui() {
me.myGui = gui.New()
me.myGui.InitEmbed(resources)
me.myGui.Default()
win := gadgets.RawBasicWindow("Zookeeper: (inventory your cluster)")
win.Make()
win.Show()
win.Custom = func() {
log.Warn("Main window close")
os.Exit(0)
}
box := win.Box()
vbox := box.NewVerticalBox("BOX2")
group1 := vbox.NewGroup("Zookeeper Settings")
grid := group1.NewGrid("buildOptions", 0, 0)
grid.NewButton("zood versions", func() {
// if the window exists, just toggle it open or closed
if me.zood != nil {
me.zood.Toggle()
return
}
me.zood = makeZoodWin()
})
grid.NewButton("Cluster Events", func() {
log.Info("todo: start a list here!")
})
// sit here forever refreshing the GUI
for {
refresh()
time.Sleep(90 * time.Second)
}
}
func saveMachineState() {
cur := zoopb.NewMachines()
all := me.machines.SortByHostname()
for all.Scan() {
m := all.Next()
log.Info("have machine:", m.Hostname)
cur.Append(m)
}
cur.ConfigSave()
}

105
http.go
View File

@ -1,10 +1,12 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"strings" "strings"
"go.wit.com/log" "go.wit.com/log"
@ -17,70 +19,89 @@ func cleanURL(url string) string {
} }
func okHandler(w http.ResponseWriter, r *http.Request) { func okHandler(w http.ResponseWriter, r *http.Request) {
log.Info("Got URL Path: ", r.URL.Path) // log.Info("Got URL Path: ", r.URL.Path)
route := cleanURL(r.URL.Path) route := cleanURL(r.URL.Path)
domname := r.URL.Query().Get("domain") hostname := r.URL.Query().Get("hostname")
// flag := r.URL.Query().Get("flag")
msg, err := ioutil.ReadAll(r.Body) // Read the body as []byte msg, err := ioutil.ReadAll(r.Body) // Read the body as []byte
if err != nil { if err != nil {
fmt.Fprintln(w, "ReadAll() error =", err) log.Info("ReadAll() error =", err)
return return
} }
log.Info("Got URL msg:", string(msg))
if route == "/" { if route == "/" {
fmt.Fprintln(w, "OK")
return return
} }
// exit the virtigo daemon & have systemd restart it if route == "/machine" {
// this can happen & when it does, access to handleMachine(r, w, hostname, msg)
// to libvirtd will hang (aka: virsh list will hang)
// One way to trigger this is to not properly close
// domain sockets opened from go-qemu/hypervisor
// it's a good idea in any case so leave it here
if route == "/kill" {
log.Warn("KILLED")
fmt.Fprintln(w, "KILLED")
os.Exit(-1)
return return
} }
// curl http://localhost:2520/import?domain=foo.bar.com /*
if route == "/import" { if route == "/status" {
fmt.Fprint(w, "import domain:", domname) var packs *zoopb.Packages
packs = new(zoopb.Packages)
if err := packs.Unmarshal(msg); err != nil {
log.Info("/status proto.Unmarshal() failed on wire message len", len(msg), "from", hostname)
return
}
return log.Info("/status Unmarshal worked with msg len", len(msg), "from", hostname)
} log.Info("/status hostname", hostname, "has", packs.Len(), "packages installed")
fmt.Fprintln(w, "upgrade")
return
}
*/
if route == "/favicon.ico" { // list out the machines and thier version of zood
writeFile(w, "ipv6.png") /*
if route == "/list" {
log.HttpMode(w)
defer log.HttpMode(nil)
loop := me.machines.SortByHostname()
for loop.Scan() {
m := loop.Next()
zood := m.Packages.FindByName("zood")
v := me.targets["zood"] // this is the target version
if zood == nil {
log.Info("machine", m.Hostname, "does not have zood installed")
} else {
log.Info(fmt.Sprintf("zood version %s vs target version %s on machine %s", zood.Version, v, m.Hostname))
}
}
return
}
*/
if route == "/uptime" {
if me.zood == nil {
fmt.Fprintf(w, "BAD zood == nil\n")
return
}
var count int
var bad int
all := me.machines.All()
for all.Scan() {
m := all.Next()
count += 1
if findVersion(m, "zood") != me.zood.version {
bad += 1
}
}
if bad == 0 {
fmt.Fprintf(w, "GOOD machine count=(%d) all machines are version %s\n", count, me.zood.version)
} else {
fmt.Fprintf(w, "BAD machine count=(%d) upgrade=(%d) to %s\n", count, bad, me.zood.version)
}
return return
} }
log.Warn("BAD URL =", route) log.Warn("BAD URL =", route)
} }
func writeFile(w http.ResponseWriter, filename string) {
// fmt.Fprintln(w, "GOT TEST?")
fullname := "resources/" + filename
pfile, err := resources.ReadFile(fullname)
if err != nil {
log.Println("ERROR:", err)
// w.Write(pfile)
return
}
var repohtml string
repohtml = string(pfile)
if filename == "goReference.svg" {
w.Header().Set("Content-Type", "image/svg+xml")
}
fmt.Fprintln(w, repohtml)
log.Println("writeFile() found internal file:", filename)
}
// starts and sits waiting for HTTP requests // starts and sits waiting for HTTP requests
func startHTTP() { func startHTTP() {
http.HandleFunc("/", okHandler) http.HandleFunc("/", okHandler)

83
httpDump.go Normal file
View File

@ -0,0 +1,83 @@
package main
import (
"fmt"
"net/http"
)
func dumpRemoteAddr(r *http.Request) string {
return r.RemoteAddr
}
func dumpUserAgent(r *http.Request) string {
var all string
for param, values := range r.URL.Query() {
for _, value := range values {
all += fmt.Sprint(" Query:", param, value)
}
}
// hostname := r.URL.Query().Get("hostname")
return r.UserAgent() + all
}
func dumpClient(r *http.Request) {
/*
var host, url, proto, addr, agent string
host = r.Host
url = r.URL.String()
proto = r.Proto
addr = r.RemoteAddr
agent = r.UserAgent()
log.Warn(host, proto, addr, url, agent)
fmt.Fprintln(accessf, time.Now(), host, proto, addr, url, agent)
// return
fmt.Fprintln(clientf)
fmt.Fprintln(clientf, time.Now())
// Basic request information
fmt.Fprintln(clientf, "Method:", r.Method)
fmt.Fprintln(clientf, "URL:", r.URL)
fmt.Fprintln(clientf, "Protocol:", r.Proto)
fmt.Fprintln(clientf, "Host:", r.Host)
fmt.Fprintln(clientf, "Remote Address:", r.RemoteAddr)
// Headers
fmt.Fprintln(clientf, "Headers:")
for name, values := range r.Header {
for _, value := range values {
fmt.Fprintln(clientf, "Headers:", name, value)
}
}
// Query parameters
fmt.Fprintln(clientf, "Query Parameters:")
for param, values := range r.URL.Query() {
for _, value := range values {
fmt.Fprintln(clientf, "Query:", param, value)
}
}
// User-Agent
fmt.Fprintln(clientf, "User-Agent:", r.UserAgent())
// Content Length
fmt.Fprintln(clientf, "Content Length:", r.ContentLength)
// Cookies
fmt.Fprintln(clientf, "Cookies:")
for _, cookie := range r.Cookies() {
fmt.Fprintln(clientf, cookie.Name, cookie.Value)
}
// Request Body (if applicable)
if r.Body != nil {
body, err := ioutil.ReadAll(r.Body)
if err == nil {
fmt.Fprintln(clientf, "Body:", string(body))
}
}
*/
}

143
machine.go Normal file
View File

@ -0,0 +1,143 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"fmt"
"net/http"
"strings"
"time"
"go.wit.com/lib/protobuf/zoopb"
"go.wit.com/log"
"google.golang.org/protobuf/types/known/timestamppb"
)
func rawGetHostname(data []byte) *zoopb.Machine {
newm := new(zoopb.Machine)
newm.Unmarshal(data)
return newm
}
func handleMachine(r *http.Request, w http.ResponseWriter, hostname string, data []byte) {
hostname = strings.TrimSpace(hostname)
newm := rawGetHostname(data)
if newm == nil {
log.Info("unmarshal failed on data len =", len(data))
}
if hostname != newm.Hostname {
// log.Info("hostname mismatch", hostname, "vs", newm.Hostname)
hostname = newm.Hostname
}
if hostname == "" {
ua := dumpUserAgent(r)
ra := dumpRemoteAddr(r)
log.Info("hostname is blank even after unmarshal. data len =", len(data), ra, ua, newm.Cpus, newm.Hostname)
return
}
// log.Info("lookoing for", hostname)
m := me.machines.FindByHostname(hostname)
if m == nil {
am := new(zoopb.Machine)
am.Hostname = newm.Hostname
am.Memory = newm.Memory
// me.machines2.Append(am)
me.machines.Append(newm)
log.Info("new machine", am.Hostname, am.Memory)
return
}
ua := dumpUserAgent(r)
ra := dumpRemoteAddr(r)
if m.UserAgent != ua {
log.Info("hostname ua changed len =", len(data), ra, hostname, ua)
m.UserAgent = ua
}
if m.Upgrade {
log.Info(m.Hostname, "was told to upgrade zood")
fmt.Fprintln(w, "apt update")
m.Upgrade = false
} else {
fmt.Fprintln(w, "good")
}
// log.Info("update machine protobuf", hostname)
updateMachine(newm)
}
// someone sent machine 'u' is it new?
// if not, update the record of it
func updateMachine(u *zoopb.Machine) string {
if u == nil {
return "nil"
}
m := me.machines.FindByHostname(u.Hostname)
if m == nil {
log.Info("adding new machine", u.Hostname)
me.machines.Append(u)
if me.zood == nil {
// do nothing. window has not been opened
} else {
me.zood.doMachinesUpgradeTable(me.machines)
}
saveMachineState()
return "new"
}
// log.Info("updating machine", m.Hostname)
// did the # of cpus change?
if m.Cpus != u.Cpus {
m.Cpus = u.Cpus
log.Info("cpus changed to", m.Cpus)
}
// did the memory change?
if m.Memory != u.Memory {
m.Memory = u.Memory
log.Info("memory changed to", m.Memory)
}
// init these if nil
if m.Packages == nil {
m.Packages = new(zoopb.Packages)
}
if u.Packages == nil {
u.Packages = new(zoopb.Packages)
}
if zood := m.Packages.FindByName("zood"); zood != nil {
log.Log(INFO, m.Hostname, "has zood version", zood.Version)
}
m.Laststamp = timestamppb.New(time.Now())
updatePackages(m, u.Packages)
return "upgrade"
}
// looks to see if any packages:
// changed versions
// were newly installed
// were uninstalled
func updatePackages(m *zoopb.Machine, newp *zoopb.Packages) bool {
var changed bool = false
loop := newp.SortByName()
for loop.Scan() {
p := loop.Next()
if p.Name == "zood" {
if pold := m.Packages.FindByName("zood"); pold == nil {
changed = true
log.Log(ZOOD, "updatePackages() new package", p.Name, "version", p.Version, "machine", m.Hostname)
m.Packages.Append(p)
} else {
if p.Version == pold.Version {
log.Log(ZOOD, "updatePackages() unchanged", p.Version, "machine", m.Hostname)
} else {
changed = true
log.Log(NOW, "updatePackages() package", p.Name, "version changed", pold.Version, "to", p.Version, "machine", m.Hostname)
pold.Version = p.Version
}
}
}
}
return changed
}

47
main.go
View File

@ -1,16 +1,5 @@
// Copyright 2016 The go-qemu Authors. // Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// // Use of this source code is governed by the GPL 3.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main package main
@ -20,6 +9,7 @@ import (
"time" "time"
"go.wit.com/dev/alexflint/arg" "go.wit.com/dev/alexflint/arg"
"go.wit.com/gui"
"go.wit.com/lib/protobuf/zoopb" "go.wit.com/lib/protobuf/zoopb"
"go.wit.com/log" "go.wit.com/log"
) )
@ -32,6 +22,7 @@ var resources embed.FS
func main() { func main() {
var pp *arg.Parser var pp *arg.Parser
gui.InitArg()
pp = arg.MustParse(&argv) pp = arg.MustParse(&argv)
if pp == nil { if pp == nil {
@ -44,19 +35,27 @@ func main() {
log.DaemonMode(true) log.DaemonMode(true)
} }
me = new(stuff) me = new(zookeep)
me.zookeeper = "zookeeper.wit.com"
me.hostname, _ = os.Hostname() me.hostname, _ = os.Hostname()
me.pollDelay = 3 * time.Second me.pollDelay = time.Hour
me.machines = zoopb.NewMachines()
// what OS? // me.machines2 = zoopb.NewMachines()
me.distro = initDistro() if err := me.machines.ConfigLoad(); err != nil {
log.Warn("load config failed", err)
// init the installed package list os.Exit(-1)
me.packages = new(zoopb.Packages) }
initPackages() /*
if err := me.machines2.ConfigLoad(); err != nil {
log.Warn("load config failed", err)
os.Exit(-1)
}
*/
// me.targets = make(map[string]string) // keep track of what versions the machines should be running
me.upgrade = make(map[string]bool) // used to trigger upgrade attempts
go NewWatchdog() go NewWatchdog()
startHTTP() go startHTTP()
doGui()
} }

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
set -e set -e
systemctl enable zood.service systemctl enable zookeeper.service
systemctl stop zood.service systemctl stop zookeeper.service
systemctl start zood.service systemctl start zookeeper.service

View File

@ -1,19 +1,33 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
import ( import (
"time" "time"
"go.wit.com/gui"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/protobuf/zoopb" "go.wit.com/lib/protobuf/zoopb"
) )
var me *stuff var me *zookeep
// this app's variables // this app's variables
type stuff struct { type zookeep struct {
hostname string // my hostname to send to zookeeper hostname string // my fqdn dns zookeeper hostname
zookeeper string // the dns name for the zookeeper
pollDelay time.Duration // how often to report our status pollDelay time.Duration // how often to report our status
dog *time.Ticker // the watchdog timer dog *time.Ticker // the watchdog timer
dogchan chan bool // can kill the watchdog
distro string // debian,redhat,gentoo,macos,wincrap distro string // debian,redhat,gentoo,macos,wincrap
packages *zoopb.Packages // installed packages and versions packages *zoopb.Packages // installed packages and versions
machines *zoopb.Machines // every machine that has reported itself to the zookeeper
// machines2 *zoopb.Machines // every machine that has reported itself to the zookeeper
targets map[string]string // what versions the machines should be running
upgrade map[string]bool // use this to trigger builds
myGui *gui.Node // the gui toolkit handle
machinesWin *gadgets.GenericWindow // the machines gui window
machinesBox *gui.Node // the machines gui parent box widget
machinesTB *zoopb.MachinesTable // the machines gui table buffer
zood *stdTableWin // the zood version window
} }

View File

@ -1,3 +1,6 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main package main
import ( import (
@ -14,10 +17,18 @@ func TimeFunction(f func()) time.Duration {
return time.Since(startTime) // Calculate the elapsed time return time.Since(startTime) // Calculate the elapsed time
} }
func shutdownDog() {
// this example would exit/destroy the ticker in 10 seconds
go func() {
time.Sleep(10 * time.Second)
me.dogchan <- true
}()
}
func NewWatchdog() { func NewWatchdog() {
me.dog = time.NewTicker(me.pollDelay) me.dog = time.NewTicker(me.pollDelay)
defer me.dog.Stop() defer me.dog.Stop()
done := make(chan bool) me.dogchan = make(chan bool)
/* /*
// this example would exit/destroy the ticker in 10 seconds // this example would exit/destroy the ticker in 10 seconds
go func() { go func() {
@ -27,12 +38,25 @@ func NewWatchdog() {
*/ */
for { for {
select { select {
case <-done: case <-me.dogchan:
fmt.Println("Done!") fmt.Println("Done!")
return return
case t := <-me.dog.C: case t := <-me.dog.C:
log.Info("Watchdog() ticked", me.zookeeper, "Current time: ", t) // log.Info("zookeeper Watchdog() ticked", me.hostname, "Current time: ", t)
updatePackages() var counter int
loop := me.machines.SortByHostname()
for loop.Scan() {
m := loop.Next()
counter += 1
zood := m.Packages.FindByName("zood")
if zood == nil {
log.Info("machine", m.Hostname, "does not have zood installed")
} else {
// log.Info("know about machine", m.Hostname, "zood version", zood.Version)
}
}
log.Info("hour watchdog:", counter, "machines. Current time:", t)
// h.pollHypervisor() // h.pollHypervisor()
// h.Scan() // h.Scan()
} }

161
windowZood.go Normal file
View File

@ -0,0 +1,161 @@
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
// Use of this source code is governed by the GPL 3.0
package main
import (
"fmt"
"sync"
"time"
"go.wit.com/gui"
"go.wit.com/lib/gadgets"
"go.wit.com/lib/protobuf/zoopb"
"go.wit.com/log"
)
type stdTableWin struct {
sync.Mutex
win *gadgets.GenericWindow // the machines gui window
box *gui.Node // the machines gui parent box widget
TB *zoopb.MachinesTable // the machines gui table buffer
version string // the current zood version
versionL *gui.Node // label widget to display the current zood version
update bool // if the window should be updated
}
func (w *stdTableWin) Toggle() {
if w == nil {
return
}
if w.win == nil {
return
}
w.win.Toggle()
}
func makeZoodWin() *stdTableWin {
zood := new(stdTableWin)
zood.win = gadgets.NewGenericWindow("zood daemon versions", "todo: add global controls here")
zood.win.Custom = func() {
log.Info("test delete window here")
}
grid := zood.win.Group.RawGrid()
grid.NewButton("save machines.pb", func() {
saveMachineState()
})
grid.NewButton("show active", func() {
zood.doMachinesUpgradeTable(me.machines)
})
grid.NewButton("refresh", func() {
refresh()
})
zood.versionL = grid.NewLabel("scan")
grid.NewButton("show out of date", func() {
found := zoopb.NewMachines()
all := me.machines.All()
for all.Scan() {
m := all.Next()
if findVersion(m, "zood") != me.zood.version {
found.Append(m)
}
}
zood.doMachinesUpgradeTable(found)
})
// make a box at the bottom of the window for the protobuf table
zood.box = zood.win.Bottom.Box().SetProgName("TBOX")
zood.doMachinesUpgradeTable(me.machines)
return zood
}
func (zood *stdTableWin) doMachinesUpgradeTable(pb *zoopb.Machines) {
zood.Lock()
defer zood.Unlock()
if zood.TB != nil {
zood.TB.Delete()
zood.TB = nil
}
/*
found := zoopb.NewMachines()
all := pb.SortByHostname()
for all.Scan() {
m := all.Next()
found.Append(m)
}
*/
// display the protobuf
zood.TB = AddMachinesPB(zood.box, pb)
f := func(m *zoopb.Machine) {
log.Info("Triggering machine", m.Hostname, "to upgrade zood")
m.Upgrade = true
}
zood.TB.Custom(f)
log.Info("table has uuid", zood.TB.GetUuid())
}
func AddMachinesPB(tbox *gui.Node, pb *zoopb.Machines) *zoopb.MachinesTable {
t := pb.NewTable("MachinesPB")
t.NewUuid()
t.SetParent(tbox)
upbut := t.AddButtonFunc("upgrade", func(m *zoopb.Machine) string {
if me.zood != nil {
mver := findVersion(m, "zood")
if mver == me.zood.version {
return ""
} else {
// log.Info("machine mismatch", m.Hostname, mver, me.zood.version)
}
}
// log.Info("machine =", m.Hostname)
return "now"
})
upbut.Custom = func(m *zoopb.Machine) {
log.Info("Triggering machine", m.Hostname, "to upgrade zood")
m.Upgrade = true
}
t.AddHostname()
t.AddMemory()
t.AddCpus()
t.AddStringFunc("sMB", func(m *zoopb.Machine) string {
return fmt.Sprintf("%d mb", m.Memory/(1024*1024))
})
t.AddStringFunc("zood", func(m *zoopb.Machine) string {
return findVersion(m, "zood")
})
delf := func(m *zoopb.Machine) string {
return "delete"
}
t.AddButtonFunc("delete", delf)
/*
// show if the machine needs to be upgraded
t.AddStringFunc("triggered?", func(m *zoopb.Machine) string {
if m.Upgrade {
return "yes"
}
return ""
})
*/
t.AddTimeFunc("age", func(m *zoopb.Machine) time.Time {
return m.Laststamp.AsTime()
})
t.ShowTable()
return t
}
func findVersion(m *zoopb.Machine, pkgname string) string {
zood := m.Packages.FindByName(pkgname)
if zood == nil {
return "n/a"
}
return zood.Version
}

View File

@ -1,11 +1,11 @@
[Unit] [Unit]
Description=zood Description=zookeeper
[Service] [Service]
User=root User=root
Type=simple Type=simple
ExecStart=/usr/bin/zood ExecStart=/usr/bin/zookeeper
ExecStop=killall zood ExecStop=killall zookeeper
Restart=on-failure Restart=on-failure
RestartSec=5 RestartSec=5