103 lines
2.1 KiB
Go
103 lines
2.1 KiB
Go
package sysinfo
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// App holds CLI state.
|
|
type App struct {
|
|
force bool
|
|
jsonOut bool
|
|
verbose bool
|
|
aptUpdated bool
|
|
cmd *cobra.Command
|
|
}
|
|
|
|
// NewApp configures root command.
|
|
func NewApp() (*App, error) {
|
|
a := &App{}
|
|
root := &cobra.Command{
|
|
Use: "sysinfo",
|
|
Short: "capture block-device / system snapshot",
|
|
Version: Version, // <-- --version flag
|
|
SilenceUsage: true,
|
|
SilenceErrors: true,
|
|
RunE: a.run,
|
|
}
|
|
|
|
root.Flags().BoolVarP(&a.force, "force", "f", false,
|
|
"overwrite /etc/sysinfo if it exists")
|
|
root.Flags().BoolVar(&a.jsonOut, "json", false,
|
|
"emit JSON snapshot to stdout")
|
|
root.Flags().BoolVarP(&a.verbose, "verbose", "v", false,
|
|
"verbose progress")
|
|
_ = viper.BindPFlags(root.Flags())
|
|
|
|
root.AddCommand(&cobra.Command{
|
|
Use: "schema",
|
|
Short: "print the JSON schema",
|
|
Run: func(*cobra.Command, []string) {
|
|
fmt.Fprintln(os.Stdout, JSONSchema)
|
|
},
|
|
})
|
|
|
|
a.cmd = root
|
|
return a, nil
|
|
}
|
|
|
|
func (a *App) Execute() error { return a.cmd.Execute() }
|
|
|
|
func (a *App) logf(f string, v ...any) {
|
|
if a.verbose {
|
|
_, _ = fmt.Fprintf(os.Stderr, f+"\n", v...)
|
|
}
|
|
}
|
|
|
|
// run executes the snapshot workflow.
|
|
func (a *App) run(_ *cobra.Command, _ []string) error {
|
|
if err := a.ensureUbuntu(); err != nil {
|
|
return err
|
|
}
|
|
if err := a.ensureDeps(); err != nil {
|
|
return err
|
|
}
|
|
|
|
ctx := &Context{
|
|
Now: time.Now().UTC(),
|
|
Logf: a.logf,
|
|
Run: a.runCmd,
|
|
SafeRun: a.safeRun,
|
|
SafeRead: a.safeRead,
|
|
}
|
|
|
|
snap := &Snapshot{
|
|
Timestamp: ctx.Now.Format(time.RFC3339),
|
|
Sections: map[string]json.RawMessage{},
|
|
}
|
|
|
|
collectors := []Collector{
|
|
SystemCollector{}, BlockCollector{},
|
|
NetworkCollector{}, SensorsCollector{},
|
|
PackagesCollector{}, ZFSCollector{},
|
|
}
|
|
|
|
for _, c := range collectors {
|
|
raw, err := c.Collect(ctx)
|
|
if err != nil {
|
|
ctx.Logf("%s: %v", c.Key(), err)
|
|
continue
|
|
}
|
|
snap.Sections[c.Key()] = raw
|
|
}
|
|
|
|
if a.jsonOut {
|
|
return a.emitJSON(os.Stdout, snap)
|
|
}
|
|
return a.writeHierarchy(snap)
|
|
}
|