feat: introducing a karmada top command
Signed-off-by: chaunceyjiang <chaunceyjiang@gmail.com>
This commit is contained in:
parent
25db1e06d0
commit
62482f437c
|
@ -28,6 +28,7 @@ import (
|
|||
"github.com/karmada-io/karmada/pkg/karmadactl/register"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/taint"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/token"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/top"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/unjoin"
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/util"
|
||||
"github.com/karmada-io/karmada/pkg/version/sharedcommand"
|
||||
|
@ -106,6 +107,7 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command {
|
|||
Commands: []*cobra.Command{
|
||||
apply.NewCmdApply(f, parentCommand, ioStreams),
|
||||
promote.NewCmdPromote(f, parentCommand),
|
||||
top.NewCmdTop(f, parentCommand, ioStreams),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
package top
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/cli-runtime/pkg/printers"
|
||||
"k8s.io/kubectl/pkg/metricsutil"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
|
||||
autoscalingv1alpha1 "github.com/karmada-io/karmada/pkg/apis/autoscaling/v1alpha1"
|
||||
)
|
||||
|
||||
var (
|
||||
MeasuredResources = []corev1.ResourceName{
|
||||
corev1.ResourceCPU,
|
||||
corev1.ResourceMemory,
|
||||
}
|
||||
PodColumns = []string{"NAME", "CLUSTER", "CPU(cores)", "MEMORY(bytes)"}
|
||||
NamespaceColumn = "NAMESPACE"
|
||||
PodColumn = "POD"
|
||||
)
|
||||
|
||||
type ResourceMetricsInfo struct {
|
||||
Cluster string
|
||||
Name string
|
||||
Metrics corev1.ResourceList
|
||||
Available corev1.ResourceList
|
||||
}
|
||||
|
||||
type TopCmdPrinter struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func NewTopCmdPrinter(out io.Writer) *TopCmdPrinter {
|
||||
return &TopCmdPrinter{out: out}
|
||||
}
|
||||
|
||||
func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, printContainers, withNamespace, noHeaders bool, sortBy string, sum bool) error {
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
w := printers.GetNewTabWriter(printer.out)
|
||||
defer w.Flush()
|
||||
|
||||
columnWidth := len(PodColumns)
|
||||
if !noHeaders {
|
||||
if withNamespace {
|
||||
printValue(w, NamespaceColumn)
|
||||
columnWidth++
|
||||
}
|
||||
if printContainers {
|
||||
printValue(w, PodColumn)
|
||||
columnWidth++
|
||||
}
|
||||
printColumnNames(w, PodColumns)
|
||||
}
|
||||
|
||||
sort.Sort(NewPodMetricsSorter(metrics, withNamespace, sortBy))
|
||||
|
||||
for i := range metrics {
|
||||
if printContainers {
|
||||
sort.Sort(metricsutil.NewContainerMetricsSorter(metrics[i].Containers, sortBy))
|
||||
printSinglePodContainerMetrics(w, &metrics[i], withNamespace)
|
||||
} else {
|
||||
printSinglePodMetrics(w, &metrics[i], withNamespace)
|
||||
}
|
||||
}
|
||||
|
||||
if sum {
|
||||
adder := NewResourceAdder(MeasuredResources)
|
||||
for i := range metrics {
|
||||
adder.AddPodMetrics(&metrics[i])
|
||||
}
|
||||
printPodResourcesSum(w, adder.total, columnWidth)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printColumnNames(out io.Writer, names []string) {
|
||||
for _, name := range names {
|
||||
printValue(out, name)
|
||||
}
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
func printSinglePodMetrics(out io.Writer, m *metricsapi.PodMetrics, withNamespace bool) {
|
||||
podMetrics := getPodMetrics(m)
|
||||
if withNamespace {
|
||||
printValue(out, m.Namespace)
|
||||
}
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: m.Name,
|
||||
Cluster: m.Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey],
|
||||
Metrics: podMetrics,
|
||||
Available: corev1.ResourceList{},
|
||||
})
|
||||
}
|
||||
|
||||
func printSinglePodContainerMetrics(out io.Writer, m *metricsapi.PodMetrics, withNamespace bool) {
|
||||
for _, c := range m.Containers {
|
||||
if withNamespace {
|
||||
printValue(out, m.Namespace)
|
||||
}
|
||||
printValue(out, m.Name)
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: c.Name,
|
||||
Cluster: m.Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey],
|
||||
Metrics: c.Usage,
|
||||
Available: corev1.ResourceList{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getPodMetrics(m *metricsapi.PodMetrics) corev1.ResourceList {
|
||||
podMetrics := make(corev1.ResourceList)
|
||||
for _, res := range MeasuredResources {
|
||||
podMetrics[res], _ = resource.ParseQuantity("0")
|
||||
}
|
||||
|
||||
for _, c := range m.Containers {
|
||||
for _, res := range MeasuredResources {
|
||||
quantity := podMetrics[res]
|
||||
quantity.Add(c.Usage[res])
|
||||
podMetrics[res] = quantity
|
||||
}
|
||||
}
|
||||
return podMetrics
|
||||
}
|
||||
|
||||
func printMetricsLine(out io.Writer, metrics *ResourceMetricsInfo) {
|
||||
printValue(out, metrics.Name)
|
||||
printValue(out, metrics.Cluster)
|
||||
printAllResourceUsages(out, metrics)
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
func printValue(out io.Writer, value interface{}) {
|
||||
fmt.Fprintf(out, "%v\t", value)
|
||||
}
|
||||
|
||||
func printAllResourceUsages(out io.Writer, metrics *ResourceMetricsInfo) {
|
||||
for _, res := range MeasuredResources {
|
||||
quantity := metrics.Metrics[res]
|
||||
printSingleResourceUsage(out, res, quantity)
|
||||
fmt.Fprint(out, "\t")
|
||||
if available, found := metrics.Available[res]; found {
|
||||
fraction := float64(quantity.MilliValue()) / float64(available.MilliValue()) * 100
|
||||
fmt.Fprintf(out, "%d%%\t", int64(fraction))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printSingleResourceUsage(out io.Writer, resourceType corev1.ResourceName, quantity resource.Quantity) {
|
||||
switch resourceType {
|
||||
case corev1.ResourceCPU:
|
||||
fmt.Fprintf(out, "%vm", quantity.MilliValue())
|
||||
case corev1.ResourceMemory:
|
||||
fmt.Fprintf(out, "%vMi", quantity.Value()/(1024*1024))
|
||||
default:
|
||||
fmt.Fprintf(out, "%v", quantity.Value())
|
||||
}
|
||||
}
|
||||
|
||||
func printPodResourcesSum(out io.Writer, total corev1.ResourceList, columnWidth int) {
|
||||
for i := 0; i < columnWidth-2; i++ {
|
||||
printValue(out, "")
|
||||
}
|
||||
printValue(out, "________")
|
||||
printValue(out, "________")
|
||||
fmt.Fprintf(out, "\n")
|
||||
for i := 0; i < columnWidth-4; i++ {
|
||||
printValue(out, "")
|
||||
}
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: "",
|
||||
Metrics: total,
|
||||
Available: corev1.ResourceList{},
|
||||
})
|
||||
}
|
||||
|
||||
type ResourceAdder struct {
|
||||
resources []corev1.ResourceName
|
||||
total corev1.ResourceList
|
||||
}
|
||||
|
||||
func NewResourceAdder(resources []corev1.ResourceName) *ResourceAdder {
|
||||
return &ResourceAdder{
|
||||
resources: resources,
|
||||
total: make(corev1.ResourceList),
|
||||
}
|
||||
}
|
||||
|
||||
// AddPodMetrics adds each pod metric to the total
|
||||
func (adder *ResourceAdder) AddPodMetrics(m *metricsapi.PodMetrics) {
|
||||
for _, c := range m.Containers {
|
||||
for _, res := range adder.resources {
|
||||
total := adder.total[res]
|
||||
total.Add(c.Usage[res])
|
||||
adder.total[res] = total
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package top
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
|
||||
autoscalingv1alpha1 "github.com/karmada-io/karmada/pkg/apis/autoscaling/v1alpha1"
|
||||
)
|
||||
|
||||
type PodMetricsSorter struct {
|
||||
metrics []metricsapi.PodMetrics
|
||||
sortBy string
|
||||
withNamespace bool
|
||||
podMetrics []corev1.ResourceList
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Len() int {
|
||||
return len(p.metrics)
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Swap(i, j int) {
|
||||
p.metrics[i], p.metrics[j] = p.metrics[j], p.metrics[i]
|
||||
p.podMetrics[i], p.podMetrics[j] = p.podMetrics[j], p.podMetrics[i]
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Less(i, j int) bool {
|
||||
switch p.sortBy {
|
||||
case "cpu":
|
||||
return p.podMetrics[i].Cpu().MilliValue() > p.podMetrics[j].Cpu().MilliValue()
|
||||
case "memory":
|
||||
return p.podMetrics[i].Memory().Value() > p.podMetrics[j].Memory().Value()
|
||||
default:
|
||||
if p.metrics[i].Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey] != p.metrics[j].Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey] {
|
||||
return p.metrics[i].Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey] < p.metrics[j].Annotations[autoscalingv1alpha1.QuerySourceAnnotationKey]
|
||||
}
|
||||
if p.withNamespace && p.metrics[i].Namespace != p.metrics[j].Namespace {
|
||||
return p.metrics[i].Namespace < p.metrics[j].Namespace
|
||||
}
|
||||
return p.metrics[i].Name < p.metrics[j].Name
|
||||
}
|
||||
}
|
||||
|
||||
func NewPodMetricsSorter(metrics []metricsapi.PodMetrics, withNamespace bool, sortBy string) *PodMetricsSorter {
|
||||
var podMetrics = make([]corev1.ResourceList, len(metrics))
|
||||
if len(sortBy) > 0 {
|
||||
for i := range metrics {
|
||||
podMetrics[i] = getPodMetrics(&metrics[i])
|
||||
}
|
||||
}
|
||||
|
||||
return &PodMetricsSorter{
|
||||
metrics: metrics,
|
||||
sortBy: sortBy,
|
||||
withNamespace: withNamespace,
|
||||
podMetrics: podMetrics,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package top
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
sortByCPU = "cpu"
|
||||
sortByMemory = "memory"
|
||||
)
|
||||
|
||||
var (
|
||||
supportedMetricsAPIVersions = []string{
|
||||
"v1beta1",
|
||||
}
|
||||
topLong = templates.LongDesc(`
|
||||
Display Resource (CPU/Memory) usage of member clusters.
|
||||
|
||||
The top command allows you to see the resource consumption for pods of member clusters.
|
||||
|
||||
This command requires karmada-metrics-adapter to be correctly configured and working on the Karmada control plane and
|
||||
Metrics Server to be correctly configured and working on the member clusters.`)
|
||||
)
|
||||
|
||||
func NewCmdTop(f cmdutil.Factory, parentCommand string, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "top",
|
||||
Short: "Display resource (CPU/memory) usage of member clusters",
|
||||
Long: topLong,
|
||||
Run: cmdutil.DefaultSubCommandRun(streams.ErrOut),
|
||||
}
|
||||
|
||||
// create subcommands
|
||||
cmd.AddCommand(NewCmdTopPod(f, parentCommand, nil, streams))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func SupportedMetricsAPIVersionAvailable(discoveredAPIGroups *metav1.APIGroupList) bool {
|
||||
for _, discoveredAPIGroup := range discoveredAPIGroups.Groups {
|
||||
if discoveredAPIGroup.Name != metricsapi.GroupName {
|
||||
continue
|
||||
}
|
||||
for _, version := range discoveredAPIGroup.Versions {
|
||||
for _, supportedVersion := range supportedMetricsAPIVersions {
|
||||
if version.Version == supportedVersion {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
package top
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/client-go/discovery"
|
||||
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
"k8s.io/klog/v2"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/util/completion"
|
||||
"k8s.io/kubectl/pkg/util/i18n"
|
||||
"k8s.io/kubectl/pkg/util/templates"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
metricsv1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1"
|
||||
metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
|
||||
"github.com/karmada-io/karmada/pkg/karmadactl/options"
|
||||
)
|
||||
|
||||
type TopPodOptions struct {
|
||||
ResourceName string
|
||||
Namespace string
|
||||
LabelSelector string
|
||||
FieldSelector string
|
||||
SortBy string
|
||||
AllNamespaces bool
|
||||
PrintContainers bool
|
||||
NoHeaders bool
|
||||
UseProtocolBuffers bool
|
||||
Sum bool
|
||||
|
||||
PodClient corev1client.PodsGetter
|
||||
Printer *TopCmdPrinter
|
||||
DiscoveryClient discovery.DiscoveryInterface
|
||||
MetricsClient metricsclientset.Interface
|
||||
|
||||
genericclioptions.IOStreams
|
||||
}
|
||||
|
||||
const metricsCreationDelay = 2 * time.Minute
|
||||
|
||||
var (
|
||||
topPodLong = templates.LongDesc(i18n.T(`
|
||||
Display resource (CPU/memory) usage of pods.
|
||||
|
||||
The 'top pod' command allows you to see the resource consumption of pods of member clusters.
|
||||
|
||||
Due to the metrics pipeline delay, they may be unavailable for a few minutes
|
||||
since pod creation.`))
|
||||
|
||||
topPodExample = templates.Examples(i18n.T(`
|
||||
# Show metrics for all pods in the default namespace
|
||||
%[1]s top pod
|
||||
|
||||
# Show metrics for all pods in the given namespace
|
||||
%[1]s top pod --namespace=NAMESPACE
|
||||
|
||||
# Show metrics for a given pod and its containers
|
||||
%[1]s top pod POD_NAME --containers
|
||||
|
||||
# Show metrics for the pods defined by label name=myLabel
|
||||
%[1]s top pod -l name=myLabel`))
|
||||
)
|
||||
|
||||
func NewCmdTopPod(f cmdutil.Factory, parentCommand string, o *TopPodOptions, streams genericclioptions.IOStreams) *cobra.Command {
|
||||
if o == nil {
|
||||
o = &TopPodOptions{
|
||||
IOStreams: streams,
|
||||
UseProtocolBuffers: true,
|
||||
}
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "pod [NAME | -l label]",
|
||||
DisableFlagsInUseLine: true,
|
||||
Short: i18n.T("Display resource (CPU/memory) usage of pods of member clusters"),
|
||||
Long: topPodLong,
|
||||
Example: fmt.Sprintf(topPodExample, parentCommand),
|
||||
ValidArgsFunction: completion.ResourceNameCompletionFunc(f, "pod"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate())
|
||||
cmdutil.CheckErr(o.RunTopPod())
|
||||
},
|
||||
Aliases: []string{"pods", "po"},
|
||||
}
|
||||
cmdutil.AddLabelSelectorFlagVar(cmd, &o.LabelSelector)
|
||||
options.AddKubeConfigFlags(cmd.Flags())
|
||||
cmd.Flags().StringVarP(options.DefaultConfigFlags.Namespace, "namespace", "n", *options.DefaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request")
|
||||
cmd.Flags().StringVar(&o.FieldSelector, "field-selector", o.FieldSelector, "Selector (field query) to filter on, supports '=', '==', and '!='.(e.g. --field-selector key1=value1,key2=value2). The server only supports a limited number of field queries per type.")
|
||||
cmd.Flags().StringVar(&o.SortBy, "sort-by", o.SortBy, "If non-empty, sort pods list using specified field. The field can be either 'cpu' or 'memory'.")
|
||||
cmd.Flags().BoolVar(&o.PrintContainers, "containers", o.PrintContainers, "If present, print usage of containers within a pod.")
|
||||
cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.")
|
||||
cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If present, print output without headers.")
|
||||
cmd.Flags().BoolVar(&o.UseProtocolBuffers, "use-protocol-buffers", o.UseProtocolBuffers, "Enables using protocol-buffers to access Metrics API.")
|
||||
cmd.Flags().BoolVar(&o.Sum, "sum", o.Sum, "Print the sum of the resource usage")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *TopPodOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) == 1 {
|
||||
o.ResourceName = args[0]
|
||||
} else if len(args) > 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "%s", cmd.Use)
|
||||
}
|
||||
|
||||
o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clientset, err := f.KubernetesClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.DiscoveryClient = clientset.DiscoveryClient
|
||||
config, err := f.ToRESTConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.UseProtocolBuffers {
|
||||
config.ContentType = "application/vnd.kubernetes.protobuf"
|
||||
}
|
||||
o.MetricsClient, err = metricsclientset.NewForConfig(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.PodClient = clientset.CoreV1()
|
||||
|
||||
o.Printer = NewTopCmdPrinter(o.Out)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *TopPodOptions) Validate() error {
|
||||
if len(o.SortBy) > 0 {
|
||||
if o.SortBy != sortByCPU && o.SortBy != sortByMemory {
|
||||
return errors.New("--sort-by accepts only cpu or memory")
|
||||
}
|
||||
}
|
||||
if len(o.ResourceName) > 0 && (len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0) {
|
||||
return errors.New("only one of NAME or selector can be provided")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *TopPodOptions) RunTopPod() error {
|
||||
var err error
|
||||
labelSelector := labels.Everything()
|
||||
if len(o.LabelSelector) > 0 {
|
||||
labelSelector, err = labels.Parse(o.LabelSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
fieldSelector := fields.Everything()
|
||||
if len(o.FieldSelector) > 0 {
|
||||
fieldSelector, err = fields.ParseSelector(o.FieldSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
apiGroups, err := o.DiscoveryClient.ServerGroups()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
metricsAPIAvailable := SupportedMetricsAPIVersionAvailable(apiGroups)
|
||||
|
||||
if !metricsAPIAvailable {
|
||||
return errors.New("Metrics API not available")
|
||||
}
|
||||
metrics, err := getMetricsFromMetricsAPI(o.MetricsClient, o.Namespace, o.ResourceName, o.AllNamespaces, labelSelector, fieldSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// First we check why no metrics have been received.
|
||||
if len(metrics.Items) == 0 {
|
||||
// If the API server query is successful but all the pods are newly created,
|
||||
// the metrics are probably not ready yet, so we return the error here in the first place.
|
||||
err := verifyEmptyMetrics(o, labelSelector, fieldSelector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// if we had no errors, be sure we output something.
|
||||
if o.AllNamespaces {
|
||||
fmt.Fprintln(o.ErrOut, "No resources found")
|
||||
} else {
|
||||
fmt.Fprintf(o.ErrOut, "No resources found in %s namespace.\n", o.Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
return o.Printer.PrintPodMetrics(metrics.Items, o.PrintContainers, o.AllNamespaces, o.NoHeaders, o.SortBy, o.Sum)
|
||||
}
|
||||
|
||||
func getMetricsFromMetricsAPI(metricsClient metricsclientset.Interface, namespace, resourceName string, allNamespaces bool, labelSelector labels.Selector, fieldSelector fields.Selector) (*metricsapi.PodMetricsList, error) {
|
||||
var err error
|
||||
ns := metav1.NamespaceAll
|
||||
if !allNamespaces {
|
||||
ns = namespace
|
||||
}
|
||||
versionedMetrics := &metricsv1beta1api.PodMetricsList{}
|
||||
if resourceName != "" {
|
||||
m, err := metricsClient.MetricsV1beta1().PodMetricses(ns).Get(context.TODO(), resourceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
versionedMetrics.Items = []metricsv1beta1api.PodMetrics{*m}
|
||||
} else {
|
||||
versionedMetrics, err = metricsClient.MetricsV1beta1().PodMetricses(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: labelSelector.String(), FieldSelector: fieldSelector.String()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
metrics := &metricsapi.PodMetricsList{}
|
||||
err = metricsv1beta1api.Convert_v1beta1_PodMetricsList_To_metrics_PodMetricsList(versionedMetrics, metrics, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return metrics, nil
|
||||
}
|
||||
|
||||
func verifyEmptyMetrics(o *TopPodOptions, labelSelector labels.Selector, fieldSelector fields.Selector) error {
|
||||
if len(o.ResourceName) > 0 {
|
||||
pod, err := o.PodClient.Pods(o.Namespace).Get(context.TODO(), o.ResourceName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := checkPodAge(pod); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
pods, err := o.PodClient.Pods(o.Namespace).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: labelSelector.String(),
|
||||
FieldSelector: fieldSelector.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pods.Items) == 0 {
|
||||
return nil
|
||||
}
|
||||
for i := range pods.Items {
|
||||
if err := checkPodAge(&pods.Items[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors.New("metrics not available yet")
|
||||
}
|
||||
|
||||
func checkPodAge(pod *corev1.Pod) error {
|
||||
age := time.Since(pod.CreationTimestamp.Time)
|
||||
if age > metricsCreationDelay {
|
||||
message := fmt.Sprintf("Metrics not available for pod %s/%s, age: %s", pod.Namespace, pod.Name, age.String())
|
||||
return errors.New(message)
|
||||
} else {
|
||||
klog.V(2).Infof("Metrics not yet available for pod %s/%s, age: %s", pod.Namespace, pod.Name, age.String())
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metricsutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/cli-runtime/pkg/printers"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
)
|
||||
|
||||
var (
|
||||
MeasuredResources = []v1.ResourceName{
|
||||
v1.ResourceCPU,
|
||||
v1.ResourceMemory,
|
||||
}
|
||||
NodeColumns = []string{"NAME", "CPU(cores)", "CPU%", "MEMORY(bytes)", "MEMORY%"}
|
||||
PodColumns = []string{"NAME", "CPU(cores)", "MEMORY(bytes)"}
|
||||
NamespaceColumn = "NAMESPACE"
|
||||
PodColumn = "POD"
|
||||
)
|
||||
|
||||
type ResourceMetricsInfo struct {
|
||||
Name string
|
||||
Metrics v1.ResourceList
|
||||
Available v1.ResourceList
|
||||
}
|
||||
|
||||
type TopCmdPrinter struct {
|
||||
out io.Writer
|
||||
}
|
||||
|
||||
func NewTopCmdPrinter(out io.Writer) *TopCmdPrinter {
|
||||
return &TopCmdPrinter{out: out}
|
||||
}
|
||||
|
||||
func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics, availableResources map[string]v1.ResourceList, noHeaders bool, sortBy string) error {
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
w := printers.GetNewTabWriter(printer.out)
|
||||
defer w.Flush()
|
||||
|
||||
sort.Sort(NewNodeMetricsSorter(metrics, sortBy))
|
||||
|
||||
if !noHeaders {
|
||||
printColumnNames(w, NodeColumns)
|
||||
}
|
||||
var usage v1.ResourceList
|
||||
for _, m := range metrics {
|
||||
m.Usage.DeepCopyInto(&usage)
|
||||
printMetricsLine(w, &ResourceMetricsInfo{
|
||||
Name: m.Name,
|
||||
Metrics: usage,
|
||||
Available: availableResources[m.Name],
|
||||
})
|
||||
delete(availableResources, m.Name)
|
||||
}
|
||||
|
||||
// print lines for nodes of which the metrics is unreachable.
|
||||
for nodeName := range availableResources {
|
||||
printMissingMetricsNodeLine(w, nodeName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, printContainers bool, withNamespace bool, noHeaders bool, sortBy string, sum bool) error {
|
||||
if len(metrics) == 0 {
|
||||
return nil
|
||||
}
|
||||
w := printers.GetNewTabWriter(printer.out)
|
||||
defer w.Flush()
|
||||
|
||||
columnWidth := len(PodColumns)
|
||||
if !noHeaders {
|
||||
if withNamespace {
|
||||
printValue(w, NamespaceColumn)
|
||||
columnWidth++
|
||||
}
|
||||
if printContainers {
|
||||
printValue(w, PodColumn)
|
||||
columnWidth++
|
||||
}
|
||||
printColumnNames(w, PodColumns)
|
||||
}
|
||||
|
||||
sort.Sort(NewPodMetricsSorter(metrics, withNamespace, sortBy))
|
||||
|
||||
for _, m := range metrics {
|
||||
if printContainers {
|
||||
sort.Sort(NewContainerMetricsSorter(m.Containers, sortBy))
|
||||
printSinglePodContainerMetrics(w, &m, withNamespace)
|
||||
} else {
|
||||
printSinglePodMetrics(w, &m, withNamespace)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if sum {
|
||||
adder := NewResourceAdder(MeasuredResources)
|
||||
for _, m := range metrics {
|
||||
adder.AddPodMetrics(&m)
|
||||
}
|
||||
printPodResourcesSum(w, adder.total, columnWidth)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func printColumnNames(out io.Writer, names []string) {
|
||||
for _, name := range names {
|
||||
printValue(out, name)
|
||||
}
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
func printSinglePodMetrics(out io.Writer, m *metricsapi.PodMetrics, withNamespace bool) {
|
||||
podMetrics := getPodMetrics(m)
|
||||
if withNamespace {
|
||||
printValue(out, m.Namespace)
|
||||
}
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: m.Name,
|
||||
Metrics: podMetrics,
|
||||
Available: v1.ResourceList{},
|
||||
})
|
||||
}
|
||||
|
||||
func printSinglePodContainerMetrics(out io.Writer, m *metricsapi.PodMetrics, withNamespace bool) {
|
||||
for _, c := range m.Containers {
|
||||
if withNamespace {
|
||||
printValue(out, m.Namespace)
|
||||
}
|
||||
printValue(out, m.Name)
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: c.Name,
|
||||
Metrics: c.Usage,
|
||||
Available: v1.ResourceList{},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func getPodMetrics(m *metricsapi.PodMetrics) v1.ResourceList {
|
||||
podMetrics := make(v1.ResourceList)
|
||||
for _, res := range MeasuredResources {
|
||||
podMetrics[res], _ = resource.ParseQuantity("0")
|
||||
}
|
||||
|
||||
for _, c := range m.Containers {
|
||||
for _, res := range MeasuredResources {
|
||||
quantity := podMetrics[res]
|
||||
quantity.Add(c.Usage[res])
|
||||
podMetrics[res] = quantity
|
||||
}
|
||||
}
|
||||
return podMetrics
|
||||
}
|
||||
|
||||
func printMetricsLine(out io.Writer, metrics *ResourceMetricsInfo) {
|
||||
printValue(out, metrics.Name)
|
||||
printAllResourceUsages(out, metrics)
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
func printMissingMetricsNodeLine(out io.Writer, nodeName string) {
|
||||
printValue(out, nodeName)
|
||||
unknownMetricsStatus := "<unknown>"
|
||||
for i := 0; i < len(MeasuredResources); i++ {
|
||||
printValue(out, unknownMetricsStatus)
|
||||
printValue(out, unknownMetricsStatus)
|
||||
}
|
||||
fmt.Fprint(out, "\n")
|
||||
}
|
||||
|
||||
func printValue(out io.Writer, value interface{}) {
|
||||
fmt.Fprintf(out, "%v\t", value)
|
||||
}
|
||||
|
||||
func printAllResourceUsages(out io.Writer, metrics *ResourceMetricsInfo) {
|
||||
for _, res := range MeasuredResources {
|
||||
quantity := metrics.Metrics[res]
|
||||
printSingleResourceUsage(out, res, quantity)
|
||||
fmt.Fprint(out, "\t")
|
||||
if available, found := metrics.Available[res]; found {
|
||||
fraction := float64(quantity.MilliValue()) / float64(available.MilliValue()) * 100
|
||||
fmt.Fprintf(out, "%d%%\t", int64(fraction))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printSingleResourceUsage(out io.Writer, resourceType v1.ResourceName, quantity resource.Quantity) {
|
||||
switch resourceType {
|
||||
case v1.ResourceCPU:
|
||||
fmt.Fprintf(out, "%vm", quantity.MilliValue())
|
||||
case v1.ResourceMemory:
|
||||
fmt.Fprintf(out, "%vMi", quantity.Value()/(1024*1024))
|
||||
default:
|
||||
fmt.Fprintf(out, "%v", quantity.Value())
|
||||
}
|
||||
}
|
||||
|
||||
func printPodResourcesSum(out io.Writer, total v1.ResourceList, columnWidth int) {
|
||||
for i := 0; i < columnWidth-2; i++ {
|
||||
printValue(out, "")
|
||||
}
|
||||
printValue(out, "________")
|
||||
printValue(out, "________")
|
||||
fmt.Fprintf(out, "\n")
|
||||
for i := 0; i < columnWidth-3; i++ {
|
||||
printValue(out, "")
|
||||
}
|
||||
printMetricsLine(out, &ResourceMetricsInfo{
|
||||
Name: "",
|
||||
Metrics: total,
|
||||
Available: v1.ResourceList{},
|
||||
})
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metricsutil
|
||||
|
||||
import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
)
|
||||
|
||||
type ResourceAdder struct {
|
||||
resources []corev1.ResourceName
|
||||
total corev1.ResourceList
|
||||
}
|
||||
|
||||
func NewResourceAdder(resources []corev1.ResourceName) *ResourceAdder {
|
||||
return &ResourceAdder{
|
||||
resources: resources,
|
||||
total: make(corev1.ResourceList),
|
||||
}
|
||||
}
|
||||
|
||||
// AddPodMetrics adds each pod metric to the total
|
||||
func (adder *ResourceAdder) AddPodMetrics(m *metricsapi.PodMetrics) {
|
||||
for _, c := range m.Containers {
|
||||
for _, res := range adder.resources {
|
||||
total := adder.total[res]
|
||||
total.Add(c.Usage[res])
|
||||
adder.total[res] = total
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
Copyright 2021 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metricsutil
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
metricsapi "k8s.io/metrics/pkg/apis/metrics"
|
||||
)
|
||||
|
||||
type NodeMetricsSorter struct {
|
||||
metrics []metricsapi.NodeMetrics
|
||||
sortBy string
|
||||
}
|
||||
|
||||
func (n *NodeMetricsSorter) Len() int {
|
||||
return len(n.metrics)
|
||||
}
|
||||
|
||||
func (n *NodeMetricsSorter) Swap(i, j int) {
|
||||
n.metrics[i], n.metrics[j] = n.metrics[j], n.metrics[i]
|
||||
}
|
||||
|
||||
func (n *NodeMetricsSorter) Less(i, j int) bool {
|
||||
switch n.sortBy {
|
||||
case "cpu":
|
||||
return n.metrics[i].Usage.Cpu().MilliValue() > n.metrics[j].Usage.Cpu().MilliValue()
|
||||
case "memory":
|
||||
return n.metrics[i].Usage.Memory().Value() > n.metrics[j].Usage.Memory().Value()
|
||||
default:
|
||||
return n.metrics[i].Name < n.metrics[j].Name
|
||||
}
|
||||
}
|
||||
|
||||
func NewNodeMetricsSorter(metrics []metricsapi.NodeMetrics, sortBy string) *NodeMetricsSorter {
|
||||
return &NodeMetricsSorter{
|
||||
metrics: metrics,
|
||||
sortBy: sortBy,
|
||||
}
|
||||
}
|
||||
|
||||
type PodMetricsSorter struct {
|
||||
metrics []metricsapi.PodMetrics
|
||||
sortBy string
|
||||
withNamespace bool
|
||||
podMetrics []v1.ResourceList
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Len() int {
|
||||
return len(p.metrics)
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Swap(i, j int) {
|
||||
p.metrics[i], p.metrics[j] = p.metrics[j], p.metrics[i]
|
||||
p.podMetrics[i], p.podMetrics[j] = p.podMetrics[j], p.podMetrics[i]
|
||||
}
|
||||
|
||||
func (p *PodMetricsSorter) Less(i, j int) bool {
|
||||
switch p.sortBy {
|
||||
case "cpu":
|
||||
return p.podMetrics[i].Cpu().MilliValue() > p.podMetrics[j].Cpu().MilliValue()
|
||||
case "memory":
|
||||
return p.podMetrics[i].Memory().Value() > p.podMetrics[j].Memory().Value()
|
||||
default:
|
||||
if p.withNamespace && p.metrics[i].Namespace != p.metrics[j].Namespace {
|
||||
return p.metrics[i].Namespace < p.metrics[j].Namespace
|
||||
}
|
||||
return p.metrics[i].Name < p.metrics[j].Name
|
||||
}
|
||||
}
|
||||
|
||||
func NewPodMetricsSorter(metrics []metricsapi.PodMetrics, withNamespace bool, sortBy string) *PodMetricsSorter {
|
||||
var podMetrics = make([]v1.ResourceList, len(metrics))
|
||||
if len(sortBy) > 0 {
|
||||
for i, v := range metrics {
|
||||
podMetrics[i] = getPodMetrics(&v)
|
||||
}
|
||||
}
|
||||
|
||||
return &PodMetricsSorter{
|
||||
metrics: metrics,
|
||||
sortBy: sortBy,
|
||||
withNamespace: withNamespace,
|
||||
podMetrics: podMetrics,
|
||||
}
|
||||
}
|
||||
|
||||
type ContainerMetricsSorter struct {
|
||||
metrics []metricsapi.ContainerMetrics
|
||||
sortBy string
|
||||
}
|
||||
|
||||
func (s *ContainerMetricsSorter) Len() int {
|
||||
return len(s.metrics)
|
||||
}
|
||||
|
||||
func (s *ContainerMetricsSorter) Swap(i, j int) {
|
||||
s.metrics[i], s.metrics[j] = s.metrics[j], s.metrics[i]
|
||||
}
|
||||
|
||||
func (s *ContainerMetricsSorter) Less(i, j int) bool {
|
||||
switch s.sortBy {
|
||||
case "cpu":
|
||||
return s.metrics[i].Usage.Cpu().MilliValue() > s.metrics[j].Usage.Cpu().MilliValue()
|
||||
case "memory":
|
||||
return s.metrics[i].Usage.Memory().Value() > s.metrics[j].Usage.Memory().Value()
|
||||
default:
|
||||
return s.metrics[i].Name < s.metrics[j].Name
|
||||
}
|
||||
}
|
||||
|
||||
func NewContainerMetricsSorter(metrics []metricsapi.ContainerMetrics, sortBy string) *ContainerMetricsSorter {
|
||||
return &ContainerMetricsSorter{
|
||||
metrics: metrics,
|
||||
sortBy: sortBy,
|
||||
}
|
||||
}
|
133
vendor/k8s.io/metrics/pkg/client/clientset/versioned/clientset.go
generated
vendored
Normal file
133
vendor/k8s.io/metrics/pkg/client/clientset/versioned/clientset.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package versioned
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
discovery "k8s.io/client-go/discovery"
|
||||
rest "k8s.io/client-go/rest"
|
||||
flowcontrol "k8s.io/client-go/util/flowcontrol"
|
||||
metricsv1alpha1 "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1"
|
||||
metricsv1beta1 "k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Discovery() discovery.DiscoveryInterface
|
||||
MetricsV1alpha1() metricsv1alpha1.MetricsV1alpha1Interface
|
||||
MetricsV1beta1() metricsv1beta1.MetricsV1beta1Interface
|
||||
}
|
||||
|
||||
// Clientset contains the clients for groups.
|
||||
type Clientset struct {
|
||||
*discovery.DiscoveryClient
|
||||
metricsV1alpha1 *metricsv1alpha1.MetricsV1alpha1Client
|
||||
metricsV1beta1 *metricsv1beta1.MetricsV1beta1Client
|
||||
}
|
||||
|
||||
// MetricsV1alpha1 retrieves the MetricsV1alpha1Client
|
||||
func (c *Clientset) MetricsV1alpha1() metricsv1alpha1.MetricsV1alpha1Interface {
|
||||
return c.metricsV1alpha1
|
||||
}
|
||||
|
||||
// MetricsV1beta1 retrieves the MetricsV1beta1Client
|
||||
func (c *Clientset) MetricsV1beta1() metricsv1beta1.MetricsV1beta1Interface {
|
||||
return c.metricsV1beta1
|
||||
}
|
||||
|
||||
// Discovery retrieves the DiscoveryClient
|
||||
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.DiscoveryClient
|
||||
}
|
||||
|
||||
// NewForConfig creates a new Clientset for the given config.
|
||||
// If config's RateLimiter is not set and QPS and Burst are acceptable,
|
||||
// NewForConfig will generate a rate-limiter in configShallowCopy.
|
||||
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
|
||||
// where httpClient was generated with rest.HTTPClientFor(c).
|
||||
func NewForConfig(c *rest.Config) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
|
||||
if configShallowCopy.UserAgent == "" {
|
||||
configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
// share the transport between all clients
|
||||
httpClient, err := rest.HTTPClientFor(&configShallowCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
}
|
||||
|
||||
// NewForConfigAndClient creates a new Clientset for the given config and http client.
|
||||
// Note the http client provided takes precedence over the configured transport values.
|
||||
// If config's RateLimiter is not set and QPS and Burst are acceptable,
|
||||
// NewForConfigAndClient will generate a rate-limiter in configShallowCopy.
|
||||
func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
|
||||
configShallowCopy := *c
|
||||
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
|
||||
if configShallowCopy.Burst <= 0 {
|
||||
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
|
||||
}
|
||||
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
|
||||
}
|
||||
|
||||
var cs Clientset
|
||||
var err error
|
||||
cs.metricsV1alpha1, err = metricsv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs.metricsV1beta1, err = metricsv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new Clientset for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *Clientset {
|
||||
cs, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return cs
|
||||
}
|
||||
|
||||
// New creates a new Clientset for the given RESTClient.
|
||||
func New(c rest.Interface) *Clientset {
|
||||
var cs Clientset
|
||||
cs.metricsV1alpha1 = metricsv1alpha1.New(c)
|
||||
cs.metricsV1beta1 = metricsv1beta1.New(c)
|
||||
|
||||
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
|
||||
return &cs
|
||||
}
|
20
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/doc.go
generated
vendored
Normal file
20
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
// This package has the automatically generated typed clients.
|
||||
package v1alpha1
|
23
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/generated_expansion.go
generated
vendored
Normal file
23
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/generated_expansion.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
type NodeMetricsExpansion interface{}
|
||||
|
||||
type PodMetricsExpansion interface{}
|
112
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/metrics_client.go
generated
vendored
Normal file
112
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/metrics_client.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha1 "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
|
||||
"k8s.io/metrics/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
type MetricsV1alpha1Interface interface {
|
||||
RESTClient() rest.Interface
|
||||
NodeMetricsesGetter
|
||||
PodMetricsesGetter
|
||||
}
|
||||
|
||||
// MetricsV1alpha1Client is used to interact with features provided by the metrics.k8s.io group.
|
||||
type MetricsV1alpha1Client struct {
|
||||
restClient rest.Interface
|
||||
}
|
||||
|
||||
func (c *MetricsV1alpha1Client) NodeMetricses() NodeMetricsInterface {
|
||||
return newNodeMetricses(c)
|
||||
}
|
||||
|
||||
func (c *MetricsV1alpha1Client) PodMetricses(namespace string) PodMetricsInterface {
|
||||
return newPodMetricses(c, namespace)
|
||||
}
|
||||
|
||||
// NewForConfig creates a new MetricsV1alpha1Client for the given config.
|
||||
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
|
||||
// where httpClient was generated with rest.HTTPClientFor(c).
|
||||
func NewForConfig(c *rest.Config) (*MetricsV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
httpClient, err := rest.HTTPClientFor(&config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewForConfigAndClient(&config, httpClient)
|
||||
}
|
||||
|
||||
// NewForConfigAndClient creates a new MetricsV1alpha1Client for the given config and http client.
|
||||
// Note the http client provided takes precedence over the configured transport values.
|
||||
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*MetricsV1alpha1Client, error) {
|
||||
config := *c
|
||||
if err := setConfigDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.RESTClientForConfigAndClient(&config, h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &MetricsV1alpha1Client{client}, nil
|
||||
}
|
||||
|
||||
// NewForConfigOrDie creates a new MetricsV1alpha1Client for the given config and
|
||||
// panics if there is an error in the config.
|
||||
func NewForConfigOrDie(c *rest.Config) *MetricsV1alpha1Client {
|
||||
client, err := NewForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
}
|
||||
|
||||
// New creates a new MetricsV1alpha1Client for the given RESTClient.
|
||||
func New(c rest.Interface) *MetricsV1alpha1Client {
|
||||
return &MetricsV1alpha1Client{c}
|
||||
}
|
||||
|
||||
func setConfigDefaults(config *rest.Config) error {
|
||||
gv := v1alpha1.SchemeGroupVersion
|
||||
config.GroupVersion = &gv
|
||||
config.APIPath = "/apis"
|
||||
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
|
||||
|
||||
if config.UserAgent == "" {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RESTClient returns a RESTClient that is used to communicate
|
||||
// with API server by this client implementation.
|
||||
func (c *MetricsV1alpha1Client) RESTClient() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
98
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/nodemetrics.go
generated
vendored
Normal file
98
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/nodemetrics.go
generated
vendored
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha1 "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
|
||||
scheme "k8s.io/metrics/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
// NodeMetricsesGetter has a method to return a NodeMetricsInterface.
|
||||
// A group's client should implement this interface.
|
||||
type NodeMetricsesGetter interface {
|
||||
NodeMetricses() NodeMetricsInterface
|
||||
}
|
||||
|
||||
// NodeMetricsInterface has methods to work with NodeMetrics resources.
|
||||
type NodeMetricsInterface interface {
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.NodeMetrics, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.NodeMetricsList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
NodeMetricsExpansion
|
||||
}
|
||||
|
||||
// nodeMetricses implements NodeMetricsInterface
|
||||
type nodeMetricses struct {
|
||||
client rest.Interface
|
||||
}
|
||||
|
||||
// newNodeMetricses returns a NodeMetricses
|
||||
func newNodeMetricses(c *MetricsV1alpha1Client) *nodeMetricses {
|
||||
return &nodeMetricses{
|
||||
client: c.RESTClient(),
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the nodeMetrics, and returns the corresponding nodeMetrics object, and an error if there is any.
|
||||
func (c *nodeMetricses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.NodeMetrics, err error) {
|
||||
result = &v1alpha1.NodeMetrics{}
|
||||
err = c.client.Get().
|
||||
Resource("nodes").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of NodeMetricses that match those selectors.
|
||||
func (c *nodeMetricses) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.NodeMetricsList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.NodeMetricsList{}
|
||||
err = c.client.Get().
|
||||
Resource("nodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested nodeMetricses.
|
||||
func (c *nodeMetricses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Resource("nodes").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
103
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/podmetrics.go
generated
vendored
Normal file
103
vendor/k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1/podmetrics.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Code generated by client-gen. DO NOT EDIT.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
v1alpha1 "k8s.io/metrics/pkg/apis/metrics/v1alpha1"
|
||||
scheme "k8s.io/metrics/pkg/client/clientset/versioned/scheme"
|
||||
)
|
||||
|
||||
// PodMetricsesGetter has a method to return a PodMetricsInterface.
|
||||
// A group's client should implement this interface.
|
||||
type PodMetricsesGetter interface {
|
||||
PodMetricses(namespace string) PodMetricsInterface
|
||||
}
|
||||
|
||||
// PodMetricsInterface has methods to work with PodMetrics resources.
|
||||
type PodMetricsInterface interface {
|
||||
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.PodMetrics, error)
|
||||
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.PodMetricsList, error)
|
||||
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
|
||||
PodMetricsExpansion
|
||||
}
|
||||
|
||||
// podMetricses implements PodMetricsInterface
|
||||
type podMetricses struct {
|
||||
client rest.Interface
|
||||
ns string
|
||||
}
|
||||
|
||||
// newPodMetricses returns a PodMetricses
|
||||
func newPodMetricses(c *MetricsV1alpha1Client, namespace string) *podMetricses {
|
||||
return &podMetricses{
|
||||
client: c.RESTClient(),
|
||||
ns: namespace,
|
||||
}
|
||||
}
|
||||
|
||||
// Get takes name of the podMetrics, and returns the corresponding podMetrics object, and an error if there is any.
|
||||
func (c *podMetricses) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.PodMetrics, err error) {
|
||||
result = &v1alpha1.PodMetrics{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("pods").
|
||||
Name(name).
|
||||
VersionedParams(&options, scheme.ParameterCodec).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// List takes label and field selectors, and returns the list of PodMetricses that match those selectors.
|
||||
func (c *podMetricses) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.PodMetricsList, err error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
result = &v1alpha1.PodMetricsList{}
|
||||
err = c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("pods").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the requested podMetricses.
|
||||
func (c *podMetricses) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
|
||||
var timeout time.Duration
|
||||
if opts.TimeoutSeconds != nil {
|
||||
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
|
||||
}
|
||||
opts.Watch = true
|
||||
return c.client.Get().
|
||||
Namespace(c.ns).
|
||||
Resource("pods").
|
||||
VersionedParams(&opts, scheme.ParameterCodec).
|
||||
Timeout(timeout).
|
||||
Watch(ctx)
|
||||
}
|
|
@ -1608,6 +1608,7 @@ k8s.io/kubectl/pkg/cmd/util/editor/crlf
|
|||
k8s.io/kubectl/pkg/cmd/util/podcmd
|
||||
k8s.io/kubectl/pkg/cmd/wait
|
||||
k8s.io/kubectl/pkg/describe
|
||||
k8s.io/kubectl/pkg/metricsutil
|
||||
k8s.io/kubectl/pkg/polymorphichelpers
|
||||
k8s.io/kubectl/pkg/rawhttp
|
||||
k8s.io/kubectl/pkg/scheme
|
||||
|
@ -1644,7 +1645,9 @@ k8s.io/metrics/pkg/apis/metrics
|
|||
k8s.io/metrics/pkg/apis/metrics/install
|
||||
k8s.io/metrics/pkg/apis/metrics/v1alpha1
|
||||
k8s.io/metrics/pkg/apis/metrics/v1beta1
|
||||
k8s.io/metrics/pkg/client/clientset/versioned
|
||||
k8s.io/metrics/pkg/client/clientset/versioned/scheme
|
||||
k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1alpha1
|
||||
k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1
|
||||
k8s.io/metrics/pkg/client/custom_metrics
|
||||
k8s.io/metrics/pkg/client/custom_metrics/scheme
|
||||
|
|
Loading…
Reference in New Issue