Skip to content

Commit

Permalink
feat:[close #78]: Add more info to abroot status command, plus a `-…
Browse files Browse the repository at this point in the history
…-dump`
  • Loading branch information
mirkobrombin committed Aug 18, 2023
1 parent d686b34 commit c87ef96
Show file tree
Hide file tree
Showing 212 changed files with 16,944 additions and 154 deletions.
143 changes: 138 additions & 5 deletions cmd/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ package cmd
*/

import (
"archive/tar"
"compress/gzip"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"

"github.com/google/uuid"
"github.com/vanilla-os/abroot/core"
"github.com/vanilla-os/abroot/settings"
"github.com/vanilla-os/orchid/cmdr"
)

Expand All @@ -38,6 +46,13 @@ func NewStatusCommand() *cmdr.Command {
abroot.Trans("status.jsonFlag"),
false))

cmd.WithBoolFlag(
cmdr.NewBoolFlag(
"dump",
"d",
abroot.Trans("status.dumpFlag"),
false))

cmd.Example = "abroot status"

return cmd
Expand All @@ -54,6 +69,11 @@ func status(cmd *cobra.Command, args []string) error {
return err
}

dumpFlag, err := cmd.Flags().GetBool("dump")
if err != nil {
return err
}

a := core.NewABRootManager()
present, err := a.GetPresent()
if err != nil {
Expand All @@ -65,27 +85,140 @@ func status(cmd *cobra.Command, args []string) error {
return err
}

if jsonFlag {
specs := core.GetPCSpecs()
abImage, err := core.NewABImageFromRoot()
if err != nil {
return err
}

kargs, err := core.KargsRead()
if err != nil {
return err
}

pkgMng := core.NewPackageManager(false)
pkgsAdd, err := pkgMng.GetAddPackages()
if err != nil {
return err
}
pkgsRm, err := pkgMng.GetRemovePackages()
if err != nil {
return err
}

if jsonFlag || dumpFlag {
type status struct {
Present string `json:"present"`
Future string `json:"future"`
Present string `json:"present"`
Future string `json:"future"`
CnfFile string `json:"cnfFile"`
CPU string `json:"cpu"`
GPU []string `json:"gpu"`
Memory string `json:"memory"`
ABImage core.ABImage `json:"abimage"`
Kargs string `json:"kargs"`
PkgsAdd []string `json:"pkgsAdd"`
PkgsRm []string `json:"pkgsRm"`
}

s := status{
Present: present.Label,
Future: future.Label,
CnfFile: settings.CnfFileUsed,
CPU: specs.CPU,
GPU: specs.GPU,
Memory: specs.Memory,
ABImage: *abImage,
Kargs: kargs,
PkgsAdd: pkgsAdd,
PkgsRm: pkgsRm,
}

b, err := json.Marshal(s)
if err != nil {
return err
}

fmt.Println(string(b))
if jsonFlag {
fmt.Println(string(b))
return nil
}

tarballPath := fmt.Sprintf("/tmp/abroot-status-%s.tar.gz", uuid.New().String())
tarballFile, err := os.Create(tarballPath)
if err != nil {
return err
}
defer tarballFile.Close()

gzipWriter := gzip.NewWriter(tarballFile)
defer gzipWriter.Close()

tarWriter := tar.NewWriter(gzipWriter)
defer tarWriter.Close()

tarHeader := &tar.Header{
Name: "status.json",
Mode: 0644,
Size: int64(len(b)),
}
err = tarWriter.WriteHeader(tarHeader)
if err != nil {
return err
}
_, err = tarWriter.Write(b)
if err != nil {
return err
}

err = filepath.Walk("/var/log/", func(path string, info os.FileInfo, err error) error {
if strings.Contains(path, "abroot.log") {
relPath, err := filepath.Rel("/var/log/", path)
if err != nil {
return err
}
tarHeader := &tar.Header{
Name: filepath.Join("logs", relPath),
Mode: 0644,
Size: info.Size(),
}
err = tarWriter.WriteHeader(tarHeader)
if err != nil {
return err
}
logFile, err := os.Open(path)
if err != nil {
return err
}
defer logFile.Close()
_, err = io.Copy(tarWriter, logFile)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return err
}

cmdr.Info.Printf(abroot.Trans("status.dumpMsg"), tarballPath)
return nil
}

cmdr.Info.Printf(abroot.Trans("status.infoMsg"), present.Label, future.Label)
formattedGPU := ""
for _, gpu := range specs.GPU {
formattedGPU += fmt.Sprintf("\n\t\t- %s", gpu)
}

cmdr.Info.Printf(
abroot.Trans("status.infoMsg"),
present.Label, future.Label,
settings.CnfFileUsed,
specs.CPU, formattedGPU, specs.Memory,
abImage.Digest, abImage.Timestamp.Format("2006-01-02 15:04:05"), abImage.Image,
kargs,
strings.Join(pkgsAdd, ", "), strings.Join(pkgsRm, ", "),
)

return nil
}
2 changes: 1 addition & 1 deletion core/kargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ func KargsEdit() (bool, error) {

// Open a temporary file, so editors installed via apx can also be used
PrintVerbose("KargsEdit: Copying kargs file to /tmp")
err = copyFile(KargsPath, KargsTmpFile)
err = CopyFile(KargsPath, KargsTmpFile)
if err != nil {
PrintVerbose("KargsEdit:err(2): " + err.Error())
return false, err
Expand Down
103 changes: 103 additions & 0 deletions core/specs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package core

/* License: GPLv3
Authors:
Mirko Brombin <mirko@fabricators.ltd>
Vanilla OS Contributors <https://github.com/vanilla-os/>
Copyright: 2023
Description:
ABRoot is utility which provides full immutability and
atomicity to a Linux system, by transacting between
two root filesystems. Updates are performed using OCI
images, to ensure that the system is always in a
consistent state.
*/

import (
"fmt"
"os/exec"
"strings"

"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/mem"
)

type PCSpecs struct {
CPU string
GPU []string
Memory string
}

type GPUInfo struct {
Address string
Description string
}

func getCPUInfo() (string, error) {
info, err := cpu.Info()
if err != nil {
return "", err
}
if len(info) == 0 {
return "", fmt.Errorf("CPU information not found")
}
return info[0].ModelName, nil
}

func parseGPUInfo(line string) (string, error) {
parts := strings.SplitN(line, " ", 3)
if len(parts) < 3 {
return "", fmt.Errorf("GPU information not found")
}

parts = strings.SplitN(parts[2], ":", 2)
if len(parts) < 2 {
return "", fmt.Errorf("GPU information not found")
}

return strings.TrimSpace(parts[1]), nil
}

func getGPUInfo() ([]string, error) {
cmd := exec.Command("lspci")
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println("Error getting GPU info:", err)
return nil, err
}

lines := strings.Split(string(output), "\n")

var gpus []string
for _, line := range lines {
if strings.Contains(line, "VGA compatible controller") {
gpu, err := parseGPUInfo(line)
if err != nil {
continue
}
gpus = append(gpus, gpu)
}
}

return gpus, nil
}

func getMemoryInfo() (string, error) {
vm, err := mem.VirtualMemory()
if err != nil {
return "", err
}
return fmt.Sprintf("%d MB", vm.Total/1024/1024), nil
}

func GetPCSpecs() PCSpecs {
cpu, _ := getCPUInfo()
gpu, _ := getGPUInfo()
memory, _ := getMemoryInfo()

return PCSpecs{
CPU: cpu,
GPU: gpu,
Memory: memory,
}
}
54 changes: 27 additions & 27 deletions core/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,33 +70,33 @@ func isLink(path string) bool {
return false
}

// copyFile copies a file from source to dest
func copyFile(source, dest string) error {
PrintVerbose("copyFile: running...")

PrintVerbose("copyFile: Opening source file")
srcFile, err := os.Open(source)
if err != nil {
PrintVerbose("copyFile:err: " + err.Error())
return err
}
defer srcFile.Close()

PrintVerbose("copyFile: Opening destination file")
// CopyFile copies a file from source to dest
func CopyFile(source, dest string) error {
PrintVerbose("CopyFile: running...")

PrintVerbose("CopyFile: Opening source file")
srcFile, err := os.Open(source)
if err != nil {
PrintVerbose("CopyFile:err: " + err.Error())
return err
}
defer srcFile.Close()

PrintVerbose("CopyFile: Opening destination file")
destFile, err := os.OpenFile(dest, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
PrintVerbose("copyFile:err: " + err.Error())
return err
}
defer destFile.Close()

PrintVerbose("copyFile: Performing copy operation")
if _, err := io.Copy(destFile, srcFile); err != nil {
PrintVerbose("copyFile:err: " + err.Error())
return err
}

return nil
if err != nil {
PrintVerbose("CopyFile:err: " + err.Error())
return err
}
defer destFile.Close()

PrintVerbose("CopyFile: Performing copy operation")
if _, err := io.Copy(destFile, srcFile); err != nil {
PrintVerbose("CopyFile:err: " + err.Error())
return err
}

return nil
}

// isDeviceLUKSEncrypted checks whether a device specified by devicePath is a LUKS-encrypted device
Expand All @@ -119,4 +119,4 @@ func isDeviceLUKSEncrypted(devicePath string) (bool, error) {
}

return true, nil
}
}
Loading

0 comments on commit c87ef96

Please sign in to comment.