gitlab.com/SkynetLabs/skyd@v1.6.9/cmd/skyc/daemoncmd.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 7 "github.com/spf13/cobra" 8 9 "gitlab.com/NebulousLabs/errors" 10 "gitlab.com/SkynetLabs/skyd/build" 11 "go.sia.tech/siad/modules" 12 ) 13 14 var ( 15 alertsCmd = &cobra.Command{ 16 Use: "alerts", 17 Short: "view daemon alerts", 18 Long: "view daemon alerts", 19 Run: wrap(alertscmd), 20 } 21 22 stopCmd = &cobra.Command{ 23 Use: "stop", 24 Short: "Stop the Skynet daemon", 25 Long: "Stop the Skynet daemon.", 26 Run: wrap(stopcmd), 27 } 28 29 globalRatelimitCmd = &cobra.Command{ 30 Use: "ratelimit [maxdownloadspeed] [maxuploadspeed]", 31 Short: "set the global maxdownloadspeed and maxuploadspeed", 32 Long: `Set the global maxdownloadspeed and maxuploadspeed in 33 Bytes per second: B/s, KB/s, MB/s, GB/s, TB/s 34 or 35 Bits per second: Bps, Kbps, Mbps, Gbps, Tbps 36 Set them to 0 for no limit.`, 37 Run: wrap(globalratelimitcmd), 38 } 39 40 profileCmd = &cobra.Command{ 41 Use: "profile", 42 Short: "Start and stop profiles for the daemon", 43 Long: "Start and stop CPU, memory, and/or trace profiles for the daemon", 44 Run: profilecmd, 45 } 46 47 profileStartCmd = &cobra.Command{ 48 Use: "start", 49 Short: "Start the profile for the daemon", 50 Long: `Start a CPU, memory, and/or trace profile for the daemon by using 51 the corresponding flag. Provide a profileDir to save the profiles to. If no 52 profileDir is provided the profiles will be saved in the default profile 53 directory in the siad data directory.`, 54 Run: wrap(profilestartcmd), 55 } 56 57 profileStopCmd = &cobra.Command{ 58 Use: "stop", 59 Short: "Stop profiles for the daemon", 60 Long: "Stop profiles for the daemon", 61 Run: wrap(profilestopcmd), 62 } 63 64 stackCmd = &cobra.Command{ 65 Use: "stack", 66 Short: "Get current stack trace for the daemon", 67 Long: "Get current stack trace for the daemon", 68 Run: wrap(stackcmd), 69 } 70 71 versionCmd = &cobra.Command{ 72 Use: "version", 73 Short: "Print version information", 74 Long: "Print version information.", 75 Run: wrap(versioncmd), 76 } 77 ) 78 79 // alertscmd prints the alerts from the daemon. This will not print critical 80 // alerts as critical alerts are printed on every siac command 81 func alertscmd() { 82 al, err := httpClient.DaemonAlertsGet() 83 if err != nil { 84 fmt.Println("Could not get daemon alerts:", err) 85 return 86 } 87 if len(al.Alerts) == 0 { 88 fmt.Println("There are no alerts registered.") 89 return 90 } 91 if len(al.Alerts) == len(al.CriticalAlerts) { 92 // Return since critical alerts are already displayed 93 return 94 } 95 96 // Print Error alerts 97 const maxAlerts = 1000 98 remainingAlerts := maxAlerts - len(al.CriticalAlerts) 99 if remainingAlerts <= 0 { 100 fmt.Println("Only first", maxAlerts, "alerts printed") 101 return 102 } 103 alertsToPrint := remainingAlerts 104 if alertsToPrint > len(al.ErrorAlerts) { 105 alertsToPrint = len(al.ErrorAlerts) 106 } 107 printAlerts(al.ErrorAlerts[:alertsToPrint], modules.SeverityError) 108 109 // Print Warning alerts 110 remainingAlerts -= len(al.ErrorAlerts) 111 if remainingAlerts <= 0 { 112 fmt.Println("Only first", maxAlerts, "alerts printed") 113 return 114 } 115 alertsToPrint = remainingAlerts 116 if alertsToPrint > len(al.WarningAlerts) { 117 alertsToPrint = len(al.WarningAlerts) 118 } 119 printAlerts(al.WarningAlerts[:alertsToPrint], modules.SeverityWarning) 120 121 // Print max alerts message 122 if len(al.CriticalAlerts)+len(al.ErrorAlerts)+len(al.WarningAlerts) > maxAlerts { 123 fmt.Println("Only first", maxAlerts, "alerts printed") 124 } 125 } 126 127 // profilecmd displays the usage info for the command. 128 func profilecmd(cmd *cobra.Command, args []string) { 129 _ = cmd.UsageFunc()(cmd) 130 os.Exit(exitCodeUsage) 131 } 132 133 // profilestartcmd starts the profile for the daemon. 134 func profilestartcmd() { 135 var profileFlags string 136 if daemonCPUProfile { 137 profileFlags += "c" 138 } 139 if daemonMemoryProfile { 140 profileFlags += "m" 141 } 142 if daemonTraceProfile { 143 profileFlags += "t" 144 } 145 if profileFlags == "" { 146 die("no profiles submitted") 147 } 148 err := httpClient.DaemonStartProfilePost(profileFlags, daemonProfileDirectory) 149 if err != nil { 150 die(err) 151 } 152 fmt.Println("Profile Started!") 153 } 154 155 // profilestopcmd stops the profile for the daemon. 156 func profilestopcmd() { 157 err := httpClient.DaemonStopProfilePost() 158 if err != nil { 159 die(err) 160 } 161 fmt.Println("Profile Stopped") 162 } 163 164 // version prints the version of siac and siad. 165 func versioncmd() { 166 fmt.Println("Skynet Client") 167 if build.ReleaseTag == "" { 168 fmt.Println("\tVersion " + build.NodeVersion) 169 } else { 170 fmt.Println("\tVersion " + build.NodeVersion + "-" + build.ReleaseTag) 171 } 172 if build.GitRevision != "" { 173 fmt.Println("\tGit Revision " + build.GitRevision) 174 fmt.Println("\tBuild Time " + build.BuildTime) 175 } 176 dvg, err := httpClient.DaemonVersionGet() 177 if err != nil { 178 fmt.Println("Could not get daemon version:", err) 179 return 180 } 181 fmt.Println("Skynet daemon") 182 fmt.Println("\tVersion " + dvg.Version) 183 if build.GitRevision != "" { 184 fmt.Println("\tGit Revision " + dvg.GitRevision) 185 fmt.Println("\tBuild Time " + dvg.BuildTime) 186 } 187 } 188 189 // stopcmd is the handler for the command `skyc stop`. 190 // Stops the daemon. 191 func stopcmd() { 192 err := httpClient.DaemonStopGet() 193 if err != nil { 194 die("Could not stop daemon:", err) 195 } 196 fmt.Println("Skynet daemon stopped.") 197 } 198 199 // stackcmd is the handler for the command `skyc stack` and writes the current 200 // stack trace to an output file. 201 func stackcmd() { 202 // Get the stack trace 203 dsg, err := httpClient.DaemonStackGet() 204 if err != nil { 205 die("Could not get the stack:", err) 206 } 207 fmt.Println(dsg.Stack) 208 // Create output file 209 f, err := os.Create(daemonStackOutputFile) 210 if err != nil { 211 die("Unable to create output file:", err) 212 } 213 defer func() { 214 if err := f.Close(); err != nil { 215 die(err) 216 } 217 }() 218 219 // Write stack trace to output file 220 _, err = f.Write([]byte(dsg.Stack)) 221 if err != nil { 222 die("Unable to write to output file:", err) 223 } 224 225 fmt.Println("Current stack trace written to:", daemonStackOutputFile) 226 } 227 228 // globalratelimitcmd is the handler for the command `skyc ratelimit`. 229 // Sets the global maxuploadspeed and maxdownloadspeed the daemon can use. 230 func globalratelimitcmd(downloadSpeedStr, uploadSpeedStr string) { 231 downloadSpeedInt, err := parseRatelimit(downloadSpeedStr) 232 if err != nil { 233 die(errors.AddContext(err, "unable to parse download speed")) 234 } 235 uploadSpeedInt, err := parseRatelimit(uploadSpeedStr) 236 if err != nil { 237 die(errors.AddContext(err, "unable to parse upload speed")) 238 } 239 err = httpClient.DaemonGlobalRateLimitPost(downloadSpeedInt, uploadSpeedInt) 240 if err != nil { 241 die("Could not set global ratelimit speed:", err) 242 } 243 fmt.Println("Set global maxdownloadspeed to ", downloadSpeedInt, " and maxuploadspeed to ", uploadSpeedInt) 244 } 245 246 // printAlerts is a helper function to print details of a slice of alerts 247 // with given severity description to command line 248 func printAlerts(alerts []modules.Alert, as modules.AlertSeverity) { 249 fmt.Printf("\n There are %v %s alerts\n", len(alerts), as.String()) 250 for _, a := range alerts { 251 fmt.Printf(` 252 ------------------ 253 Module: %s 254 Severity: %s 255 Message: %s 256 Cause: %s`, a.Module, a.Severity.String(), a.Msg, a.Cause) 257 } 258 fmt.Printf("\n------------------\n\n") 259 }