Skip to content

Commit

Permalink
add output flag for advise (#990)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonhawkharris committed Jun 7, 2023
1 parent 23e8eb2 commit 5a99c9b
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 10 deletions.
16 changes: 9 additions & 7 deletions cmd/src/scout_advise.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import (
"path/filepath"

"github.com/docker/docker/client"
"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/src-cli/internal/scout/advise"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
metricsv "k8s.io/metrics/pkg/client/clientset/versioned"

"github.com/sourcegraph/sourcegraph/lib/errors"
)

func init() {
Expand All @@ -23,17 +24,14 @@ func init() {
Make recommendations for all pods in a kubernetes deployment of Sourcegraph.
$ src scout advise
Make recommendations for all containers in a Docker deployment of Sourcegraph.
$ src scout advise
Make recommendations for specific pod:
$ src scout advise --pod <podname>
Make recommendations for specific container:
$ src scout advise --container <containername>
Add namespace if using namespace in a Kubernetes cluster
$ src scout advise --namespace <namespace>
Output advice to file
$ src scout advise --o path/to/file
`

flagSet := flag.NewFlagSet("advise", flag.ExitOnError)
Expand All @@ -48,6 +46,7 @@ func init() {
namespace = flagSet.String("namespace", "", "(optional) specify the kubernetes namespace to use")
pod = flagSet.String("pod", "", "(optional) specify a single pod")
container = flagSet.String("container", "", "(optional) specify a single container")
output = flagSet.String("o", "", "(optional) output advice to file")
docker = flagSet.Bool("docker", false, "(optional) using docker deployment")
)

Expand Down Expand Up @@ -89,6 +88,9 @@ func init() {
if *pod != "" {
options = append(options, advise.WithPod(*pod))
}
if *output != "" {
options = append(options, advise.WithOutput(*output))
}
if *container != "" || *docker {
if *container != "" {
options = append(options, advise.WithContainer(*container))
Expand Down
6 changes: 6 additions & 0 deletions internal/scout/advise/advise.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,9 @@ func WithContainer(containerName string) Option {
config.Container = containerName
}
}

func WithOutput(pathToFile string) Option {
return func(config *scout.Config) {
config.Output = pathToFile
}
}
38 changes: 35 additions & 3 deletions internal/scout/advise/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package advise
import (
"context"
"fmt"
"os"


"github.com/sourcegraph/sourcegraph/lib/errors"
"github.com/sourcegraph/src-cli/internal/scout"
Expand All @@ -24,6 +26,7 @@ func K8s(
Namespace: "default",
Pod: "",
Container: "",
Output: "",
Spy: false,
Docker: false,
RestConfig: restConfig,
Expand Down Expand Up @@ -64,6 +67,11 @@ func K8s(
return nil
}

// Advise generates resource allocation advice for a Kubernetes pod.
// The function fetches usage metrics for each container in the pod. It then
// checks the usage percentages against thresholds to determine if more or less
// of a resource is needed. Advice is generated and either printed to the console
// or output to a file depending on the cfg.Output field.
func Advise(ctx context.Context, cfg *scout.Config, pod v1.Pod) error {
var advice []string
usageMetrics, err := getUsageMetrics(ctx, cfg, pod)
Expand All @@ -83,15 +91,39 @@ func Advise(ctx context.Context, cfg *scout.Config, pod v1.Pod) error {
advice = append(advice, storageAdvice)
}

fmt.Println(scout.EmojiFingerPointRight, pod.Name)
for _, msg := range advice {
fmt.Println(msg)
if cfg.Output != "" {
outputToFile(ctx, cfg, pod, advice)
} else {
for _, msg := range advice {
fmt.Println(msg)
}
}
}

return nil
}

// outputToFile writes resource allocation advice for a Kubernetes pod to a file.
func outputToFile(ctx context.Context, cfg *scout.Config, pod v1.Pod, advice []string) error {
file, err := os.OpenFile(cfg.Output, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return errors.Wrap(err, "failed to open file")
}
defer file.Close()

if _, err := fmt.Fprintf(file, "- %s\n", pod.Name); err != nil {
return errors.Wrap(err, "failed to write pod name to file")
}

for _, msg := range advice {
if _, err := fmt.Fprintf(file, "%s\n", msg); err != nil {
return errors.Wrap(err, "failed to write container advice to file")
}
}
return nil
}

// getUsageMetrics generates resource usage statistics for containers in a Kubernetes pod.
func getUsageMetrics(ctx context.Context, cfg *scout.Config, pod v1.Pod) ([]scout.UsageStats, error) {
var usages []scout.UsageStats
var usage scout.UsageStats
Expand Down
1 change: 1 addition & 0 deletions internal/scout/types.go