k8s.io/kubernetes@v1.29.3/pkg/registry/core/componentstatus/rest.go (about) 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 }