2016-08-11 15:24:22 +00:00
/ *
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 cmd
import (
"errors"
"github.com/spf13/cobra"
2016-11-29 20:48:53 +00:00
"github.com/spf13/pflag"
2017-10-31 08:15:32 +00:00
"k8s.io/api/core/v1"
2017-01-11 14:09:48 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
2017-11-15 19:41:04 +00:00
"k8s.io/client-go/discovery"
2018-08-03 11:47:05 +00:00
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
2016-10-07 22:24:42 +00:00
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
2016-09-08 15:50:53 +00:00
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
2018-05-08 13:02:34 +00:00
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
2016-09-08 15:50:53 +00:00
"k8s.io/kubernetes/pkg/kubectl/metricsutil"
2017-07-07 04:04:11 +00:00
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
2017-11-15 19:41:04 +00:00
metricsapi "k8s.io/metrics/pkg/apis/metrics"
metricsV1beta1api "k8s.io/metrics/pkg/apis/metrics/v1beta1"
2018-06-29 19:17:38 +00:00
metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned"
2016-08-11 15:24:22 +00:00
)
// TopNodeOptions contains all the options for running the top-node cli command.
type TopNodeOptions struct {
2016-11-29 20:48:53 +00:00
ResourceName string
Selector string
2018-08-03 11:47:05 +00:00
NodeClient corev1client . CoreV1Interface
2016-11-29 20:48:53 +00:00
HeapsterOptions HeapsterTopOptions
Client * metricsutil . HeapsterMetricsClient
Printer * metricsutil . TopCmdPrinter
2017-11-15 19:41:04 +00:00
DiscoveryClient discovery . DiscoveryInterface
MetricsClient metricsclientset . Interface
2018-05-08 13:02:34 +00:00
genericclioptions . IOStreams
2016-11-29 20:48:53 +00:00
}
type HeapsterTopOptions struct {
Namespace string
Service string
Scheme string
Port string
}
func ( o * HeapsterTopOptions ) Bind ( flags * pflag . FlagSet ) {
2017-08-15 18:59:56 +00:00
if len ( o . Namespace ) == 0 {
o . Namespace = metricsutil . DefaultHeapsterNamespace
}
if len ( o . Service ) == 0 {
o . Service = metricsutil . DefaultHeapsterService
}
if len ( o . Scheme ) == 0 {
o . Scheme = metricsutil . DefaultHeapsterScheme
}
if len ( o . Port ) == 0 {
o . Port = metricsutil . DefaultHeapsterPort
}
flags . StringVar ( & o . Namespace , "heapster-namespace" , o . Namespace , "Namespace Heapster service is located in" )
flags . StringVar ( & o . Service , "heapster-service" , o . Service , "Name of Heapster service" )
flags . StringVar ( & o . Scheme , "heapster-scheme" , o . Scheme , "Scheme (http or https) to connect to Heapster as" )
flags . StringVar ( & o . Port , "heapster-port" , o . Port , "Port name in service to use" )
2016-08-11 15:24:22 +00:00
}
var (
2017-03-15 03:49:10 +00:00
topNodeLong = templates . LongDesc ( i18n . T ( `
2016-08-11 15:24:22 +00:00
Display Resource ( CPU / Memory / Storage ) usage of nodes .
2017-03-15 03:49:10 +00:00
The top - node command allows you to see the resource consumption of nodes . ` ) )
2016-08-11 15:24:22 +00:00
2017-03-15 03:49:10 +00:00
topNodeExample = templates . Examples ( i18n . T ( `
2016-08-11 15:24:22 +00:00
# Show metrics for all nodes
kubectl top node
# Show metrics for a given node
2017-03-15 03:49:10 +00:00
kubectl top node NODE_NAME ` ) )
2016-08-11 15:24:22 +00:00
)
2018-05-08 13:02:34 +00:00
func NewCmdTopNode ( f cmdutil . Factory , o * TopNodeOptions , streams genericclioptions . IOStreams ) * cobra . Command {
if o == nil {
o = & TopNodeOptions {
IOStreams : streams ,
}
2017-08-15 18:59:56 +00:00
}
2016-08-11 15:24:22 +00:00
cmd := & cobra . Command {
2017-10-11 06:26:02 +00:00
Use : "node [NAME | -l label]" ,
DisableFlagsInUseLine : true ,
2017-01-25 01:00:32 +00:00
Short : i18n . T ( "Display Resource (CPU/Memory/Storage) usage of nodes" ) ,
2016-08-11 15:24:22 +00:00
Long : topNodeLong ,
Example : topNodeExample ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2018-05-08 13:02:34 +00:00
if err := o . Complete ( f , cmd , args ) ; err != nil {
2016-08-11 15:24:22 +00:00
cmdutil . CheckErr ( err )
}
2018-05-08 13:02:34 +00:00
if err := o . Validate ( ) ; err != nil {
2017-06-14 21:14:42 +00:00
cmdutil . CheckErr ( cmdutil . UsageErrorf ( cmd , "%v" , err ) )
2016-08-11 15:24:22 +00:00
}
2018-05-08 13:02:34 +00:00
if err := o . RunTopNode ( ) ; err != nil {
2016-08-11 15:24:22 +00:00
cmdutil . CheckErr ( err )
}
} ,
2016-12-24 16:25:08 +00:00
Aliases : [ ] string { "nodes" , "no" } ,
2016-08-11 15:24:22 +00:00
}
2018-05-08 13:02:34 +00:00
cmd . Flags ( ) . StringVarP ( & o . Selector , "selector" , "l" , o . Selector , "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)" )
o . HeapsterOptions . Bind ( cmd . Flags ( ) )
2016-08-11 15:24:22 +00:00
return cmd
}
2018-05-08 13:02:34 +00:00
func ( o * TopNodeOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
2016-08-11 15:24:22 +00:00
if len ( args ) == 1 {
o . ResourceName = args [ 0 ]
} else if len ( args ) > 1 {
2017-06-14 21:14:42 +00:00
return cmdutil . UsageErrorf ( cmd , "%s" , cmd . Use )
2016-08-11 15:24:22 +00:00
}
2017-10-31 08:15:32 +00:00
clientset , err := f . KubernetesClientSet ( )
2016-08-11 15:24:22 +00:00
if err != nil {
return err
}
2017-11-15 19:41:04 +00:00
o . DiscoveryClient = clientset . DiscoveryClient
2018-02-21 16:01:09 +00:00
2018-05-16 14:54:42 +00:00
config , err := f . ToRESTConfig ( )
2018-02-21 16:01:09 +00:00
if err != nil {
return err
}
o . MetricsClient , err = metricsclientset . NewForConfig ( config )
2017-11-15 19:41:04 +00:00
if err != nil {
return err
}
2017-11-12 11:00:21 +00:00
o . NodeClient = clientset . CoreV1 ( )
o . Client = metricsutil . NewHeapsterMetricsClient ( clientset . CoreV1 ( ) , o . HeapsterOptions . Namespace , o . HeapsterOptions . Scheme , o . HeapsterOptions . Service , o . HeapsterOptions . Port )
2017-11-15 19:41:04 +00:00
2018-05-08 13:02:34 +00:00
o . Printer = metricsutil . NewTopCmdPrinter ( o . Out )
2016-08-11 15:24:22 +00:00
return nil
}
func ( o * TopNodeOptions ) Validate ( ) error {
if len ( o . ResourceName ) > 0 && len ( o . Selector ) > 0 {
return errors . New ( "only one of NAME or --selector can be provided" )
}
return nil
}
func ( o TopNodeOptions ) RunTopNode ( ) error {
2016-08-26 09:44:14 +00:00
var err error
2017-11-15 19:41:04 +00:00
selector := labels . Everything ( )
2016-08-17 12:40:18 +00:00
if len ( o . Selector ) > 0 {
2017-11-15 19:41:04 +00:00
selector , err = labels . Parse ( o . Selector )
if err != nil {
return err
}
2016-08-17 12:40:18 +00:00
}
2017-11-15 19:41:04 +00:00
apiGroups , err := o . DiscoveryClient . ServerGroups ( )
2016-08-26 09:44:14 +00:00
if err != nil {
return err
}
2017-11-15 19:41:04 +00:00
metricsAPIAvailable := SupportedMetricsAPIVersionAvailable ( apiGroups )
metrics := & metricsapi . NodeMetricsList { }
if metricsAPIAvailable {
metrics , err = getNodeMetricsFromMetricsAPI ( o . MetricsClient , o . ResourceName , selector )
if err != nil {
return err
}
} else {
metrics , err = o . Client . GetNodeMetrics ( o . ResourceName , selector . String ( ) )
if err != nil {
return err
}
}
if len ( metrics . Items ) == 0 {
2016-09-12 15:59:31 +00:00
return errors . New ( "metrics not available yet" )
}
2016-08-26 09:44:14 +00:00
2017-10-31 08:15:32 +00:00
var nodes [ ] v1 . Node
2016-08-17 12:40:18 +00:00
if len ( o . ResourceName ) > 0 {
2016-12-07 13:26:33 +00:00
node , err := o . NodeClient . Nodes ( ) . Get ( o . ResourceName , metav1 . GetOptions { } )
2016-08-17 12:40:18 +00:00
if err != nil {
return err
}
nodes = append ( nodes , * node )
} else {
2017-01-22 03:36:02 +00:00
nodeList , err := o . NodeClient . Nodes ( ) . List ( metav1 . ListOptions {
2017-11-15 19:41:04 +00:00
LabelSelector : selector . String ( ) ,
2016-08-17 12:40:18 +00:00
} )
if err != nil {
return err
}
nodes = append ( nodes , nodeList . Items ... )
}
2017-10-31 08:15:32 +00:00
allocatable := make ( map [ string ] v1 . ResourceList )
2016-08-17 12:40:18 +00:00
for _ , n := range nodes {
allocatable [ n . Name ] = n . Status . Allocatable
}
2017-11-15 19:41:04 +00:00
return o . Printer . PrintNodeMetrics ( metrics . Items , allocatable )
}
func getNodeMetricsFromMetricsAPI ( metricsClient metricsclientset . Interface , resourceName string , selector labels . Selector ) ( * metricsapi . NodeMetricsList , error ) {
var err error
versionedMetrics := & metricsV1beta1api . NodeMetricsList { }
mc := metricsClient . Metrics ( )
nm := mc . NodeMetricses ( )
if resourceName != "" {
m , err := nm . Get ( resourceName , metav1 . GetOptions { } )
if err != nil {
return nil , err
}
versionedMetrics . Items = [ ] metricsV1beta1api . NodeMetrics { * m }
} else {
versionedMetrics , err = nm . List ( metav1 . ListOptions { LabelSelector : selector . String ( ) } )
if err != nil {
return nil , err
}
}
metrics := & metricsapi . NodeMetricsList { }
err = metricsV1beta1api . Convert_v1beta1_NodeMetricsList_To_metrics_NodeMetricsList ( versionedMetrics , metrics , nil )
if err != nil {
return nil , err
}
return metrics , nil
2016-08-11 15:24:22 +00:00
}