-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
618 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,4 @@ go.work.sum | |
|
||
# env file | ||
.env | ||
ublue-upd |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
package checks | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/godbus/dbus/v5" | ||
"github.com/shirou/gopsutil/v4/load" | ||
"github.com/shirou/gopsutil/v4/mem" | ||
) | ||
|
||
type Info struct { | ||
Name string | ||
Err error | ||
} | ||
|
||
func Hardware(conn *dbus.Conn) []Info { | ||
var checks []Info | ||
checks = append(checks, battery(conn)) | ||
checks = append(checks, network(conn)) | ||
checks = append(checks, cpu()) | ||
checks = append(checks, memory()) | ||
|
||
return checks | ||
} | ||
|
||
func battery(conn *dbus.Conn) Info { | ||
const name string = "Battery" | ||
upower := conn.Object("org.freedesktop.UPower", "/org/freedesktop/UPower") | ||
// first, check if the device is running on battery | ||
variant, err := upower.GetProperty("org.freedesktop.UPower.OnBattery") | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
|
||
onBattery, ok := variant.Value().(bool) | ||
if !ok { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Unable to determine if this computer is running on battery with: %v", variant), | ||
} | ||
} | ||
// Not running on battery, skip this test | ||
if !onBattery { | ||
return Info{ | ||
name, | ||
nil, | ||
} | ||
} | ||
|
||
dev := conn.Object("org.freedesktop.UPower", "/org/freedesktop/UPower/devices/DisplayDevice") | ||
variant, err = dev.GetProperty("org.freedesktop.UPower.Device.Percentage") | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
|
||
batteryPercent, ok := variant.Value().(float64) | ||
|
||
if !ok { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Unable to get battery percent from: %v", variant), | ||
} | ||
} | ||
if batteryPercent < 20 { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Battery percent below 20, detected battery percent: %v", batteryPercent), | ||
} | ||
} | ||
|
||
return Info{ | ||
name, | ||
nil, | ||
} | ||
} | ||
|
||
func network(conn *dbus.Conn) Info { | ||
const name string = "Network" | ||
|
||
nm := conn.Object("org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager") | ||
|
||
variant, err := nm.GetProperty("org.freedesktop.NetworkManager.Metered") | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
metered, ok := variant.Value().(uint32) | ||
if !ok { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Unable to determine if network connection is metered from: %v", variant), | ||
} | ||
} | ||
// The possible values of "Metered" are documented here: | ||
// https://networkmanager.dev/docs/api/latest/nm-dbus-types.html//NMMetered | ||
// | ||
// NM_METERED_UNKNOWN = 0 // The metered status is unknown | ||
// NM_METERED_YES = 1 // Metered, the value was explicitly configured | ||
// NM_METERED_NO = 2 // Not metered, the value was explicitly configured | ||
// NM_METERED_GUESS_YES = 3 // Metered, the value was guessed | ||
// NM_METERED_GUESS_NO = 4 // Not metered, the value was guessed | ||
// | ||
if metered == 1 || metered == 3 { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Network is metered"), | ||
} | ||
} | ||
|
||
// check if user is connected to network | ||
var connectivity uint32 | ||
err = nm.Call("org.freedesktop.NetworkManager.CheckConnectivity", 0).Store(&connectivity) | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
|
||
// 4 means fully connected: https://networkmanager.dev/docs/api/latest/nm-dbus-types.html#NMConnectivityState | ||
if connectivity != 4 { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Network not online"), | ||
} | ||
} | ||
|
||
return Info{ | ||
name, | ||
nil, | ||
} | ||
|
||
} | ||
|
||
func memory() Info { | ||
const name string = "Memory" | ||
v, err := mem.VirtualMemory() | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
if v.UsedPercent > 90.0 { | ||
return Info{ | ||
name, | ||
fmt.Errorf("Current memory usage above 90 percent: %v", v.UsedPercent), | ||
} | ||
} | ||
return Info{ | ||
name, | ||
nil, | ||
} | ||
} | ||
|
||
func cpu() Info { | ||
const name string = "CPU" | ||
avg, err := load.Avg() | ||
if err != nil { | ||
return Info{ | ||
name, | ||
err, | ||
} | ||
} | ||
// Check if the CPU load in the 5 minutes was greater than 50% | ||
if avg.Load5 > 50.0 { | ||
return Info{ | ||
name, | ||
fmt.Errorf("CPU load above 50 percent: %v", avg.Load5), | ||
} | ||
} | ||
|
||
return Info{ | ||
name, | ||
nil, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package cmd | ||
|
||
import ( | ||
"log" | ||
|
||
"github.com/gerblesh/update-next/checks" | ||
"github.com/godbus/dbus/v5" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func HwCheck(cmd *cobra.Command, args []string) { | ||
// (some hardware checks require dbus access) | ||
conn, err := dbus.SystemBus() | ||
if err != nil { | ||
log.Fatalf("Failed to connect to session bus: %v", err) | ||
} | ||
defer conn.Close() | ||
checkInfo := checks.Hardware(conn) | ||
for _, info := range checkInfo { | ||
if info.Err != nil { | ||
log.Fatalf("Hardware checks failed for %s, returned error: %v", info.Name, info.Err) | ||
} | ||
} | ||
log.Println("Hardware checks passed") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"github.com/spf13/cobra" | ||
"os" | ||
) | ||
|
||
var ( | ||
rootCmd = &cobra.Command{ | ||
Use: "ublue-upd", | ||
Short: "ublue-upd is the successor to ublue-update, built for bootc", | ||
Run: Update, | ||
} | ||
|
||
waitCmd = &cobra.Command{ | ||
Use: "wait", | ||
Short: "Wait for a condition or time period", | ||
Long: "This command simulates waiting for some event or process to complete.", | ||
Run: Wait, | ||
} | ||
|
||
updateCheckCmd = &cobra.Command{ | ||
Use: "update-check", | ||
Short: "Check for updates to the booted image", | ||
Run: UpdateCheck, | ||
} | ||
|
||
hardwareCheckCmd = &cobra.Command{ | ||
Use: "hw-check", | ||
Short: "Run hardware checks", | ||
Run: HwCheck, | ||
} | ||
) | ||
|
||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Fprintln(os.Stderr, err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(waitCmd) | ||
rootCmd.AddCommand(updateCheckCmd) | ||
rootCmd.AddCommand(hardwareCheckCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/gerblesh/update-next/checks" | ||
"github.com/gerblesh/update-next/drv" | ||
"github.com/gerblesh/update-next/lib" | ||
"github.com/godbus/dbus/v5" | ||
// "github.com/schollz/progressbar/v3" | ||
"github.com/spf13/cobra" | ||
"log" | ||
) | ||
|
||
func Update(cmd *cobra.Command, args []string) { | ||
|
||
// (some hardware checks require dbus access) | ||
conn, err := dbus.SystemBus() | ||
if err != nil { | ||
log.Fatalf("Failed to connect to session bus: %v", err) | ||
} | ||
defer conn.Close() | ||
checkInfo := checks.Hardware(conn) | ||
for _, info := range checkInfo { | ||
if info.Err != nil { | ||
log.Fatalf("Hardware checks failed for %s, returned error: %v", info.Name, info.Err) | ||
} | ||
} | ||
log.Println("Hardware checks passed") | ||
|
||
updateAvailable, err := drv.CheckForUpdate() | ||
if err != nil { | ||
log.Fatalf("Failed to check for image updates: %v", err) | ||
} | ||
log.Printf("update available: %v", updateAvailable) | ||
if updateAvailable { | ||
err = drv.BootcUpdate() | ||
if err != nil { | ||
log.Fatalf("Failed to update system: %v", err) | ||
} | ||
} | ||
err = drv.BrewUpdate() | ||
if err != nil { | ||
log.Fatalf("Failed to update brew: %v", err) | ||
} | ||
|
||
users, err := lib.ListUsers() | ||
if err != nil { | ||
log.Fatalf("ERROR: %v", err) | ||
} | ||
err = drv.FlatpakUpdate(users) | ||
if err != nil { | ||
log.Fatalf("Failed to update flatpak: %v", err) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package cmd | ||
|
||
import ( | ||
"github.com/gerblesh/update-next/drv" | ||
"github.com/spf13/cobra" | ||
"log" | ||
) | ||
|
||
func UpdateCheck(cmd *cobra.Command, args []string) { | ||
update, err := drv.CheckForUpdate() | ||
if err != nil { | ||
log.Fatalf("Failed to check for updates: %v", err) | ||
} | ||
log.Printf("Update Available: %v", update) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package cmd | ||
|
||
import ( | ||
"log" | ||
"os" | ||
"time" | ||
|
||
"github.com/gerblesh/update-next/lib" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
func Wait(cmd *cobra.Command, args []string) { | ||
// TODO: rely on bootc to do transaction wait | ||
lockFilePath := "/sysroot/ostree/lock" | ||
|
||
for { | ||
|
||
time.Sleep(2 * time.Second) | ||
file, err := os.Open(lockFilePath) | ||
if err != nil { | ||
// file must not exist | ||
break | ||
} | ||
|
||
if lib.IsFileLocked(file) { | ||
file.Close() | ||
log.Printf("Waiting for lockfile: %s", lockFilePath) | ||
} else { | ||
file.Close() | ||
break | ||
} | ||
} | ||
log.Printf("Done Waiting!") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package drv | ||
|
||
import ( | ||
"os/exec" | ||
"strings" | ||
) | ||
|
||
func BootcUpdate() error { | ||
cmd := exec.Command("/usr/bin/bootc", "upgrade") | ||
err := cmd.Run() | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func CheckForUpdate() (bool, error) { | ||
cmd := exec.Command("/usr/bin/bootc", "upgrade", "--check") | ||
out, err := cmd.Output() | ||
if err != nil { | ||
return true, err | ||
} | ||
return !strings.Contains(string(out), "No changes in:"), nil | ||
} |
Oops, something went wrong.