...

Source file src/k8s.io/kube-aggregator/pkg/registry/apiservice/etcd/etcd.go

Documentation: k8s.io/kube-aggregator/pkg/registry/apiservice/etcd

     1  /*
     2  Copyright 2016 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 etcd
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"k8s.io/apimachinery/pkg/api/meta"
    24  	metatable "k8s.io/apimachinery/pkg/api/meta/table"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/apiserver/pkg/registry/generic"
    28  	genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
    29  	"k8s.io/apiserver/pkg/registry/rest"
    30  	"k8s.io/kube-aggregator/pkg/apis/apiregistration"
    31  	"k8s.io/kube-aggregator/pkg/registry/apiservice"
    32  	"sigs.k8s.io/structured-merge-diff/v4/fieldpath"
    33  )
    34  
    35  // REST implements a RESTStorage for API services against etcd
    36  type REST struct {
    37  	*genericregistry.Store
    38  }
    39  
    40  // NewREST returns a RESTStorage object that will work against API services.
    41  func NewREST(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) *REST {
    42  	strategy := apiservice.NewStrategy(scheme)
    43  	store := &genericregistry.Store{
    44  		NewFunc:                   func() runtime.Object { return &apiregistration.APIService{} },
    45  		NewListFunc:               func() runtime.Object { return &apiregistration.APIServiceList{} },
    46  		PredicateFunc:             apiservice.MatchAPIService,
    47  		DefaultQualifiedResource:  apiregistration.Resource("apiservices"),
    48  		SingularQualifiedResource: apiregistration.Resource("apiservice"),
    49  
    50  		CreateStrategy:      strategy,
    51  		UpdateStrategy:      strategy,
    52  		DeleteStrategy:      strategy,
    53  		ResetFieldsStrategy: strategy,
    54  
    55  		// TODO: define table converter that exposes more than name/creation timestamp
    56  		TableConvertor: rest.NewDefaultTableConvertor(apiregistration.Resource("apiservices")),
    57  	}
    58  	options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: apiservice.GetAttrs}
    59  	if err := store.CompleteWithOptions(options); err != nil {
    60  		panic(err) // TODO: Propagate error up
    61  	}
    62  	return &REST{store}
    63  }
    64  
    65  // Implement CategoriesProvider
    66  var _ rest.CategoriesProvider = &REST{}
    67  
    68  // Categories implements the CategoriesProvider interface. Returns a list of categories a resource is part of.
    69  func (c *REST) Categories() []string {
    70  	return []string{"api-extensions"}
    71  }
    72  
    73  var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
    74  
    75  // ConvertToTable implements the TableConvertor interface for REST.
    76  func (c *REST) ConvertToTable(ctx context.Context, obj runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
    77  	table := &metav1.Table{
    78  		ColumnDefinitions: []metav1.TableColumnDefinition{
    79  			{Name: "Name", Type: "string", Format: "name", Description: swaggerMetadataDescriptions["name"]},
    80  			{Name: "Service", Type: "string", Description: "The reference to the service that hosts this API endpoint."},
    81  			{Name: "Available", Type: "string", Description: "Whether this service is available."},
    82  			{Name: "Age", Type: "string", Description: swaggerMetadataDescriptions["creationTimestamp"]},
    83  		},
    84  	}
    85  	if m, err := meta.ListAccessor(obj); err == nil {
    86  		table.ResourceVersion = m.GetResourceVersion()
    87  		table.Continue = m.GetContinue()
    88  		table.RemainingItemCount = m.GetRemainingItemCount()
    89  	} else {
    90  		if m, err := meta.CommonAccessor(obj); err == nil {
    91  			table.ResourceVersion = m.GetResourceVersion()
    92  		}
    93  	}
    94  
    95  	var err error
    96  	table.Rows, err = metatable.MetaToTableRow(obj, func(obj runtime.Object, m metav1.Object, name, age string) ([]interface{}, error) {
    97  		svc := obj.(*apiregistration.APIService)
    98  		service := "Local"
    99  		if svc.Spec.Service != nil {
   100  			service = fmt.Sprintf("%s/%s", svc.Spec.Service.Namespace, svc.Spec.Service.Name)
   101  		}
   102  		status := string(apiregistration.ConditionUnknown)
   103  		if condition := getCondition(svc.Status.Conditions, "Available"); condition != nil {
   104  			switch {
   105  			case condition.Status == apiregistration.ConditionTrue:
   106  				status = string(condition.Status)
   107  			case len(condition.Reason) > 0:
   108  				status = fmt.Sprintf("%s (%s)", condition.Status, condition.Reason)
   109  			default:
   110  				status = string(condition.Status)
   111  			}
   112  		}
   113  		return []interface{}{name, service, status, age}, nil
   114  	})
   115  	return table, err
   116  }
   117  
   118  func getCondition(conditions []apiregistration.APIServiceCondition, conditionType apiregistration.APIServiceConditionType) *apiregistration.APIServiceCondition {
   119  	for i, condition := range conditions {
   120  		if condition.Type == conditionType {
   121  			return &conditions[i]
   122  		}
   123  	}
   124  	return nil
   125  }
   126  
   127  // NewStatusREST makes a RESTStorage for status that has more limited options.
   128  // It is based on the original REST so that we can share the same underlying store
   129  func NewStatusREST(scheme *runtime.Scheme, rest *REST) *StatusREST {
   130  	strategy := apiservice.NewStatusStrategy(scheme)
   131  	statusStore := *rest.Store
   132  	statusStore.CreateStrategy = nil
   133  	statusStore.DeleteStrategy = nil
   134  	statusStore.UpdateStrategy = strategy
   135  	statusStore.ResetFieldsStrategy = strategy
   136  	return &StatusREST{store: &statusStore}
   137  }
   138  
   139  // StatusREST implements the REST endpoint for changing the status of an APIService.
   140  type StatusREST struct {
   141  	store *genericregistry.Store
   142  }
   143  
   144  var _ = rest.Patcher(&StatusREST{})
   145  
   146  // New creates a new APIService object.
   147  func (r *StatusREST) New() runtime.Object {
   148  	return &apiregistration.APIService{}
   149  }
   150  
   151  // Destroy cleans up resources on shutdown.
   152  func (r *StatusREST) Destroy() {
   153  	// Given that underlying store is shared with REST,
   154  	// we don't destroy it here explicitly.
   155  }
   156  
   157  // Get retrieves the object from the storage. It is required to support Patch.
   158  func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
   159  	return r.store.Get(ctx, name, options)
   160  }
   161  
   162  // Update alters the status subset of an object.
   163  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) {
   164  	// We are explicitly setting forceAllowCreate to false in the call to the underlying storage because
   165  	// subresources should never allow create on update.
   166  	return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
   167  }
   168  
   169  // GetResetFields implements rest.ResetFieldsStrategy
   170  func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
   171  	return r.store.GetResetFields()
   172  }
   173  

View as plain text