fix(fairwindsops): add nova & pluto

This commit is contained in:
Kevin Franklin Kim 2024-09-10 13:44:15 +02:00
parent 38a87b84ae
commit c7c2483258
No known key found for this signature in database
7 changed files with 547 additions and 0 deletions

View File

@ -0,0 +1,52 @@
# POSH nova provider
## Usage
### Plugin
```go
package main
type Plugin struct {
l log.Logger
kubectl *kubectl.Kubectl
commands command.Commands
}
func New(l log.Logger) (plugin.Plugin, error) {
var err error
inst := &Plugin{
l: l,
commands: command.Commands{},
}
// ...
inst.kubectl, err = kubectl.New(l, inst.cache)
if err != nil {
return nil, errors.Wrap(err, "failed to create kubectl")
}
// ...
inst.commands.Add(nova.NewCommand(l, inst.kubectl))
// ...
return inst, nil
}
```
### Ownbrew
To install binary locally, add:
```yaml
ownbrew:
packages:
# https://github.com/FairwindsOps/nova/releases
- name: nova
tap: foomo/tap/fairwindsops/nova
version: 3.10.1
```

View File

@ -0,0 +1,128 @@
package nova
import (
"context"
"sort"
"github.com/foomo/posh-providers/kubernets/kubectl"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util/suggests"
)
type (
Command struct {
l log.Logger
kubectl *kubectl.Kubectl
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, kubectl *kubectl.Kubectl, opts ...CommandOption) *Command {
inst := &Command{
l: l.Named("nova"),
kubectl: kubectl,
}
inst.commandTree = tree.New(&tree.Node{
Name: "nova",
Description: "Find outdated or deprecated Helm charts running in your cluster",
Nodes: tree.Nodes{
{
Name: "cluster",
Values: func(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
var ret []string
for _, cluster := range inst.kubectl.Clusters() {
ret = append(ret, cluster.Name())
}
sort.Strings(ret)
return suggests.List(ret)
},
Description: "Cluster name",
Nodes: tree.Nodes{
{
Name: "find",
Description: "",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().Bool("containers", false, "Show old container image versions instead of helm chart versions")
fs.Default().Bool("helm", false, "Show old helm chart versions")
fs.Default().Bool("include-all", false, "Show all charts even if no latest version is found")
fs.Default().Bool("show-errored-containers", false, "Show errors encountered when scanning")
fs.Default().Bool("show-non-semver", false, "Show all containers even if they don't follow semver")
fs.Default().Bool("show-old", false, "Only show charts that are not on the latest version")
fs.Default().Bool("wide", false, "Output chart name and namespace")
fs.Default().String("config", "", "Config file to use")
fs.Default().String("format", "table", "An output format (table, json)")
fs.Default().String("namespace", "", "Namespace to look in")
fs.Internal().String("profile", "", "Profile to use")
if r.Args().HasIndex(0) {
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
},
Execute: inst.execute,
},
},
},
},
})
return inst
}
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (c *Command) Name() string {
return c.commandTree.Node().Name
}
func (c *Command) Description() string {
return c.commandTree.Node().Description
}
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
return c.commandTree.Complete(ctx, r)
}
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error {
return c.commandTree.Execute(ctx, r)
}
func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
return c.commandTree.Help(ctx, r)
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
fs := r.FlagSets().Default()
ifs := r.FlagSets().Internal()
cluster, args := c.kubectl.Cluster(r.Args().At(0)), r.Args()[1:]
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "nova").
Args(args...).
Args(fs.Visited().Args()...).
Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Env(cluster.Env(profile)).
Run()
}

View File

@ -0,0 +1,52 @@
# POSH pluto provider
## Usage
### Plugin
```go
package main
type Plugin struct {
l log.Logger
kubectl *kubectl.Kubectl
commands command.Commands
}
func New(l log.Logger) (plugin.Plugin, error) {
var err error
inst := &Plugin{
l: l,
commands: command.Commands{},
}
// ...
inst.kubectl, err = kubectl.New(l, inst.cache)
if err != nil {
return nil, errors.Wrap(err, "failed to create kubectl")
}
// ...
inst.commands.Add(pluto.NewCommand(l, inst.kubectl))
// ...
return inst, nil
}
```
### Ownbrew
To install binary locally, add:
```yaml
ownbrew:
packages:
# https://github.com/FairwindsOps/pluto/releases
- name: pluto
tap: foomo/tap/fairwindsops/pluto
version: 5.20.2
```

View File

@ -0,0 +1,124 @@
package pluto
import (
"context"
"sort"
"github.com/foomo/posh-providers/kubernets/kubectl"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util/suggests"
)
type (
Command struct {
l log.Logger
kubectl *kubectl.Kubectl
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, kubectl *kubectl.Kubectl, opts ...CommandOption) *Command {
inst := &Command{
l: l.Named("pluto"),
kubectl: kubectl,
}
inst.commandTree = tree.New(&tree.Node{
Name: "pluto",
Description: "Find Kubernetes resources that have been deprecated",
Nodes: tree.Nodes{
{
Name: "cluster",
Values: func(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
var ret []string
for _, cluster := range inst.kubectl.Clusters() {
ret = append(ret, cluster.Name())
}
sort.Strings(ret)
return suggests.List(ret)
},
Description: "Cluster name",
Nodes: tree.Nodes{
{
Name: "detect",
Description: "",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().Bool("only-show-removed", false, "Only display the apiVersions that have been removed in the target version")
fs.Default().String("output", "wide", "The output format to use. (normal|wide|custom|json|yaml|markdown|csv)")
fs.Internal().String("profile", "", "Profile to use")
if r.Args().HasIndex(0) {
if err := fs.Internal().SetValues("profile", inst.kubectl.Cluster(r.Args().At(0)).Profiles(ctx)...); err != nil {
return err
}
}
return nil
},
Execute: inst.detect,
},
},
},
},
})
return inst
}
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (c *Command) Name() string {
return c.commandTree.Node().Name
}
func (c *Command) Description() string {
return c.commandTree.Node().Description
}
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
return c.commandTree.Complete(ctx, r)
}
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error {
return c.commandTree.Execute(ctx, r)
}
func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
return c.commandTree.Help(ctx, r)
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) detect(ctx context.Context, r *readline.Readline) error {
fs := r.FlagSets().Default()
ifs := r.FlagSets().Internal()
cluster, args := c.kubectl.Cluster(r.Args().At(0)), r.Args()[2:]
profile, err := ifs.GetString("profile")
if err != nil {
return err
}
return shell.New(ctx, c.l, "pluto", "detect-all-in-cluster").
Args(args...).
Args("--ignore-removals").
Args("--ignore-deprecations").
Args("--ignore-unavailable-replacements").
Args(fs.Visited().Args()...).
Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Args("2>/dev/null").
Env(cluster.Env(profile)).
Run()
}

149
grafana/k6/command.go Normal file
View File

@ -0,0 +1,149 @@
package k6
import (
"context"
"fmt"
"os"
"path"
"strings"
"github.com/foomo/posh-providers/onepassword"
"github.com/foomo/posh/pkg/command/tree"
"github.com/foomo/posh/pkg/log"
"github.com/foomo/posh/pkg/prompt/goprompt"
"github.com/foomo/posh/pkg/readline"
"github.com/foomo/posh/pkg/shell"
"github.com/foomo/posh/pkg/util/suggests"
"github.com/spf13/viper"
)
type (
Command struct {
l log.Logger
op *onepassword.OnePassword
name string
cfg Config
configKey string
commandTree tree.Root
}
CommandOption func(*Command)
)
// ------------------------------------------------------------------------------------------------
// ~ Options
// ------------------------------------------------------------------------------------------------
func CommandWithName(v string) CommandOption {
return func(o *Command) {
o.name = v
}
}
func CommandWithConfigKey(v string) CommandOption {
return func(o *Command) {
o.name = v
}
}
// ------------------------------------------------------------------------------------------------
// ~ Constructor
// ------------------------------------------------------------------------------------------------
func NewCommand(l log.Logger, op *onepassword.OnePassword, opts ...CommandOption) (*Command, error) {
inst := &Command{
l: l.Named("k6"),
name: "k6",
configKey: "k6",
op: op,
}
for _, opt := range opts {
if opt != nil {
opt(inst)
}
}
if err := viper.UnmarshalKey(inst.configKey, &inst.cfg); err != nil {
return nil, err
}
if err := os.MkdirAll(inst.cfg.Path, 0700); err != nil {
return nil, err
}
inst.commandTree = tree.New(&tree.Node{
Name: inst.name,
Description: "Run k6",
Flags: func(ctx context.Context, r *readline.Readline, fs *readline.FlagSets) error {
fs.Default().Bool("debug", false, "show debug output")
return nil
},
Args: tree.Args{
{
Name: "env",
Description: "Env name",
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
return suggests.List(inst.cfg.EnvNames())
},
},
{
Name: "scenario",
Description: "Scenario name",
Suggest: func(ctx context.Context, t tree.Root, r *readline.Readline) []goprompt.Suggest {
scenarios, err := inst.cfg.Scenarios()
if err != nil {
return nil
}
return suggests.List(scenarios)
},
},
},
Execute: inst.execute,
})
return inst, nil
}
// ------------------------------------------------------------------------------------------------
// ~ Public methods
// ------------------------------------------------------------------------------------------------
func (c *Command) Name() string {
return c.commandTree.Node().Name
}
func (c *Command) Description() string {
return c.commandTree.Node().Description
}
func (c *Command) Complete(ctx context.Context, r *readline.Readline) []goprompt.Suggest {
return c.commandTree.Complete(ctx, r)
}
func (c *Command) Execute(ctx context.Context, r *readline.Readline) error {
return c.commandTree.Execute(ctx, r)
}
func (c *Command) Help(ctx context.Context, r *readline.Readline) string {
return c.commandTree.Help(ctx, r)
}
// ------------------------------------------------------------------------------------------------
// ~ Private methods
// ------------------------------------------------------------------------------------------------
func (c *Command) execute(ctx context.Context, r *readline.Readline) error {
fs := r.FlagSets().Default()
env, scenario := r.Args().At(0), r.Args().At(1)
var envs []string
for k, v := range c.cfg.Env(env) {
envs = append(envs, fmt.Sprintf("%s=%s", strings.ToUpper(k), v))
}
return shell.New(ctx, c.l, "k6", "run", "--out", "web-dashboard", path.Join(c.cfg.Path, scenario)).
Args(fs.Visited().Args()...).
Args(r.AdditionalArgs()...).
Args(r.AdditionalFlags()...).
Env(envs...).
Run()
}

39
grafana/k6/config.go Normal file
View File

@ -0,0 +1,39 @@
package k6
import (
"os"
"sort"
"strings"
"github.com/foomo/posh/pkg/env"
"github.com/samber/lo"
)
type Config struct {
Path string `yaml:"path"`
Envs map[string]Env `yaml:"envs"`
}
func (c Config) Env(name string) Env {
return c.Envs[name]
}
func (c Config) EnvNames() []string {
ret := lo.Keys(c.Envs)
sort.Strings(ret)
return ret
}
func (c Config) Scenarios() ([]string, error) {
entries, err := os.ReadDir(env.Path(c.Path))
if err != nil {
return nil, err
}
var ret []string
for _, e := range entries {
if !e.IsDir() && strings.HasSuffix(e.Name(), ".js") {
ret = append(ret, e.Name())
}
}
return ret, nil
}

3
grafana/k6/env.go Normal file
View File

@ -0,0 +1,3 @@
package k6
type Env map[string]string