add Installed bool in .proto
Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
parent
11e105ec93
commit
5581a4eb9c
|
@ -0,0 +1,72 @@
|
||||||
|
package zoopb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"go.wit.com/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// init the installed package list
|
||||||
|
func (me *Machine) initPackages() {
|
||||||
|
// Get the list of installed packages for the detected distro
|
||||||
|
newP, err := getPackageList(me.Distro)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print the installed packages and their versions
|
||||||
|
for pkg, version := range newP {
|
||||||
|
new1 := new(Package)
|
||||||
|
new1.Name = pkg
|
||||||
|
new1.Version = version
|
||||||
|
if 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.")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (me *Machine) addNew(name string, version string) bool {
|
||||||
|
new1 := new(Package)
|
||||||
|
new1.Name = name
|
||||||
|
new1.Version = version
|
||||||
|
return me.Packages.Append(new1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (me *Machine) updatePackages() string {
|
||||||
|
// Get the list of installed packages for the detected distro
|
||||||
|
newP, err := getPackageList(me.Distro)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Error:", err)
|
||||||
|
return fmt.Sprintln("getPackageList()", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
me.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)
|
||||||
|
}
|
||||||
|
return footer
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package zoopb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"go.wit.com/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// getPackageList returns the list of installed packages based on the distro
|
||||||
|
func getPackageList(distro string) (map[string]string, error) {
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
|
||||||
|
// Run the appropriate command based on the detected distribution
|
||||||
|
switch distro {
|
||||||
|
case "ubuntu", "debian":
|
||||||
|
return dpkgQuery()
|
||||||
|
case "fedora", "centos", "rhel":
|
||||||
|
cmd = exec.Command("rpm", "-qa")
|
||||||
|
case "arch", "manjaro":
|
||||||
|
cmd = exec.Command("pacman", "-Q")
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported distribution: %s", distro)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Capture the command's output
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error running command: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: Split the output into lines and return
|
||||||
|
lines := strings.Split(string(output), "\n")
|
||||||
|
log.Info("output had", len(lines), "lines")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func dpkgQuery() (map[string]string, error) {
|
||||||
|
// Run the dpkg-query command to list installed packages and versions
|
||||||
|
cmd := exec.Command("dpkg-query", "-W", "-f=${Package} ${Version}\n")
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the command execution
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cmd.Wait()
|
||||||
|
|
||||||
|
// Create a map to store package names and versions
|
||||||
|
installedPackages := make(map[string]string)
|
||||||
|
|
||||||
|
// Use a scanner to read the output of the command line by line
|
||||||
|
scanner := bufio.NewScanner(stdout)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
// Split each line into package name and version
|
||||||
|
parts := strings.SplitN(line, " ", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
packageName := parts[0]
|
||||||
|
version := parts[1]
|
||||||
|
installedPackages[packageName] = version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the map with package names and versions
|
||||||
|
return installedPackages, scanner.Err()
|
||||||
|
}
|
71
config.go
71
config.go
|
@ -24,6 +24,29 @@ func (m *Machines) ConfigSave() error {
|
||||||
configWrite(data)
|
configWrite(data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when running on a single machine, save the file in forge/
|
||||||
|
// as <hostname>.pb
|
||||||
|
// write to ~/.config/forge/ unless ENV{FORGE_HOME} is set
|
||||||
|
func (m *Machine) ConfigSave() error {
|
||||||
|
if os.Getenv("FORGE_HOME") == "" {
|
||||||
|
homeDir, _ := os.UserHomeDir()
|
||||||
|
fullpath := filepath.Join(homeDir, ".config/forge")
|
||||||
|
os.Setenv("FORGE_HOME", fullpath)
|
||||||
|
}
|
||||||
|
data, err := m.Marshal()
|
||||||
|
if err != nil {
|
||||||
|
log.Info("proto.Marshal() failed len", len(data), err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("ConfigSave() proto.Marshal() worked len", len(data))
|
||||||
|
|
||||||
|
hostname, _ := os.Hostname()
|
||||||
|
fname := hostname + ".pb"
|
||||||
|
return m.configWrite(fname, data)
|
||||||
|
}
|
||||||
|
|
||||||
func ConfigSaveRaw(data []byte) error {
|
func ConfigSaveRaw(data []byte) error {
|
||||||
configWrite(data)
|
configWrite(data)
|
||||||
return nil
|
return nil
|
||||||
|
@ -45,6 +68,30 @@ func (m *Machines) ConfigLoad() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Machine) ConfigLoad() error {
|
||||||
|
if m == nil {
|
||||||
|
return errors.New("It's not safe to run ConfigLoad() on a nil ?")
|
||||||
|
}
|
||||||
|
if os.Getenv("FORGE_HOME") == "" {
|
||||||
|
homeDir, _ := os.UserHomeDir()
|
||||||
|
fullpath := filepath.Join(homeDir, ".config/forge")
|
||||||
|
os.Setenv("FORGE_HOME", fullpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
hostname, _ := os.Hostname()
|
||||||
|
fname := hostname + ".pb"
|
||||||
|
|
||||||
|
if data, err := m.loadFile(fname); err == nil {
|
||||||
|
if err = proto.Unmarshal(data, m); err != nil {
|
||||||
|
log.Warn("broken zookeeper.pb config file", fname)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func loadFile(filename string) ([]byte, error) {
|
func loadFile(filename string) ([]byte, error) {
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
p := filepath.Join(homeDir, ".config/zookeeper")
|
p := filepath.Join(homeDir, ".config/zookeeper")
|
||||||
|
@ -57,6 +104,17 @@ func loadFile(filename string) ([]byte, error) {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Machine) loadFile(fname string) ([]byte, error) {
|
||||||
|
fullname := filepath.Join(os.Getenv("FORGE_HOME"), fname)
|
||||||
|
|
||||||
|
data, err := os.ReadFile(fullname)
|
||||||
|
if err != nil {
|
||||||
|
// log.Info("open config file :", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
func configWrite(data []byte) error {
|
func configWrite(data []byte) error {
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
p := filepath.Join(homeDir, ".config/zookeeper")
|
p := filepath.Join(homeDir, ".config/zookeeper")
|
||||||
|
@ -70,3 +128,16 @@ func configWrite(data []byte) error {
|
||||||
cfgfile.Write(data)
|
cfgfile.Write(data)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Machine) configWrite(fname string, data []byte) error {
|
||||||
|
fullname := filepath.Join(os.Getenv("FORGE_HOME"), fname)
|
||||||
|
|
||||||
|
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE, 0666)
|
||||||
|
defer cfgfile.Close()
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("open config file :", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cfgfile.Write(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2024 WIT.COM Inc.
|
||||||
|
|
||||||
|
package zoopb
|
||||||
|
|
||||||
|
// simple stab at making a human readable distro name
|
||||||
|
// this is for displaying in a table in the zookeeper app
|
||||||
|
// it's just so you can easily see what machines in your grid are
|
||||||
|
// doing what
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func initDistro() string {
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "windows":
|
||||||
|
return "windows"
|
||||||
|
case "macos":
|
||||||
|
return "macos"
|
||||||
|
case "linux":
|
||||||
|
// Detect the Linux distribution
|
||||||
|
distro := detectDistro()
|
||||||
|
if distro == "" {
|
||||||
|
fmt.Println("Unable to detect Linux distribution.")
|
||||||
|
distro = "fixme"
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Detected distribution: %s\n", distro)
|
||||||
|
return distro
|
||||||
|
default:
|
||||||
|
return runtime.GOOS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// detectDistro returns the Linux distribution name (if possible)
|
||||||
|
func detectDistro() string {
|
||||||
|
// Check if we're on Linux
|
||||||
|
|
||||||
|
// Try to read /etc/os-release to determine the distro
|
||||||
|
file, err := os.Open("/etc/os-release")
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if strings.HasPrefix(line, "ID=") {
|
||||||
|
parts := strings.SplitN(line, "=", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
return strings.Trim(parts[1], `"`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -12,6 +12,9 @@ message Machine {
|
||||||
string distro = 4;
|
string distro = 4;
|
||||||
Packages packages = 5;
|
Packages packages = 5;
|
||||||
google.protobuf.Timestamp laststamp = 6; // the last time we heard anything from this machine
|
google.protobuf.Timestamp laststamp = 6; // the last time we heard anything from this machine
|
||||||
|
Packages installed = 7; // packages that are installed
|
||||||
|
Packages available = 8; // packages that are available
|
||||||
|
Packages wit = 9; // packages that are available from mirrors.wit.com
|
||||||
}
|
}
|
||||||
|
|
||||||
message Machines {
|
message Machines {
|
||||||
|
|
|
@ -6,9 +6,11 @@ package gitpb;
|
||||||
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
|
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
|
||||||
|
|
||||||
message Package {
|
message Package {
|
||||||
string name = 1;
|
string name = 1; // name: zookeeper-go
|
||||||
string version = 2;
|
string version = 2; // version: 0.0.3
|
||||||
google.protobuf.Timestamp laststamp = 4; // the last time we heard anything from this droplet
|
google.protobuf.Timestamp laststamp = 3; // the last time this package was seen (used to timeout entries)
|
||||||
|
string srcPath = 4; // path to the sources (go.wit.com/apps/zookeeper)
|
||||||
|
bool installed = 5; // installed: true
|
||||||
}
|
}
|
||||||
|
|
||||||
message Packages {
|
message Packages {
|
||||||
|
|
Loading…
Reference in New Issue