Skip to content

Commit

Permalink
info subcommand
Browse files Browse the repository at this point in the history
  • Loading branch information
tedteng committed Oct 20, 2022
1 parent 33fa169 commit 72b5427
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/help/gardenctl.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Find more information at: https://github.com/gardener/gardenctl-v2/blob/master/R
### SEE ALSO

* [gardenctl config](gardenctl_config.md) - Modify gardenctl configuration file using subcommands
* [gardenctl info](gardenctl_info.md) - Get landscape informations and shows the number of shoots per seed, e.g. "gardenctl info"
* [gardenctl kubeconfig](gardenctl_kubeconfig.md) - Print the kubeconfig for the current target
* [gardenctl kubectl-env](gardenctl_kubectl-env.md) - Generate a script that points KUBECONFIG to the targeted cluster for the specified shell
* [gardenctl provider-env](gardenctl_provider-env.md) - Generate the cloud provider CLI configuration script for the specified shell
Expand Down
42 changes: 42 additions & 0 deletions docs/help/gardenctl_info.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
## gardenctl info

Get landscape informations and shows the number of shoots per seed, e.g. "gardenctl info"

```
gardenctl info [flags]
```

### Options

```
-h, --help help for info
```

### Options inherited from parent commands

```
--add-dir-header If true, adds the file directory to the header of the log messages
--alsologtostderr log to standard error as well as files
--config string config file (default is ~/.garden/gardenctl-v2.yaml)
--control-plane target control plane of shoot, use together with shoot argument
--garden string target the given garden cluster
--log-backtrace-at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log-dir string If non-empty, write log files in this directory
--log-file string If non-empty, use this log file
--log-file-max-size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--logtostderr log to standard error instead of files (default true)
--one-output If true, only write logs to their native severity level (vs also writing to each lower severity level)
--project string target the given project
--seed string target the given seed cluster
--shoot string target the given shoot cluster
--skip-headers If true, avoid header prefixes in the log messages
--skip-log-headers If true, avoid headers when opening log files
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```

### SEE ALSO

* [gardenctl](gardenctl.md) - Gardenctl is a utility to interact with Gardener installations

2 changes: 2 additions & 0 deletions pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"github.com/gardener/gardenctl-v2/internal/util"
cmdconfig "github.com/gardener/gardenctl-v2/pkg/cmd/config"
cmdenv "github.com/gardener/gardenctl-v2/pkg/cmd/env"
cmdinfo "github.com/gardener/gardenctl-v2/pkg/cmd/info"
"github.com/gardener/gardenctl-v2/pkg/cmd/kubeconfig"
cmdssh "github.com/gardener/gardenctl-v2/pkg/cmd/ssh"
cmdtarget "github.com/gardener/gardenctl-v2/pkg/cmd/target"
Expand Down Expand Up @@ -129,6 +130,7 @@ Find more information at: https://github.com/gardener/gardenctl-v2/blob/master/R
cmd.AddCommand(cmdenv.NewCmdKubectlEnv(f, ioStreams))
cmd.AddCommand(cmdenv.NewCmdRC(f, ioStreams))
cmd.AddCommand(kubeconfig.NewCmdKubeconfig(f, ioStreams))
cmd.AddCommand(cmdinfo.NewCmdInfo(f, cmdinfo.NewInfoOptions(ioStreams)))

return cmd
}
Expand Down
26 changes: 26 additions & 0 deletions pkg/cmd/info/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Gardener contributors
SPDX-License-Identifier: Apache-2.0
*/

package info

import (
"github.com/spf13/cobra"

"github.com/gardener/gardenctl-v2/internal/util"
"github.com/gardener/gardenctl-v2/pkg/cmd/base"
)

// NewCmdInfo returns a new info command.
func NewCmdInfo(f util.Factory, o *InfoOptions) *cobra.Command {
cmd := &cobra.Command{
Use: "info",
Short: "Get landscape informations and shows the number of shoots per seed, e.g. \"gardenctl info\"",
Args: cobra.NoArgs,
RunE: base.WrapRunE(o, f),
}

return cmd
}
136 changes: 136 additions & 0 deletions pkg/cmd/info/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
SPDX-FileCopyrightText: 2022 SAP SE or an SAP affiliate company and Gardener contributors
SPDX-License-Identifier: Apache-2.0
*/

package info

import (
"fmt"
"sort"
"strings"
"text/tabwriter"

"github.com/gardener/gardenctl-v2/internal/util"
"github.com/gardener/gardenctl-v2/pkg/cmd/base"
)

// InfoOptions is a struct to support Info command
// nolint
type InfoOptions struct {
base.Options
Allocatable int64
Capacity int64
}

// NewInfoOptions returns initialized InfoOptions
func NewInfoOptions(ioStreams util.IOStreams) *InfoOptions {
return &InfoOptions{
Options: base.Options{
IOStreams: ioStreams,
},
}
}

// Run does the actual work of the command
func (o *InfoOptions) Run(f util.Factory) error {
manager, err := f.Manager()
if err != nil {
return err
}

infoTarget, err := manager.CurrentTarget()
if err != nil {
return err
}

// create client for the garden cluster
gardenClient, err := manager.GardenClient(infoTarget.GardenName())
if err != nil {
return err
}

shootList, err := gardenClient.ListShoots(f.Context(), infoTarget.WithShootName("").AsListOption())
if err != nil {
return err
}

seedList, err := gardenClient.ListSeeds(f.Context(), infoTarget.WithSeedName("").AsListOption())
if err != nil {
return err
}

var (
unscheduled = 0
hibernatedShootsCount = 0
totalShootsCountPerSeed = make(map[string]int)
hibernatedShootsCountPerSeed = make(map[string]int)
unscheduledList = make([]string, 0)
infoOptions = make(map[string]InfoOptions)
valAllocatable int64
valCapacity int64
)

for _, seed := range seedList.Items {
allocatable := seed.Status.Allocatable["shoots"]
capacity := seed.Status.Capacity["shoots"]

if v, ok := allocatable.AsInt64(); ok {
valAllocatable = v
} else {
return fmt.Errorf("allocatable conversion is not possible")
}

if v, ok := capacity.AsInt64(); ok {
valCapacity = v
} else {
return fmt.Errorf("capacity conversion is not possible")
}

infoOptions[seed.Name] = InfoOptions{Allocatable: valAllocatable, Capacity: valCapacity}
}

for _, shoot := range shootList.Items {
if shoot.Spec.SeedName == nil {
// unscheduledList usually list pending clusters during creation
unscheduledList = append(unscheduledList, shoot.Name)
unscheduled++

continue
}
totalShootsCountPerSeed[*shoot.Spec.SeedName]++

if shoot.Status.IsHibernated {
hibernatedShootsCountPerSeed[*shoot.Spec.SeedName]++
hibernatedShootsCount++
}
}

var sortedSeeds []string
for seed := range totalShootsCountPerSeed {
sortedSeeds = append(sortedSeeds, seed)
}

sort.Strings(sortedSeeds)
fmt.Fprintf(o.IOStreams.Out, "Garden: %s\n", infoTarget.GardenName())

w := tabwriter.NewWriter(o.IOStreams.Out, 6, 0, 20, ' ', 0)
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", "Seed", "Total", "Active", "Hibernated", "Allocatable", "Capacity")
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", "----", "-----", "------", "----------", "-----------", "--------")

for _, seed := range sortedSeeds {
if v, found := infoOptions[seed]; found {
fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%d\t%d\n", seed, totalShootsCountPerSeed[seed], totalShootsCountPerSeed[seed]-hibernatedShootsCountPerSeed[seed], hibernatedShootsCountPerSeed[seed], v.Allocatable, v.Capacity)
}
}

fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\n", "----", "-----", "------", "----------", "-----------", "--------")
fmt.Fprintf(w, "%s\t%d\t%d\t%d\t%s\t%s\n", "TOTAL", len(shootList.Items), len(shootList.Items)-hibernatedShootsCount-unscheduled, hibernatedShootsCount, "-", "-")
fmt.Fprintf(w, "%s\t%d\n", "Unscheduled", unscheduled)
fmt.Fprintf(w, "%s\t%s\n", "Unscheduled List", strings.Join(unscheduledList, ","))
fmt.Fprintln(w)
w.Flush()

return nil
}

0 comments on commit 72b5427

Please sign in to comment.