k8s.io/kubernetes@v1.29.3/pkg/registry/core/node/storage/storage.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 storage 18 19 import ( 20 "context" 21 "fmt" 22 "net/http" 23 "net/url" 24 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/apimachinery/pkg/runtime" 28 "k8s.io/apiserver/pkg/registry/generic" 29 genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" 30 "k8s.io/apiserver/pkg/registry/rest" 31 api "k8s.io/kubernetes/pkg/apis/core" 32 k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1" 33 "k8s.io/kubernetes/pkg/kubelet/client" 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/registry/core/node" 38 noderest "k8s.io/kubernetes/pkg/registry/core/node/rest" 39 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 40 ) 41 42 // NodeStorage includes storage for nodes and all sub resources. 43 type NodeStorage struct { 44 Node *REST 45 Status *StatusREST 46 Proxy *noderest.ProxyREST 47 48 KubeletConnectionInfo client.ConnectionInfoGetter 49 } 50 51 // REST implements a RESTStorage for nodes. 52 type REST struct { 53 *genericregistry.Store 54 connection client.ConnectionInfoGetter 55 proxyTransport http.RoundTripper 56 } 57 58 // StatusREST implements the REST endpoint for changing the status of a node. 59 type StatusREST struct { 60 store *genericregistry.Store 61 } 62 63 // New creates a new Node object. 64 func (r *StatusREST) New() runtime.Object { 65 return &api.Node{} 66 } 67 68 // Destroy cleans up resources on shutdown. 69 func (r *StatusREST) Destroy() { 70 // Given that underlying store is shared with REST, 71 // we don't destroy it here explicitly. 72 } 73 74 // Get retrieves the object from the storage. It is required to support Patch. 75 func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { 76 return r.store.Get(ctx, name, options) 77 } 78 79 // Update alters the status subset of an object. 80 func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { 81 // We are explicitly setting forceAllowCreate to false in the call to the underlying storage because 82 // subresources should never allow create on update. 83 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) 84 } 85 86 // GetResetFields implements rest.ResetFieldsStrategy 87 func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { 88 return r.store.GetResetFields() 89 } 90 91 func (r *StatusREST) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) { 92 return r.store.ConvertToTable(ctx, object, tableOptions) 93 } 94 95 // NewStorage returns a NodeStorage object that will work against nodes. 96 func NewStorage(optsGetter generic.RESTOptionsGetter, kubeletClientConfig client.KubeletClientConfig, proxyTransport http.RoundTripper) (*NodeStorage, error) { 97 store := &genericregistry.Store{ 98 NewFunc: func() runtime.Object { return &api.Node{} }, 99 NewListFunc: func() runtime.Object { return &api.NodeList{} }, 100 PredicateFunc: node.MatchNode, 101 DefaultQualifiedResource: api.Resource("nodes"), 102 SingularQualifiedResource: api.Resource("node"), 103 104 CreateStrategy: node.Strategy, 105 UpdateStrategy: node.Strategy, 106 DeleteStrategy: node.Strategy, 107 ResetFieldsStrategy: node.Strategy, 108 109 TableConvertor: printerstorage.TableConvertor{TableGenerator: printers.NewTableGenerator().With(printersinternal.AddHandlers)}, 110 } 111 options := &generic.StoreOptions{ 112 RESTOptions: optsGetter, 113 AttrFunc: node.GetAttrs, 114 } 115 if err := store.CompleteWithOptions(options); err != nil { 116 return nil, err 117 } 118 119 statusStore := *store 120 statusStore.UpdateStrategy = node.StatusStrategy 121 statusStore.ResetFieldsStrategy = node.StatusStrategy 122 123 // Set up REST handlers 124 nodeREST := &REST{Store: store, proxyTransport: proxyTransport} 125 statusREST := &StatusREST{store: &statusStore} 126 proxyREST := &noderest.ProxyREST{Store: store, ProxyTransport: proxyTransport} 127 128 // Build a NodeGetter that looks up nodes using the REST handler 129 nodeGetter := client.NodeGetterFunc(func(ctx context.Context, nodeName string, options metav1.GetOptions) (*v1.Node, error) { 130 obj, err := nodeREST.Get(ctx, nodeName, &options) 131 if err != nil { 132 return nil, err 133 } 134 node, ok := obj.(*api.Node) 135 if !ok { 136 return nil, fmt.Errorf("unexpected type %T", obj) 137 } 138 // TODO: Remove the conversion. Consider only return the NodeAddresses 139 externalNode := &v1.Node{} 140 err = k8s_api_v1.Convert_core_Node_To_v1_Node(node, externalNode, nil) 141 if err != nil { 142 return nil, fmt.Errorf("failed to convert to v1.Node: %v", err) 143 } 144 return externalNode, nil 145 }) 146 connectionInfoGetter, err := client.NewNodeConnectionInfoGetter(nodeGetter, kubeletClientConfig) 147 if err != nil { 148 return nil, err 149 } 150 nodeREST.connection = connectionInfoGetter 151 proxyREST.Connection = connectionInfoGetter 152 153 return &NodeStorage{ 154 Node: nodeREST, 155 Status: statusREST, 156 Proxy: proxyREST, 157 KubeletConnectionInfo: connectionInfoGetter, 158 }, nil 159 } 160 161 // Implement Redirector. 162 var _ = rest.Redirector(&REST{}) 163 164 // ResourceLocation returns a URL to which one can send traffic for the specified node. 165 func (r *REST) ResourceLocation(ctx context.Context, id string) (*url.URL, http.RoundTripper, error) { 166 return node.ResourceLocation(r, r.connection, r.proxyTransport, ctx, id) 167 } 168 169 // ShortNames implements the ShortNamesProvider interface. Returns a list of short names for a resource. 170 func (r *REST) ShortNames() []string { 171 return []string{"no"} 172 }