1
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
36 type REST struct {
37 *genericregistry.Store
38 }
39
40
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
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)
61 }
62 return &REST{store}
63 }
64
65
66 var _ rest.CategoriesProvider = &REST{}
67
68
69 func (c *REST) Categories() []string {
70 return []string{"api-extensions"}
71 }
72
73 var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
74
75
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
128
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
140 type StatusREST struct {
141 store *genericregistry.Store
142 }
143
144 var _ = rest.Patcher(&StatusREST{})
145
146
147 func (r *StatusREST) New() runtime.Object {
148 return &apiregistration.APIService{}
149 }
150
151
152 func (r *StatusREST) Destroy() {
153
154
155 }
156
157
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
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
165
166 return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options)
167 }
168
169
170 func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set {
171 return r.store.GetResetFields()
172 }
173
View as plain text