diff --git a/components/gitpod-cli/cmd/top.go b/components/gitpod-cli/cmd/top.go new file mode 100644 index 00000000000000..b1f67faa587396 --- /dev/null +++ b/components/gitpod-cli/cmd/top.go @@ -0,0 +1,70 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package cmd + +import ( + "context" + "fmt" + "log" + "os" + "time" + + supervisor_helper "github.com/gitpod-io/gitpod/gitpod-cli/pkg/supervisor-helper" + supervisor "github.com/gitpod-io/gitpod/supervisor/api" + + "github.com/spf13/cobra" + + "github.com/olekukonko/tablewriter" +) + +func outputTable(workspaceResources *supervisor.ResourcesStatusResponse) { + table := tablewriter.NewWriter(os.Stdout) + table.SetHeader([]string{"CPU (millicores)", "Memory (bytes)"}) + table.SetBorders(tablewriter.Border{Left: true, Top: true, Right: true, Bottom: false}) + table.SetCenterSeparator("|") + + cpuFraction := int64((float64(workspaceResources.Cpu.Used) / float64(workspaceResources.Cpu.Limit)) * 100) + memFraction := int64((float64(workspaceResources.Memory.Used) / float64(workspaceResources.Memory.Limit)) * 100) + cpu := fmt.Sprintf("%dm/%dm (%d%%)", workspaceResources.Cpu.Used, workspaceResources.Cpu.Limit, cpuFraction) + memory := fmt.Sprintf("%dMi/%dMi (%d%%)\n", workspaceResources.Memory.Used/(1024*1024), workspaceResources.Memory.Limit/(1024*1024), memFraction) + + cpuColor := getColor(cpuFraction) + memoryColor := getColor(memFraction) + + table.Rich([]string{cpu, memory}, []tablewriter.Colors{{cpuColor}, {memoryColor}}) + + table.Render() +} + +func getColor(value int64) int { + switch { + case value >= 85: + return tablewriter.FgRedColor + case value >= 65: + return tablewriter.FgYellowColor + default: + return tablewriter.FgHiGreenColor + } +} + +var topCmd = &cobra.Command{ + Use: "top", + Short: "Display workspace resource (CPU and memory usage)", + Run: func(cmd *cobra.Command, args []string) { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + workspaceResources, err := supervisor_helper.GetWorkspaceResources(ctx) + if err != nil { + log.Fatalf("cannot get workspace resources: %s", err) + } + + outputTable(workspaceResources) + }, +} + +func init() { + rootCmd.AddCommand(topCmd) +} diff --git a/components/gitpod-cli/pkg/supervisor-helper/status.go b/components/gitpod-cli/pkg/supervisor-helper/status.go new file mode 100644 index 00000000000000..0612881368e3d9 --- /dev/null +++ b/components/gitpod-cli/pkg/supervisor-helper/status.go @@ -0,0 +1,26 @@ +// Copyright (c) 2022 Gitpod GmbH. All rights reserved. +// Licensed under the GNU Affero General Public License (AGPL). +// See License-AGPL.txt in the project root for license information. + +package supervisor_helper + +import ( + "context" + + supervisor "github.com/gitpod-io/gitpod/supervisor/api" +) + +func GetWorkspaceResources(ctx context.Context) (*supervisor.ResourcesStatusResponse, error) { + conn, err := Dial(ctx) + if err != nil { + return nil, err + } + client := supervisor.NewStatusServiceClient(conn) + workspaceResources, workspaceResourcesError := client.ResourcesStatus(ctx, &supervisor.ResourcesStatuRequest{}) + + if workspaceResourcesError != nil { + return nil, workspaceResourcesError + } + + return workspaceResources, nil +}