Skip to content

Commit

Permalink
feat: initial version of kubectl plugin
Browse files Browse the repository at this point in the history
add an initial version of a kubectl-garm plugin to visualize the pools
in an opinionated manner
  • Loading branch information
bavarianbidi committed Nov 29, 2023
1 parent ad14380 commit 1a97f25
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 0 deletions.
9 changes: 9 additions & 0 deletions cmd/garmctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package main

import "github.com/mercedes-benz/garm-operator/pkg/command"

func main() {
if err := command.RootCommand.Execute(); err != nil {
panic(err)
}
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ require (
github.com/cloudbase/garm-provider-common v0.1.0
github.com/go-openapi/runtime v0.26.0
github.com/go-playground/validator/v10 v10.16.0
github.com/jedib0t/go-pretty/v6 v6.4.6
github.com/knadh/koanf/parsers/yaml v0.1.0
github.com/knadh/koanf/providers/env v0.1.0
github.com/knadh/koanf/providers/file v0.1.0
github.com/knadh/koanf/providers/posflag v0.1.0
github.com/knadh/koanf/v2 v2.0.1
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.16.0
github.com/spf13/cobra v1.6.1
github.com/spf13/pflag v1.0.5
go.uber.org/mock v0.2.0
gopkg.in/yaml.v2 v2.4.0
Expand Down Expand Up @@ -61,11 +63,13 @@ require (
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
Expand All @@ -78,6 +82,7 @@ require (
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
go.mongodb.org/mongo-driver v1.11.3 // indirect
go.opentelemetry.io/otel v1.14.0 // indirect
go.opentelemetry.io/otel/trace v1.14.0 // indirect
Expand Down
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ github.com/cloudbase/garm-provider-common v0.1.0/go.mod h1:igxJRT3OlykERYc6ssdRQ
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down Expand Up @@ -164,6 +165,11 @@ github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jedib0t/go-pretty/v6 v6.4.6 h1:v6aG9h6Uby3IusSSEjHaZNXpHFhzqMmjXcPq1Rjl9Jw=
github.com/jedib0t/go-pretty/v6 v6.4.6/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down Expand Up @@ -207,6 +213,9 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
Expand Down Expand Up @@ -239,6 +248,7 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand All @@ -251,15 +261,21 @@ github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
Expand All @@ -274,6 +290,7 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
Expand Down Expand Up @@ -367,6 +384,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
Expand Down
Binary file added main
Binary file not shown.
14 changes: 14 additions & 0 deletions pkg/command/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package command

import "github.com/spf13/cobra"

var describeCmd = &cobra.Command{
Use: "pools",
Aliases: []string{"pool", "p"},
Short: "analyze and prepare captured traces",
Long: "analyze and prepare previous captured traces for further processing",
}

func init() {
RootCommand.AddCommand(describeCmd)
}
44 changes: 44 additions & 0 deletions pkg/command/kubeclient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package command

import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"

"k8s.io/client-go/kubernetes/scheme"

garmoperatorv1alpha1 "github.com/mercedes-benz/garm-operator/api/v1alpha1"
)

func generateKubeClient() (*dynamic.DynamicClient, error) {

config, err := clientcmd.BuildConfigFromFlags("", opt.kubeConfig)
if err != nil {
return nil, err
}

return dynamic.NewForConfig(config)
// cliSet, err := dynamic.NewForConfig(config)
//if err != nil {
// return nil, err
//}
//
//// add the garm-operator CRD scheme
//garmoperatorv1alpha1.AddToScheme(scheme.Scheme)
//
//return kubernetes.NewForConfig(config)
}

func newRestClient() (*rest.RESTClient, error) {
config, err := clientcmd.BuildConfigFromFlags("", opt.kubeConfig)
if err != nil {
return nil, err
}

config.APIPath = "/apis"
config.ContentConfig.GroupVersion = &garmoperatorv1alpha1.GroupVersion
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
config.UserAgent = rest.DefaultKubernetesUserAgent()

return rest.RESTClientFor(config)
}
128 changes: 128 additions & 0 deletions pkg/command/overview.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package command

import (
"context"
"os"
"slices"

"github.com/spf13/cobra"

"github.com/jedib0t/go-pretty/v6/table"

garmoperatorv1alpha1 "github.com/mercedes-benz/garm-operator/api/v1alpha1"
)

var overviewCmd = &cobra.Command{
Use: "overview",
Aliases: []string{"o"},
Short: "analyze and prepare captured traces",
Long: "analyze and prepare previous captured traces for further processing",
RunE: generateOverview,
}

func init() {
describeCmd.AddCommand(overviewCmd)

describeCmd.PersistentFlags().StringSliceVar(&opt.sortBy, "sort-by", []string{"region", "flavor"}, "sorted")
describeCmd.PersistentFlags().BoolVar(&opt.markdown, "markdown", false, "output as markdown")
}

type providerSummary struct {
name string
flavors []flavor
}

type flavor struct {
name string
maxRunner uint
minRunner uint
}

func generateOverview(cmd *cobra.Command, args []string) error {

kubeClient, err := newRestClient()
if err != nil {
return err
}

poolList := &garmoperatorv1alpha1.PoolList{}
pools := kubeClient.Get().
Namespace("garm-infra-stage-prod").
Resource("pools").
Do(context.Background())

pools.Into(poolList)

summary := []providerSummary{}

for _, pool := range poolList.Items {

providerName := pool.Spec.ProviderName
maxRunners := pool.Spec.MaxRunners
minIdleRunners := pool.Spec.MinIdleRunners

providerIndex := slices.IndexFunc(summary, func(provider providerSummary) bool { return provider.name == providerName })
if providerIndex == -1 {
summary = append(summary, providerSummary{
name: providerName,
flavors: []flavor{
{
name: pool.Spec.Flavor,
maxRunner: pool.Spec.MaxRunners,
minRunner: pool.Spec.MinIdleRunners,
},
},
})
} else {

flavorIndex := slices.IndexFunc(summary[providerIndex].flavors, func(flavor flavor) bool { return flavor.name == pool.Spec.Flavor })
if flavorIndex == -1 {
summary[providerIndex].flavors = append(summary[providerIndex].flavors, flavor{
name: pool.Spec.Flavor,
maxRunner: pool.Spec.MaxRunners,
minRunner: pool.Spec.MinIdleRunners,
})
} else {

summary[providerIndex].flavors[flavorIndex].maxRunner += maxRunners // calculate the runners on top
summary[providerIndex].flavors[flavorIndex].minRunner += minIdleRunners
}
}

}

printOverview(summary)

return nil
}

func printOverview(summary []providerSummary) {

t := table.NewWriter()
t.SetOutputMirror(os.Stdout)
t.AppendHeader(table.Row{"region", "flavor", "max runners", "Min Idle Runners"})

for _, s := range summary {
for _, f := range s.flavors {
t.AppendRow([]interface{}{s.name, f.name, f.maxRunner, f.minRunner})
}
}

if len(opt.sortBy) > 0 {
for _, sortOption := range opt.sortBy {
t.SortBy([]table.SortBy{
{Name: sortOption, Mode: table.Asc},
})
}

}

t.SetStyle(table.StyleColoredBlackOnRedWhite)

if opt.markdown {
t.RenderMarkdown()
} else {
t.Render()
}

}
39 changes: 39 additions & 0 deletions pkg/command/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package command

import (
"github.com/spf13/cobra"
)

type options struct {
kubeConfig string
kubeConfigContext string
namespace string
sortBy []string
markdown bool
}

var opt = &options{}

var RootCommand = &cobra.Command{
Use: "kubectl-garm",
Short: "opinionated cli plugin to visualize pools and other garm resources",
Long: "this is the long help - define later",
}

func Root() *cobra.Command {
return RootCommand
}

func init() {

RootCommand.PersistentFlags().StringVar(&opt.kubeConfig, "kubeconfig", "", "path to the kubeconfig file to use for CLI requests")
RootCommand.PersistentFlags().StringVar(&opt.kubeConfigContext, "context", "", "name of the kubeconfig context to use")
RootCommand.PersistentFlags().StringVarP(&opt.namespace, "namespace", "n", "", "namespace to use for CLI requests")

RootCommand.AddGroup(
&cobra.Group{
ID: "pools",
Title: "all the pools stuff",
},
)
}

0 comments on commit 1a97f25

Please sign in to comment.