2014-10-06 01:24:19 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2014-10-06 01:24:19 +00:00
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 kubectl
import (
2015-05-22 21:33:29 +00:00
"bytes"
2015-10-28 11:23:33 +00:00
"encoding/json"
2014-10-06 01:24:19 +00:00
"fmt"
2014-11-14 19:56:41 +00:00
"io"
2016-02-16 19:43:45 +00:00
"net"
"net/url"
2015-02-26 18:50:12 +00:00
"reflect"
2014-11-14 19:56:41 +00:00
"sort"
2014-10-06 01:24:19 +00:00
"strings"
2014-12-16 22:20:51 +00:00
"time"
2014-10-06 01:24:19 +00:00
2015-08-05 22:05:17 +00:00
"github.com/golang/glog"
2016-05-05 17:30:50 +00:00
"k8s.io/kubernetes/federation/apis/federation"
fed_clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2015-07-30 21:33:48 +00:00
"k8s.io/kubernetes/pkg/api/errors"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api/resource"
2015-11-25 21:30:41 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2016-04-25 19:24:40 +00:00
"k8s.io/kubernetes/pkg/apis/apps"
2016-02-23 15:49:05 +00:00
"k8s.io/kubernetes/pkg/apis/autoscaling"
2016-02-19 06:56:21 +00:00
"k8s.io/kubernetes/pkg/apis/batch"
2015-10-09 22:04:41 +00:00
"k8s.io/kubernetes/pkg/apis/extensions"
2016-02-05 21:58:03 +00:00
clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
2015-08-13 19:01:50 +00:00
client "k8s.io/kubernetes/pkg/client/unversioned"
2016-03-01 22:15:55 +00:00
adapter "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/fieldpath"
"k8s.io/kubernetes/pkg/fields"
2015-09-01 23:35:32 +00:00
qosutil "k8s.io/kubernetes/pkg/kubelet/qos/util"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/types"
2015-10-19 21:08:35 +00:00
deploymentutil "k8s.io/kubernetes/pkg/util/deployment"
2015-11-18 10:37:23 +00:00
"k8s.io/kubernetes/pkg/util/intstr"
2015-09-09 17:45:01 +00:00
"k8s.io/kubernetes/pkg/util/sets"
2014-10-06 01:24:19 +00:00
)
2014-10-27 19:56:34 +00:00
// Describer generates output for the named resource or an error
2016-02-12 19:33:32 +00:00
// if the output could not be generated. Implementers typically
2015-02-26 18:50:12 +00:00
// abstract the retrieval of the named object from a remote server.
2014-10-27 19:56:34 +00:00
type Describer interface {
2016-04-20 17:27:32 +00:00
Describe ( namespace , name string , describerSettings DescriberSettings ) ( output string , err error )
}
// DescriberSettings holds display configuration for each object
// describer to control what is printed.
type DescriberSettings struct {
ShowEvents bool
2014-10-27 19:56:34 +00:00
}
2015-02-26 18:50:12 +00:00
// ObjectDescriber is an interface for displaying arbitrary objects with extra
// information. Use when an object is in hand (on disk, or already retrieved).
2016-02-12 19:33:32 +00:00
// Implementers may ignore the additional information passed on extra, or use it
2015-02-26 18:50:12 +00:00
// by default. ObjectDescribers may return ErrNoDescriber if no suitable describer
// is found.
type ObjectDescriber interface {
DescribeObject ( object interface { } , extra ... interface { } ) ( output string , err error )
}
// ErrNoDescriber is a structured error indicating the provided object or objects
// cannot be described.
type ErrNoDescriber struct {
Types [ ] string
}
// Error implements the error interface.
func ( e ErrNoDescriber ) Error ( ) string {
return fmt . Sprintf ( "no describer has been defined for %v" , e . Types )
}
2015-11-25 21:30:41 +00:00
func describerMap ( c * client . Client ) map [ unversioned . GroupKind ] Describer {
m := map [ unversioned . GroupKind ] Describer {
api . Kind ( "Pod" ) : & PodDescriber { c } ,
api . Kind ( "ReplicationController" ) : & ReplicationControllerDescriber { c } ,
api . Kind ( "Secret" ) : & SecretDescriber { c } ,
api . Kind ( "Service" ) : & ServiceDescriber { c } ,
api . Kind ( "ServiceAccount" ) : & ServiceAccountDescriber { c } ,
api . Kind ( "Node" ) : & NodeDescriber { c } ,
api . Kind ( "LimitRange" ) : & LimitRangeDescriber { c } ,
api . Kind ( "ResourceQuota" ) : & ResourceQuotaDescriber { c } ,
api . Kind ( "PersistentVolume" ) : & PersistentVolumeDescriber { c } ,
api . Kind ( "PersistentVolumeClaim" ) : & PersistentVolumeClaimDescriber { c } ,
api . Kind ( "Namespace" ) : & NamespaceDescriber { c } ,
api . Kind ( "Endpoints" ) : & EndpointsDescriber { c } ,
2016-01-15 16:48:36 +00:00
api . Kind ( "ConfigMap" ) : & ConfigMapDescriber { c } ,
2015-11-25 21:30:41 +00:00
2016-02-23 15:49:05 +00:00
extensions . Kind ( "ReplicaSet" ) : & ReplicaSetDescriber { c } ,
extensions . Kind ( "HorizontalPodAutoscaler" ) : & HorizontalPodAutoscalerDescriber { c } ,
2016-05-18 17:16:33 +00:00
extensions . Kind ( "NetworkPolicy" ) : & NetworkPolicyDescriber { c } ,
2016-02-23 15:49:05 +00:00
autoscaling . Kind ( "HorizontalPodAutoscaler" ) : & HorizontalPodAutoscalerDescriber { c } ,
extensions . Kind ( "DaemonSet" ) : & DaemonSetDescriber { c } ,
2016-03-01 22:15:55 +00:00
extensions . Kind ( "Deployment" ) : & DeploymentDescriber { adapter . FromUnversionedClient ( c ) } ,
2016-02-23 15:49:05 +00:00
extensions . Kind ( "Job" ) : & JobDescriber { c } ,
batch . Kind ( "Job" ) : & JobDescriber { c } ,
2016-04-25 19:24:40 +00:00
apps . Kind ( "PetSet" ) : & PetSetDescriber { c } ,
2016-02-23 15:49:05 +00:00
extensions . Kind ( "Ingress" ) : & IngressDescriber { c } ,
2015-03-17 17:01:33 +00:00
}
2015-11-25 21:30:41 +00:00
return m
2015-08-10 20:08:34 +00:00
}
2015-03-17 17:01:33 +00:00
// List of all resource types we can describe
func DescribableResources ( ) [ ] string {
keys := make ( [ ] string , 0 )
for k := range describerMap ( nil ) {
2015-11-25 21:30:41 +00:00
resource := strings . ToLower ( k . Kind )
2015-03-17 17:01:33 +00:00
keys = append ( keys , resource )
}
return keys
}
2014-10-27 19:56:34 +00:00
// Describer returns the default describe functions for each of the standard
// Kubernetes types.
2015-11-25 21:30:41 +00:00
func DescriberFor ( kind unversioned . GroupKind , c * client . Client ) ( Describer , bool ) {
f , ok := describerMap ( c ) [ kind ]
2015-08-10 20:08:34 +00:00
return f , ok
2014-10-27 19:56:34 +00:00
}
2015-02-26 18:50:12 +00:00
// DefaultObjectDescriber can describe the default Kubernetes objects.
var DefaultObjectDescriber ObjectDescriber
func init ( ) {
d := & Describers { }
err := d . Add (
describeLimitRange ,
describeQuota ,
describePod ,
describeService ,
describeReplicationController ,
2015-09-12 16:46:10 +00:00
describeDaemonSet ,
2015-02-26 18:50:12 +00:00
describeNode ,
2015-06-09 19:50:44 +00:00
describeNamespace ,
2015-02-26 18:50:12 +00:00
)
if err != nil {
glog . Fatalf ( "Cannot register describers: %v" , err )
}
DefaultObjectDescriber = d
}
2015-06-09 19:50:44 +00:00
// NamespaceDescriber generates information about a namespace
type NamespaceDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * NamespaceDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-06-09 19:50:44 +00:00
ns , err := d . Namespaces ( ) . Get ( name )
if err != nil {
return "" , err
}
2015-12-10 09:39:03 +00:00
resourceQuotaList , err := d . ResourceQuotas ( name ) . List ( api . ListOptions { } )
2015-06-09 19:50:44 +00:00
if err != nil {
return "" , err
}
2015-12-10 09:39:03 +00:00
limitRangeList , err := d . LimitRanges ( name ) . List ( api . ListOptions { } )
2015-06-09 19:50:44 +00:00
if err != nil {
return "" , err
}
return describeNamespace ( ns , resourceQuotaList , limitRangeList )
}
func describeNamespace ( namespace * api . Namespace , resourceQuotaList * api . ResourceQuotaList , limitRangeList * api . LimitRangeList ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , namespace . Name )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , namespace . Labels )
2015-06-09 19:50:44 +00:00
fmt . Fprintf ( out , "Status:\t%s\n" , string ( namespace . Status . Phase ) )
if resourceQuotaList != nil {
fmt . Fprintf ( out , "\n" )
DescribeResourceQuotas ( resourceQuotaList , out )
}
if limitRangeList != nil {
fmt . Fprintf ( out , "\n" )
DescribeLimitRanges ( limitRangeList , out )
}
return nil
} )
}
// DescribeLimitRanges merges a set of limit range items into a single tabular description
func DescribeLimitRanges ( limitRanges * api . LimitRangeList , w io . Writer ) {
if len ( limitRanges . Items ) == 0 {
fmt . Fprint ( w , "No resource limits.\n" )
return
}
2015-11-13 22:02:54 +00:00
fmt . Fprintf ( w , "Resource Limits\n Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n" )
fmt . Fprintf ( w , " ----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n" )
2015-06-09 19:50:44 +00:00
for _ , limitRange := range limitRanges . Items {
for i := range limitRange . Spec . Limits {
item := limitRange . Spec . Limits [ i ]
maxResources := item . Max
minResources := item . Min
2015-08-28 16:26:36 +00:00
defaultLimitResources := item . Default
defaultRequestResources := item . DefaultRequest
ratio := item . MaxLimitRequestRatio
2015-06-09 19:50:44 +00:00
set := map [ api . ResourceName ] bool { }
for k := range maxResources {
set [ k ] = true
}
for k := range minResources {
set [ k ] = true
}
2015-08-28 16:26:36 +00:00
for k := range defaultLimitResources {
set [ k ] = true
}
for k := range defaultRequestResources {
set [ k ] = true
}
for k := range ratio {
2015-06-09 19:50:44 +00:00
set [ k ] = true
}
for k := range set {
// if no value is set, we output -
maxValue := "-"
minValue := "-"
2015-08-28 16:26:36 +00:00
defaultLimitValue := "-"
defaultRequestValue := "-"
ratioValue := "-"
2015-06-09 19:50:44 +00:00
maxQuantity , maxQuantityFound := maxResources [ k ]
if maxQuantityFound {
maxValue = maxQuantity . String ( )
}
minQuantity , minQuantityFound := minResources [ k ]
if minQuantityFound {
minValue = minQuantity . String ( )
}
2015-08-28 16:26:36 +00:00
defaultLimitQuantity , defaultLimitQuantityFound := defaultLimitResources [ k ]
if defaultLimitQuantityFound {
defaultLimitValue = defaultLimitQuantity . String ( )
}
defaultRequestQuantity , defaultRequestQuantityFound := defaultRequestResources [ k ]
if defaultRequestQuantityFound {
defaultRequestValue = defaultRequestQuantity . String ( )
}
ratioQuantity , ratioQuantityFound := ratio [ k ]
if ratioQuantityFound {
ratioValue = ratioQuantity . String ( )
2015-06-09 19:50:44 +00:00
}
2015-08-28 16:26:36 +00:00
msg := " %s\t%v\t%v\t%v\t%v\t%v\t%v\n"
fmt . Fprintf ( w , msg , item . Type , k , minValue , maxValue , defaultRequestValue , defaultLimitValue , ratioValue )
2015-06-09 19:50:44 +00:00
}
}
}
}
// DescribeResourceQuotas merges a set of quota items into a single tabular description of all quotas
func DescribeResourceQuotas ( quotas * api . ResourceQuotaList , w io . Writer ) {
if len ( quotas . Items ) == 0 {
fmt . Fprint ( w , "No resource quota.\n" )
return
}
2016-02-22 16:16:00 +00:00
sort . Sort ( SortableResourceQuotas ( quotas . Items ) )
fmt . Fprint ( w , "Resource Quotas" )
2015-06-09 19:50:44 +00:00
for _ , q := range quotas . Items {
2016-02-22 16:16:00 +00:00
fmt . Fprintf ( w , "\n Name:\t%s\n" , q . Name )
if len ( q . Spec . Scopes ) > 0 {
2016-05-29 09:09:39 +00:00
scopes := make ( [ ] string , 0 , len ( q . Spec . Scopes ) )
2016-02-22 16:16:00 +00:00
for _ , scope := range q . Spec . Scopes {
scopes = append ( scopes , string ( scope ) )
}
sort . Strings ( scopes )
fmt . Fprintf ( w , " Scopes:\t%s\n" , strings . Join ( scopes , ", " ) )
for _ , scope := range scopes {
helpText := helpTextForResourceQuotaScope ( api . ResourceQuotaScope ( scope ) )
if len ( helpText ) > 0 {
fmt . Fprintf ( w , " * %s\n" , helpText )
}
}
}
fmt . Fprintf ( w , " Resource\tUsed\tHard\n" )
fmt . Fprint ( w , " --------\t---\t---\n" )
2016-05-29 09:09:39 +00:00
resources := make ( [ ] api . ResourceName , 0 , len ( q . Status . Hard ) )
2015-06-09 19:50:44 +00:00
for resource := range q . Status . Hard {
resources = append ( resources , resource )
2016-02-22 16:16:00 +00:00
}
sort . Sort ( SortableResourceNames ( resources ) )
for _ , resource := range resources {
2015-06-09 19:50:44 +00:00
hardQuantity := q . Status . Hard [ resource ]
usedQuantity := q . Status . Used [ resource ]
2016-02-22 16:16:00 +00:00
fmt . Fprintf ( w , " %s\t%s\t%s\n" , string ( resource ) , usedQuantity . String ( ) , hardQuantity . String ( ) )
2015-06-09 19:50:44 +00:00
}
}
}
2015-01-22 21:52:40 +00:00
// LimitRangeDescriber generates information about a limit range
type LimitRangeDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * LimitRangeDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-01-22 21:52:40 +00:00
lr := d . LimitRanges ( namespace )
limitRange , err := lr . Get ( name )
if err != nil {
return "" , err
}
2015-02-26 18:50:12 +00:00
return describeLimitRange ( limitRange )
}
2015-01-22 21:52:40 +00:00
2015-02-26 18:50:12 +00:00
func describeLimitRange ( limitRange * api . LimitRange ) ( string , error ) {
2015-01-22 21:52:40 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , limitRange . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , limitRange . Namespace )
2015-11-13 22:02:54 +00:00
fmt . Fprintf ( out , "Type\tResource\tMin\tMax\tDefault Request\tDefault Limit\tMax Limit/Request Ratio\n" )
fmt . Fprintf ( out , "----\t--------\t---\t---\t---------------\t-------------\t-----------------------\n" )
2015-01-23 04:17:04 +00:00
for i := range limitRange . Spec . Limits {
2015-01-22 21:52:40 +00:00
item := limitRange . Spec . Limits [ i ]
maxResources := item . Max
minResources := item . Min
2015-08-28 16:26:36 +00:00
defaultLimitResources := item . Default
defaultRequestResources := item . DefaultRequest
ratio := item . MaxLimitRequestRatio
2015-01-22 21:52:40 +00:00
set := map [ api . ResourceName ] bool { }
2015-01-23 04:17:04 +00:00
for k := range maxResources {
2015-01-22 21:52:40 +00:00
set [ k ] = true
}
2015-01-23 04:17:04 +00:00
for k := range minResources {
2015-01-22 21:52:40 +00:00
set [ k ] = true
}
2015-08-28 16:26:36 +00:00
for k := range defaultLimitResources {
set [ k ] = true
}
for k := range defaultRequestResources {
set [ k ] = true
}
for k := range ratio {
2015-03-31 14:12:57 +00:00
set [ k ] = true
}
2015-01-22 21:52:40 +00:00
2015-01-23 04:17:04 +00:00
for k := range set {
2015-01-22 21:52:40 +00:00
// if no value is set, we output -
maxValue := "-"
minValue := "-"
2015-08-28 16:26:36 +00:00
defaultLimitValue := "-"
defaultRequestValue := "-"
ratioValue := "-"
2015-01-22 21:52:40 +00:00
maxQuantity , maxQuantityFound := maxResources [ k ]
if maxQuantityFound {
maxValue = maxQuantity . String ( )
}
minQuantity , minQuantityFound := minResources [ k ]
if minQuantityFound {
minValue = minQuantity . String ( )
}
2015-08-28 16:26:36 +00:00
defaultLimitQuantity , defaultLimitQuantityFound := defaultLimitResources [ k ]
if defaultLimitQuantityFound {
defaultLimitValue = defaultLimitQuantity . String ( )
}
defaultRequestQuantity , defaultRequestQuantityFound := defaultRequestResources [ k ]
if defaultRequestQuantityFound {
defaultRequestValue = defaultRequestQuantity . String ( )
}
ratioQuantity , ratioQuantityFound := ratio [ k ]
if ratioQuantityFound {
ratioValue = ratioQuantity . String ( )
2015-03-31 14:12:57 +00:00
}
2015-08-28 16:26:36 +00:00
msg := "%v\t%v\t%v\t%v\t%v\t%v\t%v\n"
fmt . Fprintf ( out , msg , item . Type , k , minValue , maxValue , defaultRequestValue , defaultLimitValue , ratioValue )
2015-01-22 21:52:40 +00:00
}
}
return nil
} )
}
2015-01-23 17:38:30 +00:00
// ResourceQuotaDescriber generates information about a resource quota
type ResourceQuotaDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * ResourceQuotaDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-01-23 17:38:30 +00:00
rq := d . ResourceQuotas ( namespace )
resourceQuota , err := rq . Get ( name )
if err != nil {
return "" , err
}
2015-02-26 18:50:12 +00:00
return describeQuota ( resourceQuota )
}
2016-02-22 16:16:00 +00:00
func helpTextForResourceQuotaScope ( scope api . ResourceQuotaScope ) string {
switch scope {
case api . ResourceQuotaScopeTerminating :
return "Matches all pods that have an active deadline."
case api . ResourceQuotaScopeNotTerminating :
return "Matches all pods that do not have an active deadline."
case api . ResourceQuotaScopeBestEffort :
return "Matches all pods that have best effort quality of service."
case api . ResourceQuotaScopeNotBestEffort :
return "Matches all pods that do not have best effort quality of service."
default :
return ""
}
}
2015-02-26 18:50:12 +00:00
func describeQuota ( resourceQuota * api . ResourceQuota ) ( string , error ) {
2015-01-23 17:38:30 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , resourceQuota . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , resourceQuota . Namespace )
2016-02-22 16:16:00 +00:00
if len ( resourceQuota . Spec . Scopes ) > 0 {
2016-05-29 09:09:39 +00:00
scopes := make ( [ ] string , 0 , len ( resourceQuota . Spec . Scopes ) )
2016-02-22 16:16:00 +00:00
for _ , scope := range resourceQuota . Spec . Scopes {
scopes = append ( scopes , string ( scope ) )
}
sort . Strings ( scopes )
fmt . Fprintf ( out , "Scopes:\t%s\n" , strings . Join ( scopes , ", " ) )
for _ , scope := range scopes {
helpText := helpTextForResourceQuotaScope ( api . ResourceQuotaScope ( scope ) )
if len ( helpText ) > 0 {
fmt . Fprintf ( out , " * %s\n" , helpText )
}
}
}
2015-01-23 17:38:30 +00:00
fmt . Fprintf ( out , "Resource\tUsed\tHard\n" )
fmt . Fprintf ( out , "--------\t----\t----\n" )
2016-05-29 09:09:39 +00:00
resources := make ( [ ] api . ResourceName , 0 , len ( resourceQuota . Status . Hard ) )
2015-01-23 17:38:30 +00:00
for resource := range resourceQuota . Status . Hard {
resources = append ( resources , resource )
}
sort . Sort ( SortableResourceNames ( resources ) )
msg := "%v\t%v\t%v\n"
for i := range resources {
resource := resources [ i ]
hardQuantity := resourceQuota . Status . Hard [ resource ]
usedQuantity := resourceQuota . Status . Used [ resource ]
fmt . Fprintf ( out , msg , resource , usedQuantity . String ( ) , hardQuantity . String ( ) )
}
return nil
} )
}
2014-10-27 19:56:34 +00:00
// PodDescriber generates information about a pod and the replication controllers that
// create it.
type PodDescriber struct {
2014-11-14 01:42:50 +00:00
client . Interface
2014-10-27 19:56:34 +00:00
}
2016-04-20 17:27:32 +00:00
func ( d * PodDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2016-02-09 05:23:56 +00:00
pod , err := d . Pods ( namespace ) . Get ( name )
2014-10-06 01:24:19 +00:00
if err != nil {
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
eventsInterface := d . Events ( namespace )
selector := eventsInterface . GetFieldSelector ( & name , & namespace , nil , nil )
options := api . ListOptions { FieldSelector : selector }
events , err2 := eventsInterface . List ( options )
if describerSettings . ShowEvents && err2 == nil && len ( events . Items ) > 0 {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Pod '%v': error '%v', but found events.\n" , name , err )
DescribeEvents ( events , out )
return nil
} )
}
2014-11-14 19:56:41 +00:00
}
2014-10-06 01:24:19 +00:00
return "" , err
}
2014-11-24 23:17:28 +00:00
var events * api . EventList
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
if ref , err := api . GetReference ( pod ) ; err != nil {
glog . Errorf ( "Unable to construct reference to '%#v': %v" , pod , err )
} else {
ref . Kind = ""
events , _ = d . Events ( namespace ) . Search ( ref )
}
2014-11-24 23:17:28 +00:00
}
2014-11-14 19:56:41 +00:00
2016-02-09 05:23:56 +00:00
return describePod ( pod , events )
2015-02-26 18:50:12 +00:00
}
2016-02-09 05:23:56 +00:00
func describePod ( pod * api . Pod , events * api . EventList ) ( string , error ) {
2014-11-14 19:56:41 +00:00
return tabbedString ( func ( out io . Writer ) error {
2014-10-22 17:02:02 +00:00
fmt . Fprintf ( out , "Name:\t%s\n" , pod . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , pod . Namespace )
2015-05-22 23:40:57 +00:00
fmt . Fprintf ( out , "Node:\t%s\n" , pod . Spec . NodeName + "/" + pod . Status . HostIP )
2015-08-14 00:28:01 +00:00
if pod . Status . StartTime != nil {
fmt . Fprintf ( out , "Start Time:\t%s\n" , pod . Status . StartTime . Time . Format ( time . RFC1123Z ) )
}
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , pod . Labels )
2015-08-20 01:52:34 +00:00
if pod . DeletionTimestamp != nil {
fmt . Fprintf ( out , "Status:\tTerminating (expires %s)\n" , pod . DeletionTimestamp . Time . Format ( time . RFC1123Z ) )
2015-09-28 14:54:12 +00:00
fmt . Fprintf ( out , "Termination Grace Period:\t%ds\n" , * pod . DeletionGracePeriodSeconds )
2015-08-20 01:52:34 +00:00
} else {
fmt . Fprintf ( out , "Status:\t%s\n" , string ( pod . Status . Phase ) )
}
2016-02-16 23:43:59 +00:00
if len ( pod . Status . Reason ) > 0 {
fmt . Fprintf ( out , "Reason:\t%s\n" , pod . Status . Reason )
}
if len ( pod . Status . Message ) > 0 {
fmt . Fprintf ( out , "Message:\t%s\n" , pod . Status . Message )
}
2015-06-17 20:45:11 +00:00
fmt . Fprintf ( out , "IP:\t%s\n" , pod . Status . PodIP )
2015-10-28 11:23:33 +00:00
fmt . Fprintf ( out , "Controllers:\t%s\n" , printControllers ( pod . Annotations ) )
2016-05-02 22:08:15 +00:00
if len ( pod . Spec . InitContainers ) > 0 {
describeContainers ( "Init Containers" , pod . Spec . InitContainers , pod . Status . InitContainerStatuses , EnvValueRetriever ( pod ) , out , "" )
}
describeContainers ( "Containers" , pod . Spec . Containers , pod . Status . ContainerStatuses , EnvValueRetriever ( pod ) , out , "" )
2015-02-10 05:09:32 +00:00
if len ( pod . Status . Conditions ) > 0 {
2015-02-24 05:21:14 +00:00
fmt . Fprint ( out , "Conditions:\n Type\tStatus\n" )
2015-02-10 05:09:32 +00:00
for _ , c := range pod . Status . Conditions {
fmt . Fprintf ( out , " %v \t%v \n" ,
2015-02-24 05:21:14 +00:00
c . Type ,
2015-02-10 05:09:32 +00:00
c . Status )
}
}
2016-03-21 13:45:31 +00:00
describeVolumes ( pod . Spec . Volumes , out , "" )
2016-05-31 15:04:46 +00:00
fmt . Fprintf ( out , "QoS Tier:\t%s\n" , qosutil . GetPodQos ( pod ) )
2014-11-14 19:56:41 +00:00
if events != nil {
2015-04-21 04:24:12 +00:00
DescribeEvents ( events , out )
2014-11-14 19:56:41 +00:00
}
2014-10-06 01:24:19 +00:00
return nil
} )
}
2015-10-28 11:23:33 +00:00
func printControllers ( annotation map [ string ] string ) string {
value , ok := annotation [ "kubernetes.io/created-by" ]
if ok {
var r api . SerializedReference
err := json . Unmarshal ( [ ] byte ( value ) , & r )
if err == nil {
return fmt . Sprintf ( "%s/%s" , r . Reference . Kind , r . Reference . Name )
}
}
return "<none>"
}
2016-03-21 13:45:31 +00:00
// TODO: Do a better job at indenting, maybe by using a prefix writer
func describeVolumes ( volumes [ ] api . Volume , out io . Writer , space string ) {
2015-08-13 00:14:51 +00:00
if volumes == nil || len ( volumes ) == 0 {
2016-03-21 13:45:31 +00:00
fmt . Fprintf ( out , "%sNo volumes.\n" , space )
2015-08-13 00:14:51 +00:00
return
}
2016-03-21 13:45:31 +00:00
fmt . Fprintf ( out , "%sVolumes:\n" , space )
2015-08-13 00:14:51 +00:00
for _ , volume := range volumes {
2016-03-21 13:45:31 +00:00
nameIndent := ""
if len ( space ) > 0 {
nameIndent = " "
}
fmt . Fprintf ( out , " %s%v:\n" , nameIndent , volume . Name )
2015-08-13 00:14:51 +00:00
switch {
case volume . VolumeSource . HostPath != nil :
printHostPathVolumeSource ( volume . VolumeSource . HostPath , out )
case volume . VolumeSource . EmptyDir != nil :
printEmptyDirVolumeSource ( volume . VolumeSource . EmptyDir , out )
case volume . VolumeSource . GCEPersistentDisk != nil :
printGCEPersistentDiskVolumeSource ( volume . VolumeSource . GCEPersistentDisk , out )
case volume . VolumeSource . AWSElasticBlockStore != nil :
printAWSElasticBlockStoreVolumeSource ( volume . VolumeSource . AWSElasticBlockStore , out )
case volume . VolumeSource . GitRepo != nil :
printGitRepoVolumeSource ( volume . VolumeSource . GitRepo , out )
case volume . VolumeSource . Secret != nil :
printSecretVolumeSource ( volume . VolumeSource . Secret , out )
2016-02-22 17:17:56 +00:00
case volume . VolumeSource . ConfigMap != nil :
printConfigMapVolumeSource ( volume . VolumeSource . ConfigMap , out )
2015-08-13 00:14:51 +00:00
case volume . VolumeSource . NFS != nil :
printNFSVolumeSource ( volume . VolumeSource . NFS , out )
case volume . VolumeSource . ISCSI != nil :
printISCSIVolumeSource ( volume . VolumeSource . ISCSI , out )
case volume . VolumeSource . Glusterfs != nil :
printGlusterfsVolumeSource ( volume . VolumeSource . Glusterfs , out )
case volume . VolumeSource . PersistentVolumeClaim != nil :
printPersistentVolumeClaimVolumeSource ( volume . VolumeSource . PersistentVolumeClaim , out )
case volume . VolumeSource . RBD != nil :
printRBDVolumeSource ( volume . VolumeSource . RBD , out )
2016-02-27 20:38:29 +00:00
case volume . VolumeSource . DownwardAPI != nil :
printDownwardAPIVolumeSource ( volume . VolumeSource . DownwardAPI , out )
2015-08-13 00:14:51 +00:00
default :
2016-03-01 15:16:51 +00:00
fmt . Fprintf ( out , " <unknown>\n" )
2015-08-13 00:14:51 +00:00
}
}
}
func printHostPathVolumeSource ( hostPath * api . HostPathVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tHostPath (bare host directory volume)\n" +
" Path:\t%v\n" , hostPath . Path )
}
func printEmptyDirVolumeSource ( emptyDir * api . EmptyDirVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tEmptyDir (a temporary directory that shares a pod's lifetime)\n" +
" Medium:\t%v\n" , emptyDir . Medium )
}
func printGCEPersistentDiskVolumeSource ( gce * api . GCEPersistentDiskVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tGCEPersistentDisk (a Persistent Disk resource in Google Compute Engine)\n" +
" PDName:\t%v\n" +
" FSType:\t%v\n" +
" Partition:\t%v\n" +
" ReadOnly:\t%v\n" ,
gce . PDName , gce . FSType , gce . Partition , gce . ReadOnly )
}
func printAWSElasticBlockStoreVolumeSource ( aws * api . AWSElasticBlockStoreVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tAWSElasticBlockStore (a Persistent Disk resource in AWS)\n" +
" VolumeID:\t%v\n" +
" FSType:\t%v\n" +
" Partition:\t%v\n" +
" ReadOnly:\t%v\n" ,
aws . VolumeID , aws . FSType , aws . Partition , aws . ReadOnly )
}
func printGitRepoVolumeSource ( git * api . GitRepoVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tGitRepo (a volume that is pulled from git when the pod is created)\n" +
" Repository:\t%v\n" +
" Revision:\t%v\n" ,
git . Repository , git . Revision )
}
func printSecretVolumeSource ( secret * api . SecretVolumeSource , out io . Writer ) {
2016-02-22 17:17:56 +00:00
fmt . Fprintf ( out , " Type:\tSecret (a volume populated by a Secret)\n" +
2015-08-13 00:14:51 +00:00
" SecretName:\t%v\n" , secret . SecretName )
}
2016-02-22 17:17:56 +00:00
func printConfigMapVolumeSource ( configMap * api . ConfigMapVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tConfigMap (a volume populated by a ConfigMap)\n" +
" Name:\t%v\n" , configMap . Name )
}
2015-08-13 00:14:51 +00:00
func printNFSVolumeSource ( nfs * api . NFSVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tNFS (an NFS mount that lasts the lifetime of a pod)\n" +
" Server:\t%v\n" +
" Path:\t%v\n" +
" ReadOnly:\t%v\n" ,
nfs . Server , nfs . Path , nfs . ReadOnly )
}
func printISCSIVolumeSource ( iscsi * api . ISCSIVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tISCSI (an ISCSI Disk resource that is attached to a kubelet's host machine and then exposed to the pod)\n" +
" TargetPortal:\t%v\n" +
" IQN:\t%v\n" +
" Lun:\t%v\n" +
2015-11-05 19:06:20 +00:00
" ISCSIInterface\t%v\n" +
2015-08-13 00:14:51 +00:00
" FSType:\t%v\n" +
" ReadOnly:\t%v\n" ,
2015-11-05 19:06:20 +00:00
iscsi . TargetPortal , iscsi . IQN , iscsi . Lun , iscsi . ISCSIInterface , iscsi . FSType , iscsi . ReadOnly )
2015-08-13 00:14:51 +00:00
}
func printGlusterfsVolumeSource ( glusterfs * api . GlusterfsVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tGlusterfs (a Glusterfs mount on the host that shares a pod's lifetime)\n" +
" EndpointsName:\t%v\n" +
" Path:\t%v\n" +
" ReadOnly:\t%v\n" ,
glusterfs . EndpointsName , glusterfs . Path , glusterfs . ReadOnly )
}
func printPersistentVolumeClaimVolumeSource ( claim * api . PersistentVolumeClaimVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tPersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)\n" +
" ClaimName:\t%v\n" +
" ReadOnly:\t%v\n" ,
claim . ClaimName , claim . ReadOnly )
}
func printRBDVolumeSource ( rbd * api . RBDVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tRBD (a Rados Block Device mount on the host that shares a pod's lifetime)\n" +
" CephMonitors:\t%v\n" +
" RBDImage:\t%v\n" +
" FSType:\t%v\n" +
" RBDPool:\t%v\n" +
" RadosUser:\t%v\n" +
" Keyring:\t%v\n" +
" SecretRef:\t%v\n" +
" ReadOnly:\t%v\n" ,
rbd . CephMonitors , rbd . RBDImage , rbd . FSType , rbd . RBDPool , rbd . RadosUser , rbd . Keyring , rbd . SecretRef , rbd . ReadOnly )
}
2016-02-27 20:38:29 +00:00
func printDownwardAPIVolumeSource ( d * api . DownwardAPIVolumeSource , out io . Writer ) {
fmt . Fprintf ( out , " Type:\tDownwardAPI (a volume populated by information about the pod)\n Items:\n" )
for _ , mapping := range d . Items {
2016-05-23 22:08:22 +00:00
if mapping . FieldRef != nil {
fmt . Fprintf ( out , " %v -> %v\n" , mapping . FieldRef . FieldPath , mapping . Path )
}
if mapping . ResourceFieldRef != nil {
fmt . Fprintf ( out , " %v -> %v\n" , mapping . ResourceFieldRef . Resource , mapping . Path )
}
2016-02-27 20:38:29 +00:00
}
}
2015-03-26 19:50:36 +00:00
type PersistentVolumeDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * PersistentVolumeDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-03-26 19:50:36 +00:00
c := d . PersistentVolumes ( )
pv , err := c . Get ( name )
if err != nil {
return "" , err
}
2015-08-11 03:55:15 +00:00
storage := pv . Spec . Capacity [ api . ResourceStorage ]
2016-06-15 12:17:02 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( pv )
}
2015-03-26 19:50:36 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , pv . Name )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , pv . Labels )
2015-05-22 12:40:43 +00:00
fmt . Fprintf ( out , "Status:\t%s\n" , pv . Status . Phase )
2015-05-02 10:49:19 +00:00
if pv . Spec . ClaimRef != nil {
2015-05-22 12:40:43 +00:00
fmt . Fprintf ( out , "Claim:\t%s\n" , pv . Spec . ClaimRef . Namespace + "/" + pv . Spec . ClaimRef . Name )
2015-05-02 10:49:19 +00:00
} else {
2015-05-22 12:40:43 +00:00
fmt . Fprintf ( out , "Claim:\t%s\n" , "" )
2015-05-02 10:49:19 +00:00
}
2015-08-08 01:52:23 +00:00
fmt . Fprintf ( out , "Reclaim Policy:\t%v\n" , pv . Spec . PersistentVolumeReclaimPolicy )
2015-07-13 19:10:04 +00:00
fmt . Fprintf ( out , "Access Modes:\t%s\n" , api . GetAccessModesAsString ( pv . Spec . AccessModes ) )
2015-08-11 03:55:15 +00:00
fmt . Fprintf ( out , "Capacity:\t%s\n" , storage . String ( ) )
2015-08-08 01:52:23 +00:00
fmt . Fprintf ( out , "Message:\t%s\n" , pv . Status . Message )
2015-08-14 15:28:16 +00:00
fmt . Fprintf ( out , "Source:\n" )
switch {
case pv . Spec . HostPath != nil :
printHostPathVolumeSource ( pv . Spec . HostPath , out )
case pv . Spec . GCEPersistentDisk != nil :
printGCEPersistentDiskVolumeSource ( pv . Spec . GCEPersistentDisk , out )
case pv . Spec . AWSElasticBlockStore != nil :
printAWSElasticBlockStoreVolumeSource ( pv . Spec . AWSElasticBlockStore , out )
case pv . Spec . NFS != nil :
printNFSVolumeSource ( pv . Spec . NFS , out )
case pv . Spec . ISCSI != nil :
printISCSIVolumeSource ( pv . Spec . ISCSI , out )
case pv . Spec . Glusterfs != nil :
printGlusterfsVolumeSource ( pv . Spec . Glusterfs , out )
case pv . Spec . RBD != nil :
printRBDVolumeSource ( pv . Spec . RBD , out )
}
2016-06-15 12:17:02 +00:00
if events != nil {
DescribeEvents ( events , out )
}
2015-03-26 19:50:36 +00:00
return nil
} )
}
type PersistentVolumeClaimDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * PersistentVolumeClaimDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-03-26 19:50:36 +00:00
c := d . PersistentVolumeClaims ( namespace )
2015-05-13 00:44:29 +00:00
pvc , err := c . Get ( name )
2015-03-26 19:50:36 +00:00
if err != nil {
return "" , err
}
2015-08-11 03:55:15 +00:00
storage := pvc . Spec . Resources . Requests [ api . ResourceStorage ]
capacity := ""
accessModes := ""
if pvc . Spec . VolumeName != "" {
2015-07-13 19:10:04 +00:00
accessModes = api . GetAccessModesAsString ( pvc . Status . AccessModes )
2015-08-11 03:55:15 +00:00
storage = pvc . Status . Capacity [ api . ResourceStorage ]
capacity = storage . String ( )
}
2016-05-17 12:55:14 +00:00
events , _ := d . Events ( namespace ) . Search ( pvc )
2015-03-26 19:50:36 +00:00
return tabbedString ( func ( out io . Writer ) error {
2015-05-13 00:44:29 +00:00
fmt . Fprintf ( out , "Name:\t%s\n" , pvc . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , pvc . Namespace )
2015-08-08 01:52:23 +00:00
fmt . Fprintf ( out , "Status:\t%v\n" , pvc . Status . Phase )
fmt . Fprintf ( out , "Volume:\t%s\n" , pvc . Spec . VolumeName )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , pvc . Labels )
2015-08-11 03:55:15 +00:00
fmt . Fprintf ( out , "Capacity:\t%s\n" , capacity )
fmt . Fprintf ( out , "Access Modes:\t%s\n" , accessModes )
2016-05-17 12:55:14 +00:00
if events != nil {
DescribeEvents ( events , out )
}
2015-03-26 19:50:36 +00:00
return nil
} )
}
2016-03-21 13:45:31 +00:00
// TODO: Do a better job at indenting, maybe by using a prefix writer
2016-05-02 22:08:15 +00:00
func describeContainers ( label string , containers [ ] api . Container , containerStatuses [ ] api . ContainerStatus , resolverFn EnvVarResolverFunc , out io . Writer , space string ) {
2015-06-05 04:49:01 +00:00
statuses := map [ string ] api . ContainerStatus { }
2016-02-16 19:43:45 +00:00
for _ , status := range containerStatuses {
2015-06-05 04:49:01 +00:00
statuses [ status . Name ] = status
}
2016-05-02 22:08:15 +00:00
if len ( containers ) == 0 {
fmt . Fprintf ( out , "%s%s: <none>\n" , space , label )
} else {
fmt . Fprintf ( out , "%s%s:\n" , space , label )
}
2016-02-16 19:43:45 +00:00
for _ , container := range containers {
2016-02-22 08:16:34 +00:00
status , ok := statuses [ container . Name ]
2016-03-21 13:45:31 +00:00
nameIndent := ""
if len ( space ) > 0 {
nameIndent = " "
}
fmt . Fprintf ( out , " %s%v:\n" , nameIndent , container . Name )
2016-02-22 08:16:34 +00:00
if ok {
fmt . Fprintf ( out , " Container ID:\t%s\n" , status . ContainerID )
}
2015-04-02 15:42:19 +00:00
fmt . Fprintf ( out , " Image:\t%s\n" , container . Image )
2016-02-22 08:16:34 +00:00
if ok {
fmt . Fprintf ( out , " Image ID:\t%s\n" , status . ImageID )
}
2016-02-22 11:27:58 +00:00
portString := describeContainerPorts ( container . Ports )
if strings . Contains ( portString , "," ) {
fmt . Fprintf ( out , " Ports:\t%s\n" , portString )
} else {
fmt . Fprintf ( out , " Port:\t%s\n" , portString )
}
2015-06-05 04:49:01 +00:00
2015-10-11 19:14:06 +00:00
if len ( container . Command ) > 0 {
fmt . Fprintf ( out , " Command:\n" )
for _ , c := range container . Command {
fmt . Fprintf ( out , " %s\n" , c )
}
}
if len ( container . Args ) > 0 {
fmt . Fprintf ( out , " Args:\n" )
for _ , arg := range container . Args {
fmt . Fprintf ( out , " %s\n" , arg )
}
}
2016-05-21 21:47:47 +00:00
resources := container . Resources
if len ( resources . Limits ) > 0 {
2015-06-05 04:49:01 +00:00
fmt . Fprintf ( out , " Limits:\n" )
}
2016-05-21 21:47:47 +00:00
for _ , name := range SortedResourceNames ( resources . Limits ) {
quantity := resources . Limits [ name ]
2015-06-05 04:49:01 +00:00
fmt . Fprintf ( out , " %s:\t%s\n" , name , quantity . String ( ) )
}
2016-05-21 21:47:47 +00:00
if len ( resources . Requests ) > 0 {
2015-08-14 00:28:01 +00:00
fmt . Fprintf ( out , " Requests:\n" )
}
2016-05-21 21:47:47 +00:00
for _ , name := range SortedResourceNames ( resources . Requests ) {
quantity := resources . Requests [ name ]
2015-08-14 00:28:01 +00:00
fmt . Fprintf ( out , " %s:\t%s\n" , name , quantity . String ( ) )
}
2016-02-22 08:16:34 +00:00
if ok {
describeStatus ( "State" , status . State , out )
if status . LastTerminationState . Terminated != nil {
describeStatus ( "Last State" , status . LastTerminationState , out )
}
fmt . Fprintf ( out , " Ready:\t%v\n" , printBool ( status . Ready ) )
fmt . Fprintf ( out , " Restart Count:\t%d\n" , status . RestartCount )
2015-04-02 15:42:19 +00:00
}
2016-02-16 19:43:45 +00:00
if container . LivenessProbe != nil {
probe := DescribeProbe ( container . LivenessProbe )
fmt . Fprintf ( out , " Liveness:\t%s\n" , probe )
}
if container . ReadinessProbe != nil {
probe := DescribeProbe ( container . ReadinessProbe )
fmt . Fprintf ( out , " Readiness:\t%s\n" , probe )
}
2016-03-21 13:45:31 +00:00
none := ""
if len ( container . Env ) == 0 {
none = "\t<none>"
}
fmt . Fprintf ( out , " Environment Variables:%s\n" , none )
2015-07-04 14:31:15 +00:00
for _ , e := range container . Env {
2016-04-05 21:36:22 +00:00
if e . ValueFrom == nil {
fmt . Fprintf ( out , " %s:\t%s\n" , e . Name , e . Value )
continue
}
switch {
case e . ValueFrom . FieldRef != nil :
2016-02-16 19:43:45 +00:00
var valueFrom string
if resolverFn != nil {
valueFrom = resolverFn ( e )
}
2015-07-04 14:31:15 +00:00
fmt . Fprintf ( out , " %s:\t%s (%s:%s)\n" , e . Name , valueFrom , e . ValueFrom . FieldRef . APIVersion , e . ValueFrom . FieldRef . FieldPath )
2016-05-23 22:08:22 +00:00
case e . ValueFrom . ResourceFieldRef != nil :
valueFrom , err := fieldpath . ExtractContainerResourceValue ( e . ValueFrom . ResourceFieldRef , & container )
if err != nil {
valueFrom = ""
}
fmt . Fprintf ( out , " %s:\t%s (%s)\n" , e . Name , valueFrom , e . ValueFrom . ResourceFieldRef . Resource )
2016-04-05 21:36:22 +00:00
case e . ValueFrom . SecretKeyRef != nil :
fmt . Fprintf ( out , " %s:\t<set to the key '%s' in secret '%s'>\n" , e . Name , e . ValueFrom . SecretKeyRef . Key , e . ValueFrom . SecretKeyRef . Name )
case e . ValueFrom . ConfigMapKeyRef != nil :
fmt . Fprintf ( out , " %s:\t<set to the key '%s' of config map '%s'>\n" , e . Name , e . ValueFrom . ConfigMapKeyRef . Key , e . ValueFrom . ConfigMapKeyRef . Name )
2015-07-04 14:31:15 +00:00
}
}
2015-04-02 15:42:19 +00:00
}
}
2016-02-22 11:27:58 +00:00
func describeContainerPorts ( cPorts [ ] api . ContainerPort ) string {
2016-05-29 09:09:39 +00:00
ports := make ( [ ] string , 0 , len ( cPorts ) )
2016-02-22 11:27:58 +00:00
for _ , cPort := range cPorts {
ports = append ( ports , fmt . Sprintf ( "%d/%s" , cPort . ContainerPort , cPort . Protocol ) )
}
return strings . Join ( ports , ", " )
}
2016-02-16 19:43:45 +00:00
// DescribeProbe is exported for consumers in other API groups that have probes
func DescribeProbe ( probe * api . Probe ) string {
attrs := fmt . Sprintf ( "delay=%ds timeout=%ds period=%ds #success=%d #failure=%d" , probe . InitialDelaySeconds , probe . TimeoutSeconds , probe . PeriodSeconds , probe . SuccessThreshold , probe . FailureThreshold )
switch {
case probe . Exec != nil :
return fmt . Sprintf ( "exec %v %s" , probe . Exec . Command , attrs )
case probe . HTTPGet != nil :
url := & url . URL { }
url . Scheme = strings . ToLower ( string ( probe . HTTPGet . Scheme ) )
if len ( probe . HTTPGet . Port . String ( ) ) > 0 {
url . Host = net . JoinHostPort ( probe . HTTPGet . Host , probe . HTTPGet . Port . String ( ) )
} else {
url . Host = probe . HTTPGet . Host
}
url . Path = probe . HTTPGet . Path
return fmt . Sprintf ( "http-get %s %s" , url . String ( ) , attrs )
case probe . TCPSocket != nil :
return fmt . Sprintf ( "tcp-socket :%s %s" , probe . TCPSocket . Port . String ( ) , attrs )
2015-07-04 14:31:15 +00:00
}
2016-02-16 19:43:45 +00:00
return fmt . Sprintf ( "unknown %s" , attrs )
}
2015-07-04 14:31:15 +00:00
2016-02-16 19:43:45 +00:00
type EnvVarResolverFunc func ( e api . EnvVar ) string
// EnvValueFrom is exported for use by describers in other packages
func EnvValueRetriever ( pod * api . Pod ) EnvVarResolverFunc {
return func ( e api . EnvVar ) string {
internalFieldPath , _ , err := api . Scheme . ConvertFieldLabel ( e . ValueFrom . FieldRef . APIVersion , "Pod" , e . ValueFrom . FieldRef . FieldPath , "" )
if err != nil {
return "" // pod validation should catch this on create
}
valueFrom , err := fieldpath . ExtractFieldPathAsString ( pod , internalFieldPath )
if err != nil {
return "" // pod validation should catch this on create
}
2015-07-04 14:31:15 +00:00
2016-02-16 19:43:45 +00:00
return valueFrom
}
2015-07-04 14:31:15 +00:00
}
2015-08-07 01:45:20 +00:00
func describeStatus ( stateName string , state api . ContainerState , out io . Writer ) {
switch {
case state . Running != nil :
fmt . Fprintf ( out , " %s:\tRunning\n" , stateName )
fmt . Fprintf ( out , " Started:\t%v\n" , state . Running . StartedAt . Time . Format ( time . RFC1123Z ) )
case state . Waiting != nil :
fmt . Fprintf ( out , " %s:\tWaiting\n" , stateName )
if state . Waiting . Reason != "" {
fmt . Fprintf ( out , " Reason:\t%s\n" , state . Waiting . Reason )
}
case state . Terminated != nil :
fmt . Fprintf ( out , " %s:\tTerminated\n" , stateName )
if state . Terminated . Reason != "" {
fmt . Fprintf ( out , " Reason:\t%s\n" , state . Terminated . Reason )
}
if state . Terminated . Message != "" {
fmt . Fprintf ( out , " Message:\t%s\n" , state . Terminated . Message )
}
fmt . Fprintf ( out , " Exit Code:\t%d\n" , state . Terminated . ExitCode )
if state . Terminated . Signal > 0 {
fmt . Fprintf ( out , " Signal:\t%d\n" , state . Terminated . Signal )
}
fmt . Fprintf ( out , " Started:\t%s\n" , state . Terminated . StartedAt . Time . Format ( time . RFC1123Z ) )
fmt . Fprintf ( out , " Finished:\t%s\n" , state . Terminated . FinishedAt . Time . Format ( time . RFC1123Z ) )
default :
fmt . Fprintf ( out , " %s:\tWaiting\n" , stateName )
}
}
2015-04-02 15:42:19 +00:00
func printBool ( value bool ) string {
if value {
return "True"
}
return "False"
}
2014-10-27 19:56:34 +00:00
// ReplicationControllerDescriber generates information about a replication controller
// and the pods it has created.
type ReplicationControllerDescriber struct {
2014-11-14 01:42:50 +00:00
client . Interface
2014-10-27 19:56:34 +00:00
}
2016-04-20 17:27:32 +00:00
func ( d * ReplicationControllerDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2014-11-14 01:42:50 +00:00
rc := d . ReplicationControllers ( namespace )
pc := d . Pods ( namespace )
2014-10-06 01:24:19 +00:00
2014-10-27 19:56:34 +00:00
controller , err := rc . Get ( name )
if err != nil {
return "" , err
}
2015-10-26 06:11:09 +00:00
running , waiting , succeeded , failed , err := getPodStatusForController ( pc , labels . SelectorFromSet ( controller . Spec . Selector ) )
2014-10-06 01:24:19 +00:00
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( controller )
}
2014-11-14 19:56:41 +00:00
2015-02-26 18:50:12 +00:00
return describeReplicationController ( controller , events , running , waiting , succeeded , failed )
}
func describeReplicationController ( controller * api . ReplicationController , events * api . EventList , running , waiting , succeeded , failed int ) ( string , error ) {
2014-11-14 19:56:41 +00:00
return tabbedString ( func ( out io . Writer ) error {
2014-10-22 17:02:02 +00:00
fmt . Fprintf ( out , "Name:\t%s\n" , controller . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , controller . Namespace )
2015-02-26 18:50:12 +00:00
if controller . Spec . Template != nil {
fmt . Fprintf ( out , "Image(s):\t%s\n" , makeImageList ( & controller . Spec . Template . Spec ) )
} else {
2016-03-01 15:16:51 +00:00
fmt . Fprintf ( out , "Image(s):\t%s\n" , "<unset>" )
2015-02-26 18:50:12 +00:00
}
2015-08-16 09:33:35 +00:00
fmt . Fprintf ( out , "Selector:\t%s\n" , labels . FormatLabels ( controller . Spec . Selector ) )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , controller . Labels )
2014-11-07 02:09:46 +00:00
fmt . Fprintf ( out , "Replicas:\t%d current / %d desired\n" , controller . Status . Replicas , controller . Spec . Replicas )
2014-11-05 15:22:54 +00:00
fmt . Fprintf ( out , "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n" , running , waiting , succeeded , failed )
2015-08-13 00:14:51 +00:00
if controller . Spec . Template != nil {
2016-03-21 13:45:31 +00:00
describeVolumes ( controller . Spec . Template . Spec . Volumes , out , "" )
2015-08-13 00:14:51 +00:00
}
2014-11-14 19:56:41 +00:00
if events != nil {
2015-04-21 04:24:12 +00:00
DescribeEvents ( events , out )
2014-11-14 19:56:41 +00:00
}
2014-10-06 01:24:19 +00:00
return nil
} )
}
2016-03-21 13:45:31 +00:00
func DescribePodTemplate ( template * api . PodTemplateSpec , out io . Writer ) {
if template == nil {
fmt . Fprintf ( out , " <unset>" )
return
}
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , " Labels" , template . Labels )
2016-03-21 13:45:31 +00:00
if len ( template . Annotations ) > 0 {
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , " Annotations" , template . Annotations )
2016-03-21 13:45:31 +00:00
}
if len ( template . Spec . ServiceAccountName ) > 0 {
fmt . Fprintf ( out , " Service Account:\t%s\n" , template . Spec . ServiceAccountName )
}
2016-05-02 22:08:15 +00:00
if len ( template . Spec . InitContainers ) > 0 {
describeContainers ( "Init Containers" , template . Spec . InitContainers , nil , nil , out , " " )
}
describeContainers ( "Containers" , template . Spec . Containers , nil , nil , out , " " )
2016-03-21 13:45:31 +00:00
describeVolumes ( template . Spec . Volumes , out , " " )
2016-01-20 23:48:52 +00:00
}
2016-02-09 05:23:56 +00:00
// ReplicaSetDescriber generates information about a ReplicaSet and the pods it has created.
type ReplicaSetDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * ReplicaSetDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2016-02-09 05:23:56 +00:00
rsc := d . Extensions ( ) . ReplicaSets ( namespace )
pc := d . Pods ( namespace )
rs , err := rsc . Get ( name )
if err != nil {
return "" , err
}
selector , err := unversioned . LabelSelectorAsSelector ( rs . Spec . Selector )
if err != nil {
return "" , err
}
running , waiting , succeeded , failed , err := getPodStatusForController ( pc , selector )
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( rs )
}
2016-02-09 05:23:56 +00:00
return describeReplicaSet ( rs , events , running , waiting , succeeded , failed )
}
func describeReplicaSet ( rs * extensions . ReplicaSet , events * api . EventList , running , waiting , succeeded , failed int ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , rs . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , rs . Namespace )
2016-03-09 21:11:13 +00:00
fmt . Fprintf ( out , "Image(s):\t%s\n" , makeImageList ( & rs . Spec . Template . Spec ) )
2016-02-09 05:23:56 +00:00
fmt . Fprintf ( out , "Selector:\t%s\n" , unversioned . FormatLabelSelector ( rs . Spec . Selector ) )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , rs . Labels )
2016-02-09 05:23:56 +00:00
fmt . Fprintf ( out , "Replicas:\t%d current / %d desired\n" , rs . Status . Replicas , rs . Spec . Replicas )
fmt . Fprintf ( out , "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n" , running , waiting , succeeded , failed )
2016-03-21 13:45:31 +00:00
describeVolumes ( rs . Spec . Template . Spec . Volumes , out , "" )
2016-02-09 05:23:56 +00:00
if events != nil {
DescribeEvents ( events , out )
}
return nil
} )
}
2015-08-21 14:23:12 +00:00
// JobDescriber generates information about a job and the pods it has created.
type JobDescriber struct {
client * client . Client
}
2016-04-20 17:27:32 +00:00
func ( d * JobDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-10-12 18:18:50 +00:00
job , err := d . client . Extensions ( ) . Jobs ( namespace ) . Get ( name )
2015-08-21 14:23:12 +00:00
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . client . Events ( namespace ) . Search ( job )
}
2015-08-21 14:23:12 +00:00
return describeJob ( job , events )
}
2016-04-18 15:44:19 +00:00
func describeJob ( job * batch . Job , events * api . EventList ) ( string , error ) {
2015-08-21 14:23:12 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , job . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , job . Namespace )
2015-09-25 19:07:06 +00:00
fmt . Fprintf ( out , "Image(s):\t%s\n" , makeImageList ( & job . Spec . Template . Spec ) )
2016-02-02 05:34:42 +00:00
selector , _ := unversioned . LabelSelectorAsSelector ( job . Spec . Selector )
2015-10-14 18:04:33 +00:00
fmt . Fprintf ( out , "Selector:\t%s\n" , selector )
2015-09-21 20:55:19 +00:00
fmt . Fprintf ( out , "Parallelism:\t%d\n" , * job . Spec . Parallelism )
2015-12-14 23:26:16 +00:00
if job . Spec . Completions != nil {
fmt . Fprintf ( out , "Completions:\t%d\n" , * job . Spec . Completions )
} else {
2016-03-01 15:16:51 +00:00
fmt . Fprintf ( out , "Completions:\t<unset>\n" )
2015-12-14 23:26:16 +00:00
}
2015-11-26 15:54:04 +00:00
if job . Status . StartTime != nil {
fmt . Fprintf ( out , "Start Time:\t%s\n" , job . Status . StartTime . Time . Format ( time . RFC1123Z ) )
}
if job . Spec . ActiveDeadlineSeconds != nil {
fmt . Fprintf ( out , "Active Deadline Seconds:\t%ds\n" , * job . Spec . ActiveDeadlineSeconds )
}
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , job . Labels )
2015-10-08 17:33:39 +00:00
fmt . Fprintf ( out , "Pods Statuses:\t%d Running / %d Succeeded / %d Failed\n" , job . Status . Active , job . Status . Succeeded , job . Status . Failed )
2016-03-21 13:45:31 +00:00
describeVolumes ( job . Spec . Template . Spec . Volumes , out , "" )
2015-08-21 14:23:12 +00:00
if events != nil {
DescribeEvents ( events , out )
}
return nil
} )
}
2015-09-12 16:46:10 +00:00
// DaemonSetDescriber generates information about a daemon set and the pods it has created.
type DaemonSetDescriber struct {
2015-08-27 17:18:16 +00:00
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * DaemonSetDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-10-12 18:18:50 +00:00
dc := d . Extensions ( ) . DaemonSets ( namespace )
2015-08-27 17:18:16 +00:00
pc := d . Pods ( namespace )
daemon , err := dc . Get ( name )
if err != nil {
return "" , err
}
2016-02-02 05:34:42 +00:00
selector , err := unversioned . LabelSelectorAsSelector ( daemon . Spec . Selector )
2015-10-26 06:11:09 +00:00
if err != nil {
return "" , err
}
running , waiting , succeeded , failed , err := getPodStatusForController ( pc , selector )
2015-08-27 17:18:16 +00:00
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( daemon )
}
2015-08-27 17:18:16 +00:00
2015-09-12 16:46:10 +00:00
return describeDaemonSet ( daemon , events , running , waiting , succeeded , failed )
2015-08-27 17:18:16 +00:00
}
2015-10-09 22:49:10 +00:00
func describeDaemonSet ( daemon * extensions . DaemonSet , events * api . EventList , running , waiting , succeeded , failed int ) ( string , error ) {
2015-08-27 17:18:16 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , daemon . Name )
2016-01-11 22:17:42 +00:00
fmt . Fprintf ( out , "Image(s):\t%s\n" , makeImageList ( & daemon . Spec . Template . Spec ) )
2016-02-02 05:34:42 +00:00
selector , err := unversioned . LabelSelectorAsSelector ( daemon . Spec . Selector )
2015-10-26 06:11:09 +00:00
if err != nil {
2015-12-01 09:24:21 +00:00
// this shouldn't happen if LabelSelector passed validation
2015-10-26 06:11:09 +00:00
return err
}
fmt . Fprintf ( out , "Selector:\t%s\n" , selector )
2015-08-27 17:18:16 +00:00
fmt . Fprintf ( out , "Node-Selector:\t%s\n" , labels . FormatLabels ( daemon . Spec . Template . Spec . NodeSelector ) )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , daemon . Labels )
2015-08-27 17:18:16 +00:00
fmt . Fprintf ( out , "Desired Number of Nodes Scheduled: %d\n" , daemon . Status . DesiredNumberScheduled )
fmt . Fprintf ( out , "Current Number of Nodes Scheduled: %d\n" , daemon . Status . CurrentNumberScheduled )
fmt . Fprintf ( out , "Number of Nodes Misscheduled: %d\n" , daemon . Status . NumberMisscheduled )
fmt . Fprintf ( out , "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n" , running , waiting , succeeded , failed )
if events != nil {
DescribeEvents ( events , out )
}
return nil
} )
}
2015-04-28 03:51:20 +00:00
// SecretDescriber generates information about a secret
type SecretDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * SecretDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-04-28 03:51:20 +00:00
c := d . Secrets ( namespace )
secret , err := c . Get ( name )
if err != nil {
return "" , err
}
return describeSecret ( secret )
}
func describeSecret ( secret * api . Secret ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , secret . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , secret . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , secret . Labels )
printLabelsMultiline ( out , "Annotations" , secret . Annotations )
2015-04-28 03:51:20 +00:00
fmt . Fprintf ( out , "\nType:\t%s\n" , secret . Type )
fmt . Fprintf ( out , "\nData\n====\n" )
for k , v := range secret . Data {
switch {
case k == api . ServiceAccountTokenKey && secret . Type == api . SecretTypeServiceAccountToken :
fmt . Fprintf ( out , "%s:\t%s\n" , k , string ( v ) )
default :
fmt . Fprintf ( out , "%s:\t%d bytes\n" , k , len ( v ) )
}
}
return nil
} )
}
2015-10-25 01:51:25 +00:00
type IngressDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( i * IngressDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-10-25 01:51:25 +00:00
c := i . Extensions ( ) . Ingress ( namespace )
ing , err := c . Get ( name )
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
return i . describeIngress ( ing , describerSettings )
2015-10-25 01:51:25 +00:00
}
2016-01-11 03:05:49 +00:00
func ( i * IngressDescriber ) describeBackend ( ns string , backend * extensions . IngressBackend ) string {
endpoints , _ := i . Endpoints ( ns ) . Get ( backend . ServiceName )
service , _ := i . Services ( ns ) . Get ( backend . ServiceName )
2015-11-18 10:37:23 +00:00
spName := ""
for i := range service . Spec . Ports {
sp := & service . Spec . Ports [ i ]
2016-01-11 03:05:49 +00:00
switch backend . ServicePort . Type {
2015-11-18 10:37:23 +00:00
case intstr . String :
2016-01-11 03:05:49 +00:00
if backend . ServicePort . StrVal == sp . Name {
2015-11-18 10:37:23 +00:00
spName = sp . Name
}
case intstr . Int :
2016-04-27 04:35:14 +00:00
if int32 ( backend . ServicePort . IntVal ) == sp . Port {
2015-11-18 10:37:23 +00:00
spName = sp . Name
}
}
}
2016-01-11 03:05:49 +00:00
return formatEndpoints ( endpoints , sets . NewString ( spName ) )
2015-11-18 10:37:23 +00:00
}
2016-04-20 17:27:32 +00:00
func ( i * IngressDescriber ) describeIngress ( ing * extensions . Ingress , describerSettings DescriberSettings ) ( string , error ) {
2015-10-25 01:51:25 +00:00
return tabbedString ( func ( out io . Writer ) error {
2016-01-11 03:05:49 +00:00
fmt . Fprintf ( out , "Name:\t%v\n" , ing . Name )
fmt . Fprintf ( out , "Namespace:\t%v\n" , ing . Namespace )
2016-06-02 23:09:51 +00:00
fmt . Fprintf ( out , "Address:\t%v\n" , loadBalancerStatusStringer ( ing . Status . LoadBalancer , true ) )
2016-01-11 03:05:49 +00:00
def := ing . Spec . Backend
ns := ing . Namespace
if def == nil {
// Ingresses that don't specify a default backend inherit the
// default backend in the kube-system namespace.
def = & extensions . IngressBackend {
ServiceName : "default-http-backend" ,
ServicePort : intstr . IntOrString { Type : intstr . Int , IntVal : 80 } ,
}
ns = api . NamespaceSystem
}
fmt . Fprintf ( out , "Default backend:\t%s (%s)\n" , backendStringer ( def ) , i . describeBackend ( ns , def ) )
2016-01-17 00:06:40 +00:00
if len ( ing . Spec . TLS ) != 0 {
describeIngressTLS ( out , ing . Spec . TLS )
}
2016-01-11 03:05:49 +00:00
fmt . Fprint ( out , "Rules:\n Host\tPath\tBackends\n" )
fmt . Fprint ( out , " ----\t----\t--------\n" )
2016-06-04 08:58:37 +00:00
count := 0
2015-11-18 10:37:23 +00:00
for _ , rules := range ing . Spec . Rules {
if rules . HTTP == nil {
continue
}
2016-06-04 08:58:37 +00:00
count ++
host := rules . Host
if len ( host ) == 0 {
host = "*"
}
fmt . Fprintf ( out , " %s\t\n" , host )
2015-11-18 10:37:23 +00:00
for _ , path := range rules . HTTP . Paths {
2016-06-04 08:58:37 +00:00
fmt . Fprintf ( out , " \t%s \t%s (%s)\n" , path . Path , backendStringer ( & path . Backend ) , i . describeBackend ( ns , & path . Backend ) )
2015-11-18 10:37:23 +00:00
}
}
2016-06-04 08:58:37 +00:00
if count == 0 {
fmt . Fprintf ( out , " %s\t%s \t%s (%s)\n" , "*" , "*" , backendStringer ( def ) , i . describeBackend ( ns , def ) )
}
2015-10-25 01:51:25 +00:00
describeIngressAnnotations ( out , ing . Annotations )
2016-01-11 03:05:49 +00:00
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
events , _ := i . Events ( ing . Namespace ) . Search ( ing )
if events != nil {
DescribeEvents ( events , out )
}
2015-10-25 01:51:25 +00:00
}
return nil
} )
}
2016-01-17 00:06:40 +00:00
func describeIngressTLS ( out io . Writer , ingTLS [ ] extensions . IngressTLS ) {
fmt . Fprintf ( out , "TLS:\n" )
for _ , t := range ingTLS {
2016-03-29 00:19:35 +00:00
if t . SecretName == "" {
fmt . Fprintf ( out , " SNI routes %v\n" , strings . Join ( t . Hosts , "," ) )
} else {
fmt . Fprintf ( out , " %v terminates %v\n" , t . SecretName , strings . Join ( t . Hosts , "," ) )
}
2016-01-17 00:06:40 +00:00
}
return
}
2015-10-25 01:51:25 +00:00
// TODO: Move from annotations into Ingress status.
func describeIngressAnnotations ( out io . Writer , annotations map [ string ] string ) {
2015-11-18 10:37:23 +00:00
fmt . Fprintf ( out , "Annotations:\n" )
2015-10-25 01:51:25 +00:00
for k , v := range annotations {
if ! strings . HasPrefix ( k , "ingress" ) {
continue
}
parts := strings . Split ( k , "/" )
name := parts [ len ( parts ) - 1 ]
2016-01-11 03:05:49 +00:00
fmt . Fprintf ( out , " %v:\t%s\n" , name , v )
2015-10-25 01:51:25 +00:00
}
return
}
2014-10-27 19:56:34 +00:00
// ServiceDescriber generates information about a service.
type ServiceDescriber struct {
2014-11-14 01:42:50 +00:00
client . Interface
2014-10-27 19:56:34 +00:00
}
2016-04-20 17:27:32 +00:00
func ( d * ServiceDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2014-11-14 01:42:50 +00:00
c := d . Services ( namespace )
2014-10-27 19:56:34 +00:00
service , err := c . Get ( name )
2014-10-06 01:24:19 +00:00
if err != nil {
return "" , err
}
2015-02-26 18:50:12 +00:00
endpoints , _ := d . Endpoints ( namespace ) . Get ( name )
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( service )
}
2015-02-26 18:50:12 +00:00
return describeService ( service , endpoints , events )
}
2015-05-22 21:33:29 +00:00
func buildIngressString ( ingress [ ] api . LoadBalancerIngress ) string {
var buffer bytes . Buffer
for i := range ingress {
if i != 0 {
buffer . WriteString ( ", " )
}
if ingress [ i ] . IP != "" {
buffer . WriteString ( ingress [ i ] . IP )
} else {
buffer . WriteString ( ingress [ i ] . Hostname )
}
}
return buffer . String ( )
}
2015-02-26 18:50:12 +00:00
func describeService ( service * api . Service , endpoints * api . Endpoints , events * api . EventList ) ( string , error ) {
if endpoints == nil {
endpoints = & api . Endpoints { }
}
2014-11-14 19:56:41 +00:00
return tabbedString ( func ( out io . Writer ) error {
2014-10-22 17:02:02 +00:00
fmt . Fprintf ( out , "Name:\t%s\n" , service . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , service . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , service . Labels )
2015-08-16 09:33:35 +00:00
fmt . Fprintf ( out , "Selector:\t%s\n" , labels . FormatLabels ( service . Spec . Selector ) )
2015-05-22 21:49:26 +00:00
fmt . Fprintf ( out , "Type:\t%s\n" , service . Spec . Type )
2015-05-23 20:41:11 +00:00
fmt . Fprintf ( out , "IP:\t%s\n" , service . Spec . ClusterIP )
2015-05-22 21:33:29 +00:00
if len ( service . Status . LoadBalancer . Ingress ) > 0 {
list := buildIngressString ( service . Status . LoadBalancer . Ingress )
2015-05-22 22:58:39 +00:00
fmt . Fprintf ( out , "LoadBalancer Ingress:\t%s\n" , list )
2015-02-21 23:13:28 +00:00
}
2015-03-13 15:16:41 +00:00
for i := range service . Spec . Ports {
sp := & service . Spec . Ports [ i ]
name := sp . Name
if name == "" {
2016-03-01 15:16:51 +00:00
name = "<unset>"
2015-03-13 15:16:41 +00:00
}
2015-03-31 16:30:56 +00:00
fmt . Fprintf ( out , "Port:\t%s\t%d/%s\n" , name , sp . Port , sp . Protocol )
2015-05-22 22:58:39 +00:00
if sp . NodePort != 0 {
2015-05-28 19:09:31 +00:00
fmt . Fprintf ( out , "NodePort:\t%s\t%d/%s\n" , name , sp . NodePort , sp . Protocol )
2015-05-22 22:58:39 +00:00
}
2015-09-09 17:45:01 +00:00
fmt . Fprintf ( out , "Endpoints:\t%s\n" , formatEndpoints ( endpoints , sets . NewString ( sp . Name ) ) )
2015-03-13 15:16:41 +00:00
}
2015-02-21 23:13:28 +00:00
fmt . Fprintf ( out , "Session Affinity:\t%s\n" , service . Spec . SessionAffinity )
2014-11-14 19:56:41 +00:00
if events != nil {
2015-04-21 04:24:12 +00:00
DescribeEvents ( events , out )
2014-11-14 19:56:41 +00:00
}
2014-10-06 01:24:19 +00:00
return nil
} )
}
2015-11-05 12:47:32 +00:00
// EndpointsDescriber generates information about an Endpoint.
type EndpointsDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * EndpointsDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-11-05 12:47:32 +00:00
c := d . Endpoints ( namespace )
ep , err := c . Get ( name )
if err != nil {
return "" , err
}
2016-04-20 17:27:32 +00:00
var events * api . EventList
if describerSettings . ShowEvents {
events , _ = d . Events ( namespace ) . Search ( ep )
}
2015-11-05 12:47:32 +00:00
return describeEndpoints ( ep , events )
}
func describeEndpoints ( ep * api . Endpoints , events * api . EventList ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , ep . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , ep . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , ep . Labels )
2015-11-05 12:47:32 +00:00
fmt . Fprintf ( out , "Subsets:\n" )
for i := range ep . Subsets {
subset := & ep . Subsets [ i ]
2016-05-29 09:09:39 +00:00
addresses := make ( [ ] string , 0 , len ( subset . Addresses ) )
2015-11-05 12:47:32 +00:00
for _ , addr := range subset . Addresses {
addresses = append ( addresses , addr . IP )
}
addressesString := strings . Join ( addresses , "," )
if len ( addressesString ) == 0 {
addressesString = "<none>"
}
fmt . Fprintf ( out , " Addresses:\t%s\n" , addressesString )
2016-05-29 09:09:39 +00:00
notReadyAddresses := make ( [ ] string , 0 , len ( subset . NotReadyAddresses ) )
2015-11-05 12:47:32 +00:00
for _ , addr := range subset . NotReadyAddresses {
notReadyAddresses = append ( notReadyAddresses , addr . IP )
}
notReadyAddressesString := strings . Join ( notReadyAddresses , "," )
if len ( notReadyAddressesString ) == 0 {
notReadyAddressesString = "<none>"
}
fmt . Fprintf ( out , " NotReadyAddresses:\t%s\n" , notReadyAddressesString )
if len ( subset . Ports ) > 0 {
fmt . Fprintf ( out , " Ports:\n" )
fmt . Fprintf ( out , " Name\tPort\tProtocol\n" )
fmt . Fprintf ( out , " ----\t----\t--------\n" )
for _ , port := range subset . Ports {
name := port . Name
if len ( name ) == 0 {
2016-03-01 15:16:51 +00:00
name = "<unset>"
2015-11-05 12:47:32 +00:00
}
fmt . Fprintf ( out , " %s\t%d\t%s\n" , name , port . Port , port . Protocol )
}
}
fmt . Fprintf ( out , "\n" )
}
if events != nil {
DescribeEvents ( events , out )
}
return nil
} )
}
2015-04-27 22:53:28 +00:00
// ServiceAccountDescriber generates information about a service.
type ServiceAccountDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * ServiceAccountDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-04-27 22:53:28 +00:00
c := d . ServiceAccounts ( namespace )
serviceAccount , err := c . Get ( name )
if err != nil {
return "" , err
}
tokens := [ ] api . Secret { }
2016-02-12 18:58:43 +00:00
tokenSelector := fields . SelectorFromSet ( map [ string ] string { api . SecretTypeField : string ( api . SecretTypeServiceAccountToken ) } )
2015-12-10 09:39:03 +00:00
options := api . ListOptions { FieldSelector : tokenSelector }
2015-12-02 11:12:57 +00:00
secrets , err := d . Secrets ( namespace ) . List ( options )
2015-04-27 22:53:28 +00:00
if err == nil {
for _ , s := range secrets . Items {
name , _ := s . Annotations [ api . ServiceAccountNameKey ]
uid , _ := s . Annotations [ api . ServiceAccountUIDKey ]
if name == serviceAccount . Name && uid == string ( serviceAccount . UID ) {
tokens = append ( tokens , s )
}
}
}
return describeServiceAccount ( serviceAccount , tokens )
}
func describeServiceAccount ( serviceAccount * api . ServiceAccount , tokens [ ] api . Secret ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , serviceAccount . Name )
2015-06-15 09:12:29 +00:00
fmt . Fprintf ( out , "Namespace:\t%s\n" , serviceAccount . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , serviceAccount . Labels )
2015-07-01 17:58:29 +00:00
fmt . Fprintln ( out )
2015-04-27 22:53:28 +00:00
2015-07-01 17:58:29 +00:00
var (
emptyHeader = " "
pullHeader = "Image pull secrets:"
mountHeader = "Mountable secrets: "
tokenHeader = "Tokens: "
pullSecretNames = [ ] string { }
mountSecretNames = [ ] string { }
tokenSecretNames = [ ] string { }
)
for _ , s := range serviceAccount . ImagePullSecrets {
pullSecretNames = append ( pullSecretNames , s . Name )
}
for _ , s := range serviceAccount . Secrets {
mountSecretNames = append ( mountSecretNames , s . Name )
}
for _ , s := range tokens {
tokenSecretNames = append ( tokenSecretNames , s . Name )
2015-04-27 22:53:28 +00:00
}
2015-07-01 17:58:29 +00:00
types := map [ string ] [ ] string {
pullHeader : pullSecretNames ,
mountHeader : mountSecretNames ,
tokenHeader : tokenSecretNames ,
}
for header , names := range types {
if len ( names ) == 0 {
fmt . Fprintf ( out , "%s\t<none>\n" , header )
} else {
prefix := header
for _ , name := range names {
fmt . Fprintf ( out , "%s\t%s\n" , prefix , name )
prefix = emptyHeader
}
2015-04-27 22:53:28 +00:00
}
fmt . Fprintln ( out )
}
return nil
} )
}
2015-03-06 18:04:52 +00:00
// NodeDescriber generates information about a node.
type NodeDescriber struct {
2014-11-14 01:42:50 +00:00
client . Interface
2014-10-27 19:56:34 +00:00
}
2016-04-20 17:27:32 +00:00
func ( d * NodeDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2014-12-08 05:56:43 +00:00
mc := d . Nodes ( )
2015-03-06 18:04:52 +00:00
node , err := mc . Get ( name )
2014-10-06 01:24:19 +00:00
if err != nil {
return "" , err
}
2015-07-30 21:33:48 +00:00
fieldSelector , err := fields . ParseSelector ( "spec.nodeName=" + name + ",status.phase!=" + string ( api . PodSucceeded ) + ",status.phase!=" + string ( api . PodFailed ) )
2015-02-21 17:07:09 +00:00
if err != nil {
return "" , err
}
2015-07-30 21:33:48 +00:00
// in a policy aware setting, users may have access to a node, but not all pods
// in that case, we note that the user does not have access to the pods
canViewPods := true
2015-12-10 09:39:03 +00:00
nodeNonTerminatedPodsList , err := d . Pods ( namespace ) . List ( api . ListOptions { FieldSelector : fieldSelector } )
2015-07-30 21:33:48 +00:00
if err != nil {
if ! errors . IsForbidden ( err ) {
return "" , err
2015-02-21 17:07:09 +00:00
}
2015-07-30 21:33:48 +00:00
canViewPods = false
2015-02-21 17:07:09 +00:00
}
2015-03-26 23:32:08 +00:00
var events * api . EventList
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
if ref , err := api . GetReference ( node ) ; err != nil {
glog . Errorf ( "Unable to construct reference to '%#v': %v" , node , err )
} else {
// TODO: We haven't decided the namespace for Node object yet.
ref . UID = types . UID ( ref . Name )
events , _ = d . Events ( "" ) . Search ( ref )
}
2015-03-26 23:32:08 +00:00
}
2014-11-14 19:56:41 +00:00
2015-07-30 21:33:48 +00:00
return describeNode ( node , nodeNonTerminatedPodsList , events , canViewPods )
2015-02-26 18:50:12 +00:00
}
2015-07-30 21:33:48 +00:00
func describeNode ( node * api . Node , nodeNonTerminatedPodsList * api . PodList , events * api . EventList , canViewPods bool ) ( string , error ) {
2014-11-14 19:56:41 +00:00
return tabbedString ( func ( out io . Writer ) error {
2015-03-06 18:04:52 +00:00
fmt . Fprintf ( out , "Name:\t%s\n" , node . Name )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , node . Labels )
2016-03-31 03:42:57 +00:00
printTaintsInAnnotationMultiline ( out , "Taints" , node . Annotations )
2015-03-23 16:14:18 +00:00
fmt . Fprintf ( out , "CreationTimestamp:\t%s\n" , node . CreationTimestamp . Time . Format ( time . RFC1123Z ) )
2015-08-14 00:28:01 +00:00
fmt . Fprintf ( out , "Phase:\t%v\n" , node . Status . Phase )
2015-03-06 18:04:52 +00:00
if len ( node . Status . Conditions ) > 0 {
2015-03-27 14:09:51 +00:00
fmt . Fprint ( out , "Conditions:\n Type\tStatus\tLastHeartbeatTime\tLastTransitionTime\tReason\tMessage\n" )
2015-12-01 19:40:51 +00:00
fmt . Fprint ( out , " ----\t------\t-----------------\t------------------\t------\t-------\n" )
2015-03-06 18:04:52 +00:00
for _ , c := range node . Status . Conditions {
2015-02-10 05:09:32 +00:00
fmt . Fprintf ( out , " %v \t%v \t%s \t%s \t%v \t%v\n" ,
2015-02-24 05:21:14 +00:00
c . Type ,
2015-02-10 05:09:32 +00:00
c . Status ,
2015-03-27 14:09:51 +00:00
c . LastHeartbeatTime . Time . Format ( time . RFC1123Z ) ,
2015-02-10 05:09:32 +00:00
c . LastTransitionTime . Time . Format ( time . RFC1123Z ) ,
c . Reason ,
c . Message )
}
}
2016-05-29 09:09:39 +00:00
addresses := make ( [ ] string , 0 , len ( node . Status . Addresses ) )
2015-03-06 18:04:52 +00:00
for _ , address := range node . Status . Addresses {
addresses = append ( addresses , address . Address )
}
2016-06-14 15:16:16 +00:00
printResourceList := func ( resourceList api . ResourceList ) {
resources := make ( [ ] api . ResourceName , 0 , len ( resourceList ) )
for resource := range resourceList {
resources = append ( resources , resource )
}
sort . Sort ( SortableResourceNames ( resources ) )
for _ , resource := range resources {
value := resourceList [ resource ]
fmt . Fprintf ( out , " %s:\t%s\n" , resource , value . String ( ) )
}
}
2015-03-06 18:04:52 +00:00
fmt . Fprintf ( out , "Addresses:\t%s\n" , strings . Join ( addresses , "," ) )
2015-03-25 13:44:40 +00:00
if len ( node . Status . Capacity ) > 0 {
2015-03-02 19:51:30 +00:00
fmt . Fprintf ( out , "Capacity:\n" )
2016-06-14 15:16:16 +00:00
printResourceList ( node . Status . Capacity )
}
if len ( node . Status . Allocatable ) > 0 {
fmt . Fprintf ( out , "Allocatable:\n" )
printResourceList ( node . Status . Allocatable )
2015-03-02 19:51:30 +00:00
}
2015-03-31 07:36:06 +00:00
2015-08-14 00:28:01 +00:00
fmt . Fprintf ( out , "System Info:\n" )
fmt . Fprintf ( out , " Machine ID:\t%s\n" , node . Status . NodeInfo . MachineID )
fmt . Fprintf ( out , " System UUID:\t%s\n" , node . Status . NodeInfo . SystemUUID )
fmt . Fprintf ( out , " Boot ID:\t%s\n" , node . Status . NodeInfo . BootID )
2015-03-31 07:36:06 +00:00
fmt . Fprintf ( out , " Kernel Version:\t%s\n" , node . Status . NodeInfo . KernelVersion )
2015-12-12 07:53:34 +00:00
fmt . Fprintf ( out , " OS Image:\t%s\n" , node . Status . NodeInfo . OSImage )
2016-05-10 17:38:57 +00:00
fmt . Fprintf ( out , " Operating System:\t%s\n" , node . Status . NodeInfo . OperatingSystem )
fmt . Fprintf ( out , " Architecture:\t%s\n" , node . Status . NodeInfo . Architecture )
2015-03-31 07:36:06 +00:00
fmt . Fprintf ( out , " Container Runtime Version:\t%s\n" , node . Status . NodeInfo . ContainerRuntimeVersion )
fmt . Fprintf ( out , " Kubelet Version:\t%s\n" , node . Status . NodeInfo . KubeletVersion )
fmt . Fprintf ( out , " Kube-Proxy Version:\t%s\n" , node . Status . NodeInfo . KubeProxyVersion )
2015-03-06 18:04:52 +00:00
if len ( node . Spec . PodCIDR ) > 0 {
fmt . Fprintf ( out , "PodCIDR:\t%s\n" , node . Spec . PodCIDR )
}
if len ( node . Spec . ExternalID ) > 0 {
fmt . Fprintf ( out , "ExternalID:\t%s\n" , node . Spec . ExternalID )
}
2015-07-30 21:33:48 +00:00
if canViewPods && nodeNonTerminatedPodsList != nil {
if err := describeNodeResource ( nodeNonTerminatedPodsList , node , out ) ; err != nil {
return err
}
} else {
fmt . Fprintf ( out , "Pods:\tnot authorized\n" )
2015-09-10 00:20:31 +00:00
}
2014-11-14 19:56:41 +00:00
if events != nil {
2015-04-21 04:24:12 +00:00
DescribeEvents ( events , out )
2014-11-14 19:56:41 +00:00
}
2014-10-06 01:24:19 +00:00
return nil
} )
}
2016-04-25 19:24:40 +00:00
type PetSetDescriber struct {
client * client . Client
}
2016-04-20 17:27:32 +00:00
func ( p * PetSetDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2016-04-25 19:24:40 +00:00
ps , err := p . client . Apps ( ) . PetSets ( namespace ) . Get ( name )
if err != nil {
return "" , err
}
pc := p . client . Pods ( namespace )
selector , err := unversioned . LabelSelectorAsSelector ( ps . Spec . Selector )
if err != nil {
return "" , err
}
running , waiting , succeeded , failed , err := getPodStatusForController ( pc , selector )
if err != nil {
return "" , err
}
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , ps . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , ps . Namespace )
fmt . Fprintf ( out , "Image(s):\t%s\n" , makeImageList ( & ps . Spec . Template . Spec ) )
fmt . Fprintf ( out , "Selector:\t%s\n" , unversioned . FormatLabelSelector ( ps . Spec . Selector ) )
fmt . Fprintf ( out , "Labels:\t%s\n" , labels . FormatLabels ( ps . Labels ) )
fmt . Fprintf ( out , "Replicas:\t%d current / %d desired\n" , ps . Status . Replicas , ps . Spec . Replicas )
fmt . Fprintf ( out , "Annotations:\t%s\n" , labels . FormatLabels ( ps . Annotations ) )
fmt . Fprintf ( out , "CreationTimestamp:\t%s\n" , ps . CreationTimestamp . Time . Format ( time . RFC1123Z ) )
fmt . Fprintf ( out , "Pods Status:\t%d Running / %d Waiting / %d Succeeded / %d Failed\n" , running , waiting , succeeded , failed )
describeVolumes ( ps . Spec . Template . Spec . Volumes , out , "" )
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
events , _ := p . client . Events ( namespace ) . Search ( ps )
if events != nil {
DescribeEvents ( events , out )
}
2016-04-25 19:24:40 +00:00
}
return nil
} )
}
2015-08-26 14:17:18 +00:00
// HorizontalPodAutoscalerDescriber generates information about a horizontal pod autoscaler.
type HorizontalPodAutoscalerDescriber struct {
2015-08-31 16:29:18 +00:00
client * client . Client
2015-08-26 14:17:18 +00:00
}
2016-04-20 17:27:32 +00:00
func ( d * HorizontalPodAutoscalerDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2016-05-05 10:27:24 +00:00
hpa , err := d . client . Autoscaling ( ) . HorizontalPodAutoscalers ( namespace ) . Get ( name )
2015-08-26 14:17:18 +00:00
if err != nil {
return "" , err
}
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , hpa . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , hpa . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , hpa . Labels )
printLabelsMultiline ( out , "Annotations" , hpa . Annotations )
2015-08-26 14:17:18 +00:00
fmt . Fprintf ( out , "CreationTimestamp:\t%s\n" , hpa . CreationTimestamp . Time . Format ( time . RFC1123Z ) )
2016-05-05 10:27:24 +00:00
fmt . Fprintf ( out , "Reference:\t%s/%s\n" ,
hpa . Spec . ScaleTargetRef . Kind ,
hpa . Spec . ScaleTargetRef . Name )
if hpa . Spec . TargetCPUUtilizationPercentage != nil {
fmt . Fprintf ( out , "Target CPU utilization:\t%d%%\n" , * hpa . Spec . TargetCPUUtilizationPercentage )
2015-10-13 15:24:23 +00:00
fmt . Fprintf ( out , "Current CPU utilization:\t" )
if hpa . Status . CurrentCPUUtilizationPercentage != nil {
fmt . Fprintf ( out , "%d%%\n" , * hpa . Status . CurrentCPUUtilizationPercentage )
} else {
2016-03-01 15:16:51 +00:00
fmt . Fprintf ( out , "<unset>\n" )
2015-10-13 15:24:23 +00:00
}
2015-08-26 14:17:18 +00:00
}
2015-10-21 12:22:34 +00:00
minReplicas := "<unset>"
if hpa . Spec . MinReplicas != nil {
minReplicas = fmt . Sprintf ( "%d" , * hpa . Spec . MinReplicas )
}
fmt . Fprintf ( out , "Min replicas:\t%s\n" , minReplicas )
fmt . Fprintf ( out , "Max replicas:\t%d\n" , hpa . Spec . MaxReplicas )
2015-08-26 14:17:18 +00:00
// TODO: switch to scale subresource once the required code is submitted.
2016-05-05 10:27:24 +00:00
if strings . ToLower ( hpa . Spec . ScaleTargetRef . Kind ) == "replicationcontroller" {
2015-08-26 14:17:18 +00:00
fmt . Fprintf ( out , "ReplicationController pods:\t" )
2016-05-05 10:27:24 +00:00
rc , err := d . client . ReplicationControllers ( hpa . Namespace ) . Get ( hpa . Spec . ScaleTargetRef . Name )
2015-08-26 14:17:18 +00:00
if err == nil {
fmt . Fprintf ( out , "%d current / %d desired\n" , rc . Status . Replicas , rc . Spec . Replicas )
} else {
fmt . Fprintf ( out , "failed to check Replication Controller\n" )
}
}
2016-02-23 15:36:17 +00:00
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
events , _ := d . client . Events ( namespace ) . Search ( hpa )
if events != nil {
DescribeEvents ( events , out )
}
2016-02-23 15:36:17 +00:00
}
2015-08-26 14:17:18 +00:00
return nil
} )
}
2015-07-30 21:33:48 +00:00
func describeNodeResource ( nodeNonTerminatedPodsList * api . PodList , node * api . Node , out io . Writer ) error {
fmt . Fprintf ( out , "Non-terminated Pods:\t(%d in total)\n" , len ( nodeNonTerminatedPodsList . Items ) )
2015-09-01 23:35:32 +00:00
fmt . Fprint ( out , " Namespace\tName\t\tCPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n" )
2015-12-01 19:40:51 +00:00
fmt . Fprint ( out , " ---------\t----\t\t------------\t----------\t---------------\t-------------\n" )
2016-06-14 15:16:16 +00:00
allocatable := node . Status . Capacity
if len ( node . Status . Allocatable ) > 0 {
allocatable = node . Status . Allocatable
}
2015-07-30 21:33:48 +00:00
for _ , pod := range nodeNonTerminatedPodsList . Items {
req , limit , err := api . PodRequestsAndLimits ( & pod )
2015-09-10 00:20:31 +00:00
if err != nil {
return err
2015-08-14 00:28:01 +00:00
}
2015-09-10 00:20:31 +00:00
cpuReq , cpuLimit , memoryReq , memoryLimit := req [ api . ResourceCPU ] , limit [ api . ResourceCPU ] , req [ api . ResourceMemory ] , limit [ api . ResourceMemory ]
2016-06-14 15:16:16 +00:00
fractionCpuReq := float64 ( cpuReq . MilliValue ( ) ) / float64 ( allocatable . Cpu ( ) . MilliValue ( ) ) * 100
fractionCpuLimit := float64 ( cpuLimit . MilliValue ( ) ) / float64 ( allocatable . Cpu ( ) . MilliValue ( ) ) * 100
fractionMemoryReq := float64 ( memoryReq . Value ( ) ) / float64 ( allocatable . Memory ( ) . Value ( ) ) * 100
fractionMemoryLimit := float64 ( memoryLimit . Value ( ) ) / float64 ( allocatable . Memory ( ) . Value ( ) ) * 100
2015-09-10 00:20:31 +00:00
fmt . Fprintf ( out , " %s\t%s\t\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\n" , pod . Namespace , pod . Name ,
cpuReq . String ( ) , int64 ( fractionCpuReq ) , cpuLimit . String ( ) , int64 ( fractionCpuLimit ) ,
memoryReq . String ( ) , int64 ( fractionMemoryReq ) , memoryLimit . String ( ) , int64 ( fractionMemoryLimit ) )
2015-08-14 00:28:01 +00:00
}
2015-09-10 00:20:31 +00:00
2016-04-12 15:49:32 +00:00
fmt . Fprint ( out , "Allocated resources:\n (Total limits may be over 100 percent, i.e., overcommitted. More info: http://releases.k8s.io/HEAD/docs/user-guide/compute-resources.md)\n CPU Requests\tCPU Limits\tMemory Requests\tMemory Limits\n" )
2015-12-01 19:40:51 +00:00
fmt . Fprint ( out , " ------------\t----------\t---------------\t-------------\n" )
2015-07-30 21:33:48 +00:00
reqs , limits , err := getPodsTotalRequestsAndLimits ( nodeNonTerminatedPodsList )
2015-09-10 00:20:31 +00:00
if err != nil {
return err
}
cpuReqs , cpuLimits , memoryReqs , memoryLimits := reqs [ api . ResourceCPU ] , limits [ api . ResourceCPU ] , reqs [ api . ResourceMemory ] , limits [ api . ResourceMemory ]
2016-06-14 15:16:16 +00:00
fractionCpuReqs := float64 ( cpuReqs . MilliValue ( ) ) / float64 ( allocatable . Cpu ( ) . MilliValue ( ) ) * 100
fractionCpuLimits := float64 ( cpuLimits . MilliValue ( ) ) / float64 ( allocatable . Cpu ( ) . MilliValue ( ) ) * 100
fractionMemoryReqs := float64 ( memoryReqs . Value ( ) ) / float64 ( allocatable . Memory ( ) . Value ( ) ) * 100
fractionMemoryLimits := float64 ( memoryLimits . Value ( ) ) / float64 ( allocatable . Memory ( ) . Value ( ) ) * 100
2015-09-10 23:25:48 +00:00
fmt . Fprintf ( out , " %s (%d%%)\t%s (%d%%)\t%s (%d%%)\t%s (%d%%)\n" ,
cpuReqs . String ( ) , int64 ( fractionCpuReqs ) , cpuLimits . String ( ) , int64 ( fractionCpuLimits ) ,
memoryReqs . String ( ) , int64 ( fractionMemoryReqs ) , memoryLimits . String ( ) , int64 ( fractionMemoryLimits ) )
2015-09-10 00:20:31 +00:00
return nil
2015-08-14 00:28:01 +00:00
}
func filterTerminatedPods ( pods [ ] * api . Pod ) [ ] * api . Pod {
2015-07-30 02:19:17 +00:00
if len ( pods ) == 0 {
return pods
}
result := [ ] * api . Pod { }
for _ , pod := range pods {
if pod . Status . Phase == api . PodSucceeded || pod . Status . Phase == api . PodFailed {
continue
}
result = append ( result , pod )
}
return result
}
2015-07-30 21:33:48 +00:00
func getPodsTotalRequestsAndLimits ( podList * api . PodList ) ( reqs map [ api . ResourceName ] resource . Quantity , limits map [ api . ResourceName ] resource . Quantity , err error ) {
2015-09-10 00:20:31 +00:00
reqs , limits = map [ api . ResourceName ] resource . Quantity { } , map [ api . ResourceName ] resource . Quantity { }
2015-07-30 21:33:48 +00:00
for _ , pod := range podList . Items {
podReqs , podLimits , err := api . PodRequestsAndLimits ( & pod )
2015-07-30 02:19:17 +00:00
if err != nil {
2015-09-10 00:20:31 +00:00
return nil , nil , err
2015-07-30 02:19:17 +00:00
}
for podReqName , podReqValue := range podReqs {
if value , ok := reqs [ podReqName ] ; ! ok {
2015-09-10 00:20:31 +00:00
reqs [ podReqName ] = * podReqValue . Copy ( )
2016-05-17 04:36:56 +00:00
} else {
value . Add ( podReqValue )
reqs [ podReqName ] = value
2015-09-10 00:20:31 +00:00
}
}
for podLimitName , podLimitValue := range podLimits {
if value , ok := limits [ podLimitName ] ; ! ok {
limits [ podLimitName ] = * podLimitValue . Copy ( )
2016-05-17 04:36:56 +00:00
} else {
value . Add ( podLimitValue )
limits [ podLimitName ] = value
2015-07-30 02:19:17 +00:00
}
}
}
2015-09-10 00:20:31 +00:00
return
2015-07-30 02:19:17 +00:00
}
2015-04-21 04:24:12 +00:00
func DescribeEvents ( el * api . EventList , w io . Writer ) {
2014-11-14 19:56:41 +00:00
if len ( el . Items ) == 0 {
fmt . Fprint ( w , "No events." )
return
}
2014-12-16 22:20:51 +00:00
sort . Sort ( SortableEvents ( el . Items ) )
2015-11-13 22:30:01 +00:00
fmt . Fprint ( w , "Events:\n FirstSeen\tLastSeen\tCount\tFrom\tSubobjectPath\tType\tReason\tMessage\n" )
2015-12-01 19:40:51 +00:00
fmt . Fprint ( w , " ---------\t--------\t-----\t----\t-------------\t--------\t------\t-------\n" )
2014-11-14 19:56:41 +00:00
for _ , e := range el . Items {
2015-11-13 22:30:01 +00:00
fmt . Fprintf ( w , " %s\t%s\t%d\t%v\t%v\t%v\t%v\t%v\n" ,
2015-08-10 07:00:24 +00:00
translateTimestamp ( e . FirstTimestamp ) ,
translateTimestamp ( e . LastTimestamp ) ,
2015-02-11 00:49:32 +00:00
e . Count ,
2014-12-16 22:20:51 +00:00
e . Source ,
e . InvolvedObject . FieldPath ,
2015-11-13 22:30:01 +00:00
e . Type ,
2014-12-16 22:20:51 +00:00
e . Reason ,
e . Message )
2014-11-14 19:56:41 +00:00
}
}
2015-09-18 20:35:56 +00:00
// DeploymentDescriber generates information about a deployment.
type DeploymentDescriber struct {
2016-01-15 05:00:58 +00:00
clientset . Interface
2015-09-18 20:35:56 +00:00
}
2016-04-20 17:27:32 +00:00
func ( dd * DeploymentDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2015-10-12 18:18:50 +00:00
d , err := dd . Extensions ( ) . Deployments ( namespace ) . Get ( name )
2015-09-18 20:35:56 +00:00
if err != nil {
return "" , err
}
2016-02-08 23:13:48 +00:00
selector , err := unversioned . LabelSelectorAsSelector ( d . Spec . Selector )
if err != nil {
return "" , err
}
2015-09-18 20:35:56 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , d . ObjectMeta . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , d . ObjectMeta . Namespace )
fmt . Fprintf ( out , "CreationTimestamp:\t%s\n" , d . CreationTimestamp . Time . Format ( time . RFC1123Z ) )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , d . Labels )
2016-02-08 23:13:48 +00:00
fmt . Fprintf ( out , "Selector:\t%s\n" , selector )
2016-01-19 19:11:13 +00:00
fmt . Fprintf ( out , "Replicas:\t%d updated | %d total | %d available | %d unavailable\n" , d . Status . UpdatedReplicas , d . Spec . Replicas , d . Status . AvailableReplicas , d . Status . UnavailableReplicas )
2015-09-18 20:35:56 +00:00
fmt . Fprintf ( out , "StrategyType:\t%s\n" , d . Spec . Strategy . Type )
2016-02-09 03:13:34 +00:00
fmt . Fprintf ( out , "MinReadySeconds:\t%d\n" , d . Spec . MinReadySeconds )
2015-09-18 20:35:56 +00:00
if d . Spec . Strategy . RollingUpdate != nil {
ru := d . Spec . Strategy . RollingUpdate
2016-01-31 13:59:58 +00:00
fmt . Fprintf ( out , "RollingUpdateStrategy:\t%s max unavailable, %s max surge\n" , ru . MaxUnavailable . String ( ) , ru . MaxSurge . String ( ) )
2015-09-18 20:35:56 +00:00
}
2016-06-01 21:14:40 +00:00
oldRSs , _ , newRS , err := deploymentutil . GetAllReplicaSets ( d , dd )
2015-09-18 20:35:56 +00:00
if err == nil {
2016-01-20 00:40:18 +00:00
fmt . Fprintf ( out , "OldReplicaSets:\t%s\n" , printReplicaSetsByLabels ( oldRSs ) )
var newRSs [ ] * extensions . ReplicaSet
if newRS != nil {
newRSs = append ( newRSs , newRS )
2015-09-18 20:35:56 +00:00
}
2016-01-20 00:40:18 +00:00
fmt . Fprintf ( out , "NewReplicaSet:\t%s\n" , printReplicaSetsByLabels ( newRSs ) )
2015-09-18 20:35:56 +00:00
}
2016-04-20 17:27:32 +00:00
if describerSettings . ShowEvents {
events , err := dd . Core ( ) . Events ( namespace ) . Search ( d )
if err == nil && events != nil {
DescribeEvents ( events , out )
}
2015-09-29 23:55:06 +00:00
}
2015-09-18 20:35:56 +00:00
return nil
} )
}
2015-09-12 16:46:10 +00:00
// Get all daemon set whose selectors would match a given set of labels.
2015-08-27 17:18:16 +00:00
// TODO: Move this to pkg/client and ideally implement it server-side (instead
2015-09-12 16:46:10 +00:00
// of getting all DS's and searching through them manually).
2015-08-27 17:18:16 +00:00
// TODO: write an interface for controllers and fuse getReplicationControllersForLabels
2015-09-12 16:46:10 +00:00
// and getDaemonSetsForLabels.
2015-10-09 22:49:10 +00:00
func getDaemonSetsForLabels ( c client . DaemonSetInterface , labelsToMatch labels . Labels ) ( [ ] extensions . DaemonSet , error ) {
2015-09-12 16:46:10 +00:00
// Get all daemon sets
// TODO: this needs a namespace scope as argument
2015-12-10 09:39:03 +00:00
dss , err := c . List ( api . ListOptions { } )
2015-08-27 17:18:16 +00:00
if err != nil {
2015-09-12 16:46:10 +00:00
return nil , fmt . Errorf ( "error getting daemon set: %v" , err )
2015-08-27 17:18:16 +00:00
}
// Find the ones that match labelsToMatch.
2015-10-09 22:49:10 +00:00
var matchingDaemonSets [ ] extensions . DaemonSet
2015-09-12 16:46:10 +00:00
for _ , ds := range dss . Items {
2016-02-02 05:34:42 +00:00
selector , err := unversioned . LabelSelectorAsSelector ( ds . Spec . Selector )
2015-10-26 06:11:09 +00:00
if err != nil {
// this should never happen if the DaemonSet passed validation
return nil , err
}
2015-08-27 17:18:16 +00:00
if selector . Matches ( labelsToMatch ) {
2015-09-12 16:46:10 +00:00
matchingDaemonSets = append ( matchingDaemonSets , ds )
2015-08-27 17:18:16 +00:00
}
}
2015-09-12 16:46:10 +00:00
return matchingDaemonSets , nil
2015-08-27 17:18:16 +00:00
}
2015-09-18 20:35:56 +00:00
func printReplicationControllersByLabels ( matchingRCs [ ] * api . ReplicationController ) string {
2014-10-06 01:24:19 +00:00
// Format the matching RC's into strings.
2016-05-29 09:09:39 +00:00
rcStrings := make ( [ ] string , 0 , len ( matchingRCs ) )
2014-10-22 17:02:02 +00:00
for _ , controller := range matchingRCs {
2014-11-07 02:09:46 +00:00
rcStrings = append ( rcStrings , fmt . Sprintf ( "%s (%d/%d replicas created)" , controller . Name , controller . Status . Replicas , controller . Spec . Replicas ) )
2014-10-06 01:24:19 +00:00
}
list := strings . Join ( rcStrings , ", " )
if list == "" {
return "<none>"
}
return list
}
2016-01-20 00:40:18 +00:00
func printReplicaSetsByLabels ( matchingRSs [ ] * extensions . ReplicaSet ) string {
// Format the matching ReplicaSets into strings.
2016-05-29 09:09:39 +00:00
rsStrings := make ( [ ] string , 0 , len ( matchingRSs ) )
2016-01-20 00:40:18 +00:00
for _ , rs := range matchingRSs {
rsStrings = append ( rsStrings , fmt . Sprintf ( "%s (%d/%d replicas created)" , rs . Name , rs . Status . Replicas , rs . Spec . Replicas ) )
}
list := strings . Join ( rsStrings , ", " )
if list == "" {
return "<none>"
}
return list
}
2015-10-26 06:11:09 +00:00
func getPodStatusForController ( c client . PodInterface , selector labels . Selector ) ( running , waiting , succeeded , failed int , err error ) {
2015-12-10 09:39:03 +00:00
options := api . ListOptions { LabelSelector : selector }
2015-12-02 11:12:57 +00:00
rcPods , err := c . List ( options )
2014-10-06 01:24:19 +00:00
if err != nil {
return
}
for _ , pod := range rcPods . Items {
2014-11-21 19:04:32 +00:00
switch pod . Status . Phase {
2014-11-07 07:11:21 +00:00
case api . PodRunning :
2014-10-06 01:24:19 +00:00
running ++
2014-11-07 07:11:21 +00:00
case api . PodPending :
2014-10-06 01:24:19 +00:00
waiting ++
2014-11-07 07:11:21 +00:00
case api . PodSucceeded :
2014-11-05 15:22:54 +00:00
succeeded ++
2014-11-07 07:11:21 +00:00
case api . PodFailed :
2014-11-05 15:22:54 +00:00
failed ++
2014-10-06 01:24:19 +00:00
}
}
return
}
2015-02-26 18:50:12 +00:00
2015-12-15 15:09:42 +00:00
// ConfigMapDescriber generates information about a ConfigMap
type ConfigMapDescriber struct {
client . Interface
}
2016-04-20 17:27:32 +00:00
func ( d * ConfigMapDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
2016-01-15 16:48:36 +00:00
c := d . ConfigMaps ( namespace )
2015-12-15 15:09:42 +00:00
configMap , err := c . Get ( name )
if err != nil {
return "" , err
}
return describeConfigMap ( configMap )
}
2016-01-15 16:48:36 +00:00
func describeConfigMap ( configMap * api . ConfigMap ) ( string , error ) {
2015-12-15 15:09:42 +00:00
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , configMap . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , configMap . Namespace )
2016-04-07 18:21:58 +00:00
printLabelsMultiline ( out , "Labels" , configMap . Labels )
printLabelsMultiline ( out , "Annotations" , configMap . Annotations )
2015-12-15 15:09:42 +00:00
fmt . Fprintf ( out , "\nData\n====\n" )
for k , v := range configMap . Data {
fmt . Fprintf ( out , "%s:\t%d bytes\n" , k , len ( v ) )
}
return nil
} )
}
2016-05-05 17:30:50 +00:00
type ClusterDescriber struct {
fed_clientset . Interface
}
func ( d * ClusterDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
cluster , err := d . Federation ( ) . Clusters ( ) . Get ( name )
if err != nil {
return "" , err
}
return describeCluster ( cluster )
}
func describeCluster ( cluster * federation . Cluster ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , cluster . Name )
fmt . Fprintf ( out , "Labels:\t%s\n" , labels . FormatLabels ( cluster . Labels ) )
fmt . Fprintf ( out , "ServerAddressByClientCIDRs:\n ClientCIDR\tServerAddress\n" )
fmt . Fprintf ( out , " ----\t----\n" )
for _ , cidrAddr := range cluster . Spec . ServerAddressByClientCIDRs {
fmt . Fprintf ( out , " %v \t%v\n\n" , cidrAddr . ClientCIDR , cidrAddr . ServerAddress )
}
if len ( cluster . Status . Conditions ) > 0 {
fmt . Fprint ( out , "Conditions:\n Type\tStatus\tLastUpdateTime\tLastTransitionTime\tReason\tMessage\n" )
fmt . Fprint ( out , " ----\t------\t-----------------\t------------------\t------\t-------\n" )
for _ , c := range cluster . Status . Conditions {
fmt . Fprintf ( out , " %v \t%v \t%s \t%s \t%v \t%v\n" ,
c . Type ,
c . Status ,
c . LastProbeTime . Time . Format ( time . RFC1123Z ) ,
c . LastTransitionTime . Time . Format ( time . RFC1123Z ) ,
c . Reason ,
c . Message )
}
}
fmt . Fprintf ( out , "Version:\t%s\n" , cluster . Status . Version )
if len ( cluster . Status . Capacity ) > 0 {
fmt . Fprintf ( out , "Capacity:\n" )
for resource , value := range cluster . Status . Capacity {
fmt . Fprintf ( out , " %s:\t%s\n" , resource , value . String ( ) )
}
}
if len ( cluster . Status . Allocatable ) > 0 {
fmt . Fprintf ( out , "Allocatable:\n" )
for resource , value := range cluster . Status . Allocatable {
fmt . Fprintf ( out , " %s:\t%s\n" , resource , value . String ( ) )
}
}
2016-05-18 17:16:33 +00:00
return nil
} )
}
// NetworkPolicyDescriber generates information about a NetworkPolicy
type NetworkPolicyDescriber struct {
client . Interface
}
func ( d * NetworkPolicyDescriber ) Describe ( namespace , name string , describerSettings DescriberSettings ) ( string , error ) {
c := d . Extensions ( ) . NetworkPolicies ( namespace )
networkPolicy , err := c . Get ( name )
if err != nil {
return "" , err
}
return describeNetworkPolicy ( networkPolicy )
}
func describeNetworkPolicy ( networkPolicy * extensions . NetworkPolicy ) ( string , error ) {
return tabbedString ( func ( out io . Writer ) error {
fmt . Fprintf ( out , "Name:\t%s\n" , networkPolicy . Name )
fmt . Fprintf ( out , "Namespace:\t%s\n" , networkPolicy . Namespace )
printLabelsMultiline ( out , "Labels" , networkPolicy . Labels )
printLabelsMultiline ( out , "Annotations" , networkPolicy . Annotations )
2016-05-05 17:30:50 +00:00
return nil
} )
}
2015-02-26 18:50:12 +00:00
// newErrNoDescriber creates a new ErrNoDescriber with the names of the provided types.
func newErrNoDescriber ( types ... reflect . Type ) error {
2016-05-29 09:09:39 +00:00
names := make ( [ ] string , 0 , len ( types ) )
2015-02-26 18:50:12 +00:00
for _ , t := range types {
names = append ( names , t . String ( ) )
}
return ErrNoDescriber { Types : names }
}
// Describers implements ObjectDescriber against functions registered via Add. Those functions can
// be strongly typed. Types are exactly matched (no conversion or assignable checks).
type Describers struct {
searchFns map [ reflect . Type ] [ ] typeFunc
}
// DescribeObject implements ObjectDescriber and will attempt to print the provided object to a string,
// if at least one describer function has been registered with the exact types passed, or if any
// describer can print the exact object in its first argument (the remainder will be provided empty
// values). If no function registered with Add can satisfy the passed objects, an ErrNoDescriber will
// be returned
// TODO: reorder and partial match extra.
func ( d * Describers ) DescribeObject ( exact interface { } , extra ... interface { } ) ( string , error ) {
exactType := reflect . TypeOf ( exact )
fns , ok := d . searchFns [ exactType ]
if ! ok {
return "" , newErrNoDescriber ( exactType )
}
if len ( extra ) == 0 {
for _ , typeFn := range fns {
if len ( typeFn . Extra ) == 0 {
return typeFn . Describe ( exact , extra ... )
}
}
typeFn := fns [ 0 ]
for _ , t := range typeFn . Extra {
v := reflect . New ( t ) . Elem ( )
extra = append ( extra , v . Interface ( ) )
}
return fns [ 0 ] . Describe ( exact , extra ... )
}
2016-05-29 09:09:39 +00:00
types := make ( [ ] reflect . Type , 0 , len ( extra ) )
2015-02-26 18:50:12 +00:00
for _ , obj := range extra {
types = append ( types , reflect . TypeOf ( obj ) )
}
for _ , typeFn := range fns {
if typeFn . Matches ( types ) {
return typeFn . Describe ( exact , extra ... )
}
}
return "" , newErrNoDescriber ( append ( [ ] reflect . Type { exactType } , types ... ) ... )
}
// Add adds one or more describer functions to the Describer. The passed function must
// match the signature:
//
// func(...) (string, error)
//
// Any number of arguments may be provided.
func ( d * Describers ) Add ( fns ... interface { } ) error {
for _ , fn := range fns {
fv := reflect . ValueOf ( fn )
ft := fv . Type ( )
if ft . Kind ( ) != reflect . Func {
return fmt . Errorf ( "expected func, got: %v" , ft )
}
2016-05-29 09:09:39 +00:00
numIn := ft . NumIn ( )
if numIn == 0 {
2015-02-26 18:50:12 +00:00
return fmt . Errorf ( "expected at least one 'in' params, got: %v" , ft )
}
if ft . NumOut ( ) != 2 {
return fmt . Errorf ( "expected two 'out' params - (string, error), got: %v" , ft )
}
2016-05-29 09:09:39 +00:00
types := make ( [ ] reflect . Type , 0 , numIn )
for i := 0 ; i < numIn ; i ++ {
2015-02-26 18:50:12 +00:00
types = append ( types , ft . In ( i ) )
}
if ft . Out ( 0 ) != reflect . TypeOf ( string ( "" ) ) {
return fmt . Errorf ( "expected string return, got: %v" , ft )
}
var forErrorType error
// This convolution is necessary, otherwise TypeOf picks up on the fact
// that forErrorType is nil.
errorType := reflect . TypeOf ( & forErrorType ) . Elem ( )
if ft . Out ( 1 ) != errorType {
return fmt . Errorf ( "expected error return, got: %v" , ft )
}
exact := types [ 0 ]
extra := types [ 1 : ]
if d . searchFns == nil {
d . searchFns = make ( map [ reflect . Type ] [ ] typeFunc )
}
fns := d . searchFns [ exact ]
fn := typeFunc { Extra : extra , Fn : fv }
fns = append ( fns , fn )
d . searchFns [ exact ] = fns
}
return nil
}
// typeFunc holds information about a describer function and the types it accepts
type typeFunc struct {
Extra [ ] reflect . Type
Fn reflect . Value
}
// Matches returns true when the passed types exactly match the Extra list.
func ( fn typeFunc ) Matches ( types [ ] reflect . Type ) bool {
if len ( fn . Extra ) != len ( types ) {
return false
}
2015-11-20 19:37:24 +00:00
// reorder the items in array types and fn.Extra
// convert the type into string and sort them, check if they are matched
varMap := make ( map [ reflect . Type ] bool )
for i := range fn . Extra {
varMap [ fn . Extra [ i ] ] = true
}
2015-02-26 18:50:12 +00:00
for i := range types {
2015-11-20 19:37:24 +00:00
if _ , found := varMap [ types [ i ] ] ; ! found {
2015-02-26 18:50:12 +00:00
return false
}
}
return true
}
// Describe invokes the nested function with the exact number of arguments.
func ( fn typeFunc ) Describe ( exact interface { } , extra ... interface { } ) ( string , error ) {
values := [ ] reflect . Value { reflect . ValueOf ( exact ) }
for _ , obj := range extra {
values = append ( values , reflect . ValueOf ( obj ) )
}
out := fn . Fn . Call ( values )
s := out [ 0 ] . Interface ( ) . ( string )
var err error
if ! out [ 1 ] . IsNil ( ) {
err = out [ 1 ] . Interface ( ) . ( error )
}
return s , err
}
2016-04-07 18:21:58 +00:00
// printLabelsMultiline prints multiple labels with a proper alignment.
func printLabelsMultiline ( out io . Writer , title string , labels map [ string ] string ) {
2016-04-21 12:32:34 +00:00
printLabelsMultilineWithIndent ( out , "" , title , "\t" , labels )
}
// printLabelsMultiline prints multiple labels with a user-defined alignment.
func printLabelsMultilineWithIndent ( out io . Writer , initialIndent , title , innerIndent string , labels map [ string ] string ) {
fmt . Fprintf ( out , "%s%s:%s" , initialIndent , title , innerIndent )
2016-04-07 18:21:58 +00:00
if labels == nil || len ( labels ) == 0 {
fmt . Fprintln ( out , "<none>" )
return
}
// to print labels in the sorted order
keys := make ( [ ] string , 0 , len ( labels ) )
for key := range labels {
keys = append ( keys , key )
}
sort . Strings ( keys )
for i , key := range keys {
if i != 0 {
2016-04-21 12:32:34 +00:00
fmt . Fprint ( out , initialIndent )
fmt . Fprint ( out , innerIndent )
2016-04-07 18:21:58 +00:00
}
fmt . Fprintf ( out , "%s=%s\n" , key , labels [ key ] )
i ++
}
}
2016-03-31 03:42:57 +00:00
// printTaintsMultiline prints multiple taints with a proper alignment.
func printTaintsInAnnotationMultiline ( out io . Writer , title string , annotations map [ string ] string ) {
taints , err := api . GetTaintsFromNodeAnnotations ( annotations )
if err != nil {
taints = [ ] api . Taint { }
}
printTaintsMultilineWithIndent ( out , "" , title , "\t" , taints )
}
// printTaintsMultilineWithIndent prints multiple taints with a user-defined alignment.
func printTaintsMultilineWithIndent ( out io . Writer , initialIndent , title , innerIndent string , taints [ ] api . Taint ) {
fmt . Fprintf ( out , "%s%s:%s" , initialIndent , title , innerIndent )
if taints == nil || len ( taints ) == 0 {
fmt . Fprintln ( out , "<none>" )
return
}
// to print taints in the sorted order
keys := make ( [ ] string , 0 , len ( taints ) )
for _ , taint := range taints {
keys = append ( keys , taint . Key )
}
sort . Strings ( keys )
for i , key := range keys {
for _ , taint := range taints {
if taint . Key == key {
if i != 0 {
fmt . Fprint ( out , initialIndent )
fmt . Fprint ( out , innerIndent )
}
fmt . Fprintf ( out , "%s=%s:%s\n" , taint . Key , taint . Value , taint . Effect )
i ++
}
}
}
}