...

Source file src/k8s.io/kubernetes/pkg/registry/core/componentstatus/rest.go

Documentation: k8s.io/kubernetes/pkg/registry/core/componentstatus

     1  /*
     2  Copyright 2015 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package componentstatus
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"sync"
    23  
    24  	"k8s.io/apimachinery/pkg/fields"
    25  	"k8s.io/apimachinery/pkg/labels"
    26  	"k8s.io/apiserver/pkg/registry/generic"
    27  	"k8s.io/apiserver/pkg/storage"
    28  
    29  	metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion"
    30  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    31  	"k8s.io/apimachinery/pkg/runtime"
    32  	"k8s.io/apiserver/pkg/registry/rest"
    33  	api "k8s.io/kubernetes/pkg/apis/core"
    34  	"k8s.io/kubernetes/pkg/printers"
    35  	printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
    36  	printerstorage "k8s.io/kubernetes/pkg/printers/storage"
    37  	"k8s.io/kubernetes/pkg/probe"
    38  )
    39  
    40  type REST struct {
    41  	GetServersToValidate func() map[string]Server
    42  	rest.TableConvertor
    43  }
    44  
    45  // NewStorage returns a new REST.
    46  func NewStorage(serverRetriever func() map[string]Server) *REST {
    47  	return &REST{
    48  		GetServersToValidate: serverRetriever,
    49  		TableConvertor:       printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)},
    50  	}
    51  }
    52  
    53  func (*REST) NamespaceScoped() bool {
    54  	return false
    55  }
    56  
    57  func (rs *REST) New() runtime.Object {
    58  	return &api.ComponentStatus{}
    59  }
    60  
    61  var _ rest.SingularNameProvider = &REST{}
    62  
    63  func (rs *REST) GetSingularName() string {
    64  	return "componentstatus"
    65  }
    66  
    67  // Destroy cleans up resources on shutdown.
    68  func (r *REST) Destroy() {
    69  	// Given no underlying store, we don't destroy anything
    70  	// here explicitly.
    71  }
    72  
    73  func (rs *REST) NewList() runtime.Object {
    74  	return &api.ComponentStatusList{}
    75  }
    76  
    77  // Returns the list of component status. Note that the label and field are both ignored.
    78  // Note that this call doesn't support labels or selectors.
    79  func (rs *REST) List(ctx context.Context, options *metainternalversion.ListOptions) (runtime.Object, error) {
    80  	servers := rs.GetServersToValidate()
    81  
    82  	wait := sync.WaitGroup{}
    83  	wait.Add(len(servers))
    84  	statuses := make(chan api.ComponentStatus, len(servers))
    85  	for k, v := range servers {
    86  		go func(name string, server Server) {
    87  			defer wait.Done()
    88  			status := rs.getComponentStatus(name, server)
    89  			statuses <- *status
    90  		}(k, v)
    91  	}
    92  	wait.Wait()
    93  	close(statuses)
    94  
    95  	pred := componentStatusPredicate(options)
    96  
    97  	reply := []api.ComponentStatus{}
    98  	for status := range statuses {
    99  		// ComponentStatus resources currently (v1.14) do not support labeling, however the filtering is executed
   100  		// nonetheless in case the request contains Label or Field selectors (which will effectively filter out
   101  		// all of the results and return an empty response).
   102  		if matched := matchesPredicate(status, &pred); matched {
   103  			reply = append(reply, status)
   104  		}
   105  	}
   106  	return &api.ComponentStatusList{Items: reply}, nil
   107  }
   108  
   109  func componentStatusPredicate(options *metainternalversion.ListOptions) storage.SelectionPredicate {
   110  	pred := storage.SelectionPredicate{
   111  		Label:    labels.Everything(),
   112  		Field:    fields.Everything(),
   113  		GetAttrs: nil,
   114  	}
   115  	if options != nil {
   116  		if options.LabelSelector != nil {
   117  			pred.Label = options.LabelSelector
   118  		}
   119  		if options.FieldSelector != nil {
   120  			pred.Field = options.FieldSelector
   121  		}
   122  	}
   123  	return pred
   124  }
   125  
   126  func matchesPredicate(status api.ComponentStatus, pred *storage.SelectionPredicate) bool {
   127  	// currently no fields except the generic meta fields are supported for predicate matching
   128  	fieldsSet := generic.AddObjectMetaFieldsSet(make(fields.Set, 2), &status.ObjectMeta, true)
   129  	return pred.MatchesObjectAttributes(
   130  		status.ObjectMeta.Labels,
   131  		fieldsSet,
   132  	)
   133  }
   134  
   135  func (rs *REST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
   136  	servers := rs.GetServersToValidate()
   137  
   138  	if server, ok := servers[name]; !ok {
   139  		return nil, fmt.Errorf("Component not found: %s", name)
   140  	} else {
   141  		return rs.getComponentStatus(name, server), nil
   142  	}
   143  }
   144  
   145  func ToConditionStatus(s probe.Result) api.ConditionStatus {
   146  	switch s {
   147  	case probe.Success:
   148  		return api.ConditionTrue
   149  	case probe.Failure:
   150  		return api.ConditionFalse
   151  	default:
   152  		return api.ConditionUnknown
   153  	}
   154  }
   155  
   156  func (rs *REST) getComponentStatus(name string, server Server) *api.ComponentStatus {
   157  	status, msg, err := server.DoServerCheck()
   158  	errorMsg := ""
   159  	if err != nil {
   160  		errorMsg = err.Error()
   161  	}
   162  
   163  	c := &api.ComponentCondition{
   164  		Type:    api.ComponentHealthy,
   165  		Status:  ToConditionStatus(status),
   166  		Message: msg,
   167  		Error:   errorMsg,
   168  	}
   169  
   170  	retVal := &api.ComponentStatus{
   171  		Conditions: []api.ComponentCondition{*c},
   172  	}
   173  	retVal.Name = name
   174  
   175  	return retVal
   176  }
   177  
   178  // Implement ShortNamesProvider
   179  var _ rest.ShortNamesProvider = &REST{}
   180  
   181  // ShortNames implements the ShortNamesProvider interface. Returns a list of short names for a resource.
   182  func (r *REST) ShortNames() []string {
   183  	return []string{"cs"}
   184  }
   185  

View as plain text