Skip to content

Commit

Permalink
Refactor some commands to reduce code duplication
Browse files Browse the repository at this point in the history
Uses a command "generator" for common aggregation situations (not label)
and updates table writing to more generically accept arbitrary aggregation
levels. This will make future improvements to kubectl-cost easier by
reducing the amount of code that needs to be updated.
  • Loading branch information
michaelmdresser committed Jun 15, 2022
1 parent cad6381 commit fb9e148
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 475 deletions.
81 changes: 81 additions & 0 deletions pkg/cmd/aggregatedcommandbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package cmd

import (
"context"
"fmt"
"strings"

"k8s.io/cli-runtime/pkg/genericclioptions"

"github.com/spf13/cobra"

"github.com/kubecost/kubectl-cost/pkg/query"
)

func buildStandardAggregatedAllocationCommand(streams genericclioptions.IOStreams, commandName string, commandAliases []string, aggregation []string, enableNamespaceFilter bool) *cobra.Command {
kubeO := NewKubeOptions(streams)
costO := CostOptions{}

cmd := &cobra.Command{
Use: commandName,
Short: fmt.Sprintf("view cost information aggregated by %s", aggregation),
Aliases: commandAliases,
RunE: func(c *cobra.Command, args []string) error {
if err := kubeO.Complete(c, args); err != nil {
return err
}
if err := kubeO.Validate(); err != nil {
return err
}

costO.Complete()

if err := costO.Validate(); err != nil {
return err
}

return runAggregatedAllocationCommand(kubeO, costO, aggregation)
},
}

// TODO: Replace entirely when we have generic filter language (v2)
if enableNamespaceFilter {
cmd.Flags().StringVarP(&costO.filterNamespace, "namespace", "n", "", "Limit results to only one namespace. Defaults to all namespaces.")
}

addCostOptionsFlags(cmd, &costO)
addKubeOptionsFlags(cmd, kubeO)

return cmd
}

func runAggregatedAllocationCommand(ko *KubeOptions, co CostOptions, aggregation []string) error {

currencyCode, err := query.QueryCurrencyCode(query.CurrencyCodeParameters{
RestConfig: ko.restConfig,
Ctx: context.Background(),
QueryBackendOptions: co.QueryBackendOptions,
})
if err != nil {
return fmt.Errorf("failed to get currency code: %s", err)
}

allocations, err := query.QueryAllocation(query.AllocationParameters{
RestConfig: ko.restConfig,
Ctx: context.Background(),
QueryParams: map[string]string{
"window": co.window,
"aggregate": strings.Join(aggregation, ","),
"accumulate": "true",
"filterNamespaces": co.filterNamespace,
},
QueryBackendOptions: co.QueryBackendOptions,
})
if err != nil {
return fmt.Errorf("failed to query allocation API: %s", err)
}

writeAllocationTable(ko.Out, aggregation, allocations[0], co.displayOptions, currencyCode, !co.isHistorical)

return nil
}
3 changes: 2 additions & 1 deletion pkg/cmd/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
// CostOptions holds common options for querying and displaying
// data from the kubecost API
type CostOptions struct {
window string
window string
filterNamespace string

isHistorical bool
showAll bool
Expand Down
83 changes: 0 additions & 83 deletions pkg/cmd/controller.go

This file was deleted.

29 changes: 25 additions & 4 deletions pkg/cmd/cost.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,32 @@ helm install \
// for the subcommands
cmd.SilenceUsage = false

cmd.AddCommand(newCmdCostNamespace(streams))
cmd.AddCommand(newCmdCostDeployment(streams))
cmd.AddCommand(newCmdCostController(streams))
// TODO: disable cluster in single-cluster case
cmd.AddCommand(buildStandardAggregatedAllocationCommand(streams,
"namespace",
[]string{"ns"},
[]string{"cluster", "namespace"},
false,
))
cmd.AddCommand(buildStandardAggregatedAllocationCommand(streams,
"deployment",
[]string{"deploy"},
[]string{"cluster", "namespace", "deployment"},
true,
))
cmd.AddCommand(buildStandardAggregatedAllocationCommand(streams,
"controller",
nil,
[]string{"cluster", "namespace", "controller"},
true,
))
cmd.AddCommand(buildStandardAggregatedAllocationCommand(streams,
"pod",
[]string{"po"},
[]string{"cluster", "namespace", "pod"},
true,
))
cmd.AddCommand(newCmdCostLabel(streams))
cmd.AddCommand(newCmdCostPod(streams))
cmd.AddCommand(newCmdCostNode(streams))
cmd.AddCommand(newCmdTUI(streams))
cmd.AddCommand(newCmdVersion(streams, GitCommit, GitBranch, GitState, GitSummary, BuildDate))
Expand Down
99 changes: 0 additions & 99 deletions pkg/cmd/deployment.go

This file was deleted.

17 changes: 11 additions & 6 deletions pkg/cmd/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cmd
import (
"context"
"fmt"
"strings"

"k8s.io/cli-runtime/pkg/genericclioptions"

Expand Down Expand Up @@ -60,6 +61,8 @@ func newCmdCostLabel(streams genericclioptions.IOStreams) *cobra.Command {

func runCostLabel(ko *KubeOptions, no *CostOptionsLabel) error {

aggregation := []string{"cluster", fmt.Sprintf("label:%s", no.queryLabel)}

currencyCode, err := query.QueryCurrencyCode(query.CurrencyCodeParameters{
RestConfig: ko.restConfig,
Ctx: context.Background(),
Expand All @@ -70,19 +73,21 @@ func runCostLabel(ko *KubeOptions, no *CostOptionsLabel) error {
}

allocations, err := query.QueryAllocation(query.AllocationParameters{
RestConfig: ko.restConfig,
Ctx: context.Background(),
Window: no.window,
Aggregate: fmt.Sprintf("label:%s", no.queryLabel),
Accumulate: "true",
RestConfig: ko.restConfig,
Ctx: context.Background(),
QueryParams: map[string]string{
"window": no.window,
"aggregate": strings.Join(aggregation, ","),
"accumulate": "true",
},
QueryBackendOptions: no.QueryBackendOptions,
})
if err != nil {
return fmt.Errorf("failed to query allocation API: %s", err)
}

// Use allocations[0] because the query accumulates to a single result
writeAllocationTable(ko.Out, "Label", allocations[0], no.displayOptions, currencyCode, false, !no.isHistorical)
writeAllocationTable(ko.Out, aggregation, allocations[0], no.displayOptions, currencyCode, !no.isHistorical)

return nil
}
Loading

0 comments on commit fb9e148

Please sign in to comment.