Commit 8a69149
cmd/get/get_smart.go
@@ -0,0 +1,19 @@
+package get
+
+import (
+ "github.com/kahnwong/swissknife/internal/get"
+ "github.com/spf13/cobra"
+)
+
+var getSmartCmd = &cobra.Command{
+ Use: "smart",
+ Short: "Get disk SMART info",
+ Long: "Get disk SMART info. Equivalent of `sudo smartctl -a /dev/nvme0n1p`",
+ Run: func(cmd *cobra.Command, args []string) {
+ get.Smart()
+ },
+}
+
+func init() {
+ Cmd.AddCommand(getSmartCmd)
+}
cmd/root.go
@@ -5,6 +5,8 @@ import (
"github.com/kahnwong/swissknife/cmd/generate"
"github.com/kahnwong/swissknife/cmd/get"
+ "github.com/rs/zerolog"
+ "github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
@@ -27,6 +29,8 @@ func Execute() {
}
func init() {
+ log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
+
rootCmd.AddCommand(get.Cmd)
rootCmd.AddCommand(generate.Cmd)
}
internal/get/ip.go
@@ -15,7 +15,7 @@ type PublicIPResponse struct {
Ip string `json:"ip"`
}
-type IPLocation struct {
+type IPLocationResponse struct {
Ip string `json:"ip"`
Country string `json:"country"`
RegionName string `json:"regionName"`
@@ -56,8 +56,8 @@ func getPublicIP() PublicIPResponse {
return response
}
-func getIPLocation(ip string) IPLocation {
- var response IPLocation
+func getIPLocation(ip string) IPLocationResponse {
+ var response IPLocationResponse
err := requests.
URL(fmt.Sprintf("http://ip-api.com/json/%s", ip)).
ToJSON(&response).
internal/get/smart.go
@@ -0,0 +1,55 @@
+package get
+
+import (
+ "fmt"
+ "runtime"
+
+ "github.com/anatol/smart.go"
+ "github.com/kahnwong/swissknife/configs/color"
+ "github.com/rs/zerolog/log"
+ "github.com/shirou/gopsutil/v4/disk"
+)
+
+func Smart() {
+ if runtime.GOOS == "linux" {
+ device := getRootDiskVolume()
+
+ isNvme := true
+ dev, err := smart.OpenNVMe(device)
+ if err != nil {
+ log.Fatal().Err(err).Msgf("Failed to open %s device. You probaby have to run as sudo", device)
+ }
+ defer func(dev smart.Device) {
+ err = dev.Close()
+ if err != nil {
+ log.Fatal().Err(err).Msgf("Failed to close %s device", device)
+ }
+ }(dev)
+
+ if isNvme {
+ sm, err := dev.ReadSMART()
+ if err != nil {
+ log.Fatal().Msg("Failed to read SMART info")
+ }
+ fmt.Printf("%s: %v\n", color.Green("Percent Used"), sm.PercentUsed)
+ }
+ } else {
+ log.Error().Msgf("%s is not supported\n", runtime.GOOS)
+ }
+}
+
+func getRootDiskVolume() string {
+ partitions, err := disk.Partitions(false)
+ if err != nil {
+ log.Fatal().Msg("Failed to get disk partitions")
+ }
+
+ var volume string
+ for _, partition := range partitions {
+ if partition.Mountpoint == "/" {
+ volume = partition.Device
+ }
+ }
+
+ return volume
+}
go.mod
@@ -3,6 +3,7 @@ module github.com/kahnwong/swissknife
go 1.25.1
require (
+ github.com/anatol/smart.go v0.0.0-20241126061019-f03d79b340d2
github.com/atotto/clipboard v0.1.4
github.com/carlmjohnson/requests v0.25.1
github.com/charmbracelet/bubbles v0.21.0
go.sum
@@ -1,3 +1,7 @@
+github.com/anatol/smart.go v0.0.0-20241126061019-f03d79b340d2 h1:ha5+W2OHFJOEY4uTne98HGD9vQltSYtdyzNCbyhp7rY=
+github.com/anatol/smart.go v0.0.0-20241126061019-f03d79b340d2/go.mod h1:NoOw2eVExhZPtVxpYJzEvdRc5OSbCQZJT2vSe3dflPg=
+github.com/anatol/vmtest v0.0.0-20230711210602-87511df0d4bc h1:xMQuzBhj6hXQZufedPQM2OiGX2UcQHSptXtG3+28S8Q=
+github.com/anatol/vmtest v0.0.0-20230711210602-87511df0d4bc/go.mod h1:NC+g66bgkUjV1unIJXhHO35RHxVViWUzNeeKAkkO7DU=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -51,6 +55,8 @@ github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jedib0t/go-pretty/v6 v6.6.8 h1:JnnzQeRz2bACBobIaa/r+nqjvws4yEhcmaZ4n1QzsEc=
github.com/jedib0t/go-pretty/v6 v6.6.8/go.mod h1:YwC5CE4fJ1HFUDeivSV1r//AmANFHyqczZk+U6BDALU=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
+github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -107,6 +113,8 @@ github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8O
github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
+github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef h1:7D6Nm4D6f0ci9yttWaKjM1TMAXrH5Su72dojqYGntFY=
+github.com/tmc/scp v0.0.0-20170824174625-f7b48647feef/go.mod h1:WLFStEdnJXpjK8kd4qKLwQKX/1vrDzp5BcDyiZJBHJM=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=