Skip to content

Commit 86dd4ce

Browse files
Chao Xuroycaihw
andcommitted
Let kube-apiserver host the storage version API
Co-authored-by: Haowei Cai <[email protected]>
1 parent 3cf8009 commit 86dd4ce

File tree

16 files changed

+569
-2
lines changed

16 files changed

+569
-2
lines changed

cmd/kube-apiserver/app/aggregator.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ var apiVersionPriorities = map[schema.GroupVersion]priority{
275275
{Group: "discovery.k8s.io", Version: "v1beta1"}: {group: 16200, version: 12},
276276
{Group: "discovery.k8s.io", Version: "v1alpha1"}: {group: 16200, version: 9},
277277
{Group: "flowcontrol.apiserver.k8s.io", Version: "v1alpha1"}: {group: 16100, version: 9},
278+
{Group: "internal.apiserver.k8s.io", Version: "v1alpha1"}: {group: 16000, version: 9},
278279
// Append a new group to the end of the list if unsure.
279280
// You can use min(existing group)-100 as the initial value for a group.
280281
// Version can be set to 9 (to have space around) for a new group.

pkg/apis/apiserverinternal/install/install.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,15 @@ package install
2121
import (
2222
"k8s.io/apimachinery/pkg/runtime"
2323
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
24+
"k8s.io/kubernetes/pkg/api/legacyscheme"
2425
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
2526
"k8s.io/kubernetes/pkg/apis/apiserverinternal/v1alpha1"
2627
)
2728

29+
func init() {
30+
Install(legacyscheme.Scheme)
31+
}
32+
2833
// Install registers the API group and adds types to a scheme
2934
func Install(scheme *runtime.Scheme) {
3035
utilruntime.Must(apiserverinternal.AddToScheme(scheme))

pkg/apis/apiserverinternal/validation/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ go_library(
77
visibility = ["//visibility:public"],
88
deps = [
99
"//pkg/apis/apiserverinternal:go_default_library",
10+
"//pkg/apis/core/validation:go_default_library",
1011
"//staging/src/k8s.io/apimachinery/pkg/api/validation:go_default_library",
1112
"//staging/src/k8s.io/apimachinery/pkg/util/validation:go_default_library",
1213
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",

pkg/apis/apiserverinternal/validation/validation.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,42 @@ import (
2525
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
2626
"k8s.io/apimachinery/pkg/util/validation/field"
2727
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
28+
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
2829
)
2930

3031
// ValidateStorageVersion validate the storage version object.
3132
func ValidateStorageVersion(sv *apiserverinternal.StorageVersion) field.ErrorList {
33+
var allErrs field.ErrorList
34+
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&sv.ObjectMeta, false, ValidateStorageVersionName, field.NewPath("metadata"))...)
35+
allErrs = append(allErrs, validateStorageVersionStatus(sv.Status, field.NewPath("status"))...)
36+
return allErrs
37+
}
38+
39+
// ValidateStorageVersionName is a ValidateNameFunc for storage version names
40+
func ValidateStorageVersionName(name string, prefix bool) []string {
41+
var allErrs []string
42+
idx := strings.LastIndex(name, ".")
43+
if idx < 0 {
44+
allErrs = append(allErrs, "name must be in the form of <group>.<resource>")
45+
} else {
46+
for _, msg := range utilvalidation.IsDNS1123Subdomain(name[:idx]) {
47+
allErrs = append(allErrs, "the group segment "+msg)
48+
}
49+
for _, msg := range utilvalidation.IsDNS1035Label(name[idx+1:]) {
50+
allErrs = append(allErrs, "the resource segment "+msg)
51+
}
52+
}
53+
return allErrs
54+
}
55+
56+
// ValidateStorageVersionUpdate tests if an update to a StorageVersion is valid.
57+
func ValidateStorageVersionUpdate(sv, oldSV *apiserverinternal.StorageVersion) field.ErrorList {
58+
// no error since StorageVersionSpec is an empty spec
59+
return field.ErrorList{}
60+
}
61+
62+
// ValidateStorageVersionStatusUpdate tests if an update to a StorageVersionStatus is valid.
63+
func ValidateStorageVersionStatusUpdate(sv, oldSV *apiserverinternal.StorageVersion) field.ErrorList {
3264
var allErrs field.ErrorList
3365
allErrs = append(allErrs, validateStorageVersionStatus(sv.Status, field.NewPath("status"))...)
3466
return allErrs

pkg/apis/apiserverinternal/validation/validation_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,3 +284,66 @@ func TestValidateStorageVersionCondition(t *testing.T) {
284284
}
285285
}
286286
}
287+
288+
func TestValidateStorageVersionName(t *testing.T) {
289+
cases := []struct {
290+
name string
291+
expectedErr string
292+
}{
293+
{
294+
name: "",
295+
expectedErr: `name must be in the form of <group>.<resource>`,
296+
},
297+
{
298+
name: "pods",
299+
expectedErr: `name must be in the form of <group>.<resource>`,
300+
},
301+
{
302+
name: "core.pods",
303+
expectedErr: "",
304+
},
305+
{
306+
name: "authentication.k8s.io.tokenreviews",
307+
expectedErr: "",
308+
},
309+
{
310+
name: strings.Repeat("x", 253) + ".tokenreviews",
311+
expectedErr: "",
312+
},
313+
{
314+
name: strings.Repeat("x", 254) + ".tokenreviews",
315+
expectedErr: `the group segment must be no more than 253 characters`,
316+
},
317+
{
318+
name: "authentication.k8s.io." + strings.Repeat("x", 63),
319+
expectedErr: "",
320+
},
321+
{
322+
name: "authentication.k8s.io." + strings.Repeat("x", 64),
323+
expectedErr: `the resource segment must be no more than 63 characters`,
324+
},
325+
}
326+
for _, tc := range cases {
327+
errs := ValidateStorageVersionName(tc.name, false)
328+
if errs == nil && len(tc.expectedErr) == 0 {
329+
continue
330+
}
331+
if errs != nil && len(tc.expectedErr) == 0 {
332+
t.Errorf("unexpected error %v", errs)
333+
continue
334+
}
335+
if errs == nil && len(tc.expectedErr) != 0 {
336+
t.Errorf("unexpected empty error")
337+
continue
338+
}
339+
found := false
340+
for _, msg := range errs {
341+
if msg == tc.expectedErr {
342+
found = true
343+
}
344+
}
345+
if !found {
346+
t.Errorf("expected error to contain %s, got %v", tc.expectedErr, errs)
347+
}
348+
}
349+
}

pkg/controlplane/master.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727

2828
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
2929
admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1"
30+
apiserverinternalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1"
3031
appsv1 "k8s.io/api/apps/v1"
3132
authenticationv1 "k8s.io/api/authentication/v1"
3233
authenticationv1beta1 "k8s.io/api/authentication/v1beta1"
@@ -93,6 +94,7 @@ import (
9394

9495
// RESTStorage installers
9596
admissionregistrationrest "k8s.io/kubernetes/pkg/registry/admissionregistration/rest"
97+
apiserverinternalrest "k8s.io/kubernetes/pkg/registry/apiserverinternal/rest"
9698
appsrest "k8s.io/kubernetes/pkg/registry/apps/rest"
9799
authenticationrest "k8s.io/kubernetes/pkg/registry/authentication/rest"
98100
authorizationrest "k8s.io/kubernetes/pkg/registry/authorization/rest"
@@ -415,6 +417,7 @@ func (c completedConfig) New(delegationTarget genericapiserver.DelegationTarget)
415417
// TODO: describe the priority all the way down in the RESTStorageProviders and plumb it back through the various discovery
416418
// handlers that we have.
417419
restStorageProviders := []RESTStorageProvider{
420+
apiserverinternalrest.StorageProvider{},
418421
authenticationrest.RESTStorageProvider{Authenticator: c.GenericConfig.Authentication.Authenticator, APIAudiences: c.GenericConfig.Authentication.APIAudiences},
419422
authorizationrest.RESTStorageProvider{Authorizer: c.GenericConfig.Authorization.Authorizer, RuleResolver: c.GenericConfig.RuleResolver},
420423
autoscalingrest.RESTStorageProvider{},
@@ -633,6 +636,7 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
633636
)
634637
// disable alpha versions explicitly so we have a full list of what's possible to serve
635638
ret.DisableVersions(
639+
apiserverinternalv1alpha1.SchemeGroupVersion,
636640
batchapiv2alpha1.SchemeGroupVersion,
637641
nodev1alpha1.SchemeGroupVersion,
638642
rbacv1alpha1.SchemeGroupVersion,

pkg/printers/internalversion/printers.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"strings"
2626
"time"
2727

28+
apiserverinternalv1alpha1 "k8s.io/api/apiserverinternal/v1alpha1"
2829
appsv1beta1 "k8s.io/api/apps/v1beta1"
2930
autoscalingv2beta1 "k8s.io/api/autoscaling/v2beta1"
3031
batchv1 "k8s.io/api/batch/v1"
@@ -48,6 +49,7 @@ import (
4849
"k8s.io/apimachinery/pkg/util/sets"
4950
utilfeature "k8s.io/apiserver/pkg/util/feature"
5051
"k8s.io/kubernetes/pkg/apis/admissionregistration"
52+
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
5153
"k8s.io/kubernetes/pkg/apis/apps"
5254
"k8s.io/kubernetes/pkg/apis/autoscaling"
5355
"k8s.io/kubernetes/pkg/apis/batch"
@@ -571,6 +573,15 @@ func AddHandlers(h printers.PrintHandler) {
571573
}
572574
h.TableHandler(priorityLevelColumnDefinitions, printPriorityLevelConfiguration)
573575
h.TableHandler(priorityLevelColumnDefinitions, printPriorityLevelConfigurationList)
576+
577+
storageVersionColumnDefinitions := []metav1.TableColumnDefinition{
578+
{Name: "Name", Type: "string", Format: "name", Description: metav1.ObjectMeta{}.SwaggerDoc()["name"]},
579+
{Name: "CommonEncodingVersion", Type: "string", Description: apiserverinternalv1alpha1.StorageVersionStatus{}.SwaggerDoc()["commonEncodingVersion"]},
580+
{Name: "StorageVersions", Type: "string", Description: apiserverinternalv1alpha1.StorageVersionStatus{}.SwaggerDoc()["storageVersions"]},
581+
{Name: "Age", Type: "string", Description: metav1.ObjectMeta{}.SwaggerDoc()["creationTimestamp"]},
582+
}
583+
h.TableHandler(storageVersionColumnDefinitions, printStorageVersion)
584+
h.TableHandler(storageVersionColumnDefinitions, printStorageVersionList)
574585
}
575586

576587
// Pass ports=nil for all ports.
@@ -2477,6 +2488,46 @@ func printFlowSchemaList(list *flowcontrol.FlowSchemaList, options printers.Gene
24772488
return rows, nil
24782489
}
24792490

2491+
func printStorageVersion(obj *apiserverinternal.StorageVersion, options printers.GenerateOptions) ([]metav1.TableRow, error) {
2492+
row := metav1.TableRow{
2493+
Object: runtime.RawExtension{Object: obj},
2494+
}
2495+
commonEncodingVersion := "<unset>"
2496+
if obj.Status.CommonEncodingVersion != nil {
2497+
commonEncodingVersion = *obj.Status.CommonEncodingVersion
2498+
}
2499+
row.Cells = append(row.Cells, obj.Name, commonEncodingVersion, formatStorageVersions(obj.Status.StorageVersions), translateTimestampSince(obj.CreationTimestamp))
2500+
return []metav1.TableRow{row}, nil
2501+
}
2502+
2503+
func formatStorageVersions(storageVersions []apiserverinternal.ServerStorageVersion) string {
2504+
list := []string{}
2505+
max := 3
2506+
more := false
2507+
count := 0
2508+
for _, sv := range storageVersions {
2509+
if len(list) < max {
2510+
list = append(list, fmt.Sprintf("%s=%s", sv.APIServerID, sv.EncodingVersion))
2511+
} else if len(list) == max {
2512+
more = true
2513+
}
2514+
count++
2515+
}
2516+
return listWithMoreString(list, more, count, max)
2517+
}
2518+
2519+
func printStorageVersionList(list *apiserverinternal.StorageVersionList, options printers.GenerateOptions) ([]metav1.TableRow, error) {
2520+
rows := make([]metav1.TableRow, 0, len(list.Items))
2521+
for i := range list.Items {
2522+
r, err := printStorageVersion(&list.Items[i], options)
2523+
if err != nil {
2524+
return nil, err
2525+
}
2526+
rows = append(rows, r...)
2527+
}
2528+
return rows, nil
2529+
}
2530+
24802531
func printPriorityLevelConfiguration(obj *flowcontrol.PriorityLevelConfiguration, options printers.GenerateOptions) ([]metav1.TableRow, error) {
24812532
row := metav1.TableRow{
24822533
Object: runtime.RawExtension{Object: obj},

pkg/printers/internalversion/printers_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/apimachinery/pkg/runtime/schema"
2828
"k8s.io/apimachinery/pkg/util/diff"
2929
"k8s.io/apimachinery/pkg/util/intstr"
30+
"k8s.io/kubernetes/pkg/apis/apiserverinternal"
3031
"k8s.io/kubernetes/pkg/apis/apps"
3132
"k8s.io/kubernetes/pkg/apis/autoscaling"
3233
"k8s.io/kubernetes/pkg/apis/batch"
@@ -5311,3 +5312,125 @@ func TestPrintPriorityLevelConfiguration(t *testing.T) {
53115312
}
53125313
}
53135314
}
5315+
5316+
func TestPrintStorageVersion(t *testing.T) {
5317+
commonEncodingVersion := "v1"
5318+
tests := []struct {
5319+
sv apiserverinternal.StorageVersion
5320+
expected []metav1.TableRow
5321+
}{
5322+
{
5323+
sv: apiserverinternal.StorageVersion{
5324+
ObjectMeta: metav1.ObjectMeta{
5325+
Name: "empty",
5326+
CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5327+
},
5328+
Status: apiserverinternal.StorageVersionStatus{},
5329+
},
5330+
// Columns: Name, CommonEncodingVersion, StorageVersions, Age
5331+
expected: []metav1.TableRow{{Cells: []interface{}{"empty", "<unset>", "<unset>", "0s"}}},
5332+
},
5333+
{
5334+
sv: apiserverinternal.StorageVersion{
5335+
ObjectMeta: metav1.ObjectMeta{
5336+
Name: "valid",
5337+
CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5338+
},
5339+
Status: apiserverinternal.StorageVersionStatus{
5340+
StorageVersions: []apiserverinternal.ServerStorageVersion{
5341+
{
5342+
APIServerID: "1",
5343+
EncodingVersion: "v1",
5344+
DecodableVersions: []string{"v1"},
5345+
},
5346+
{
5347+
APIServerID: "2",
5348+
EncodingVersion: "v1",
5349+
DecodableVersions: []string{"v1", "v2"},
5350+
},
5351+
},
5352+
CommonEncodingVersion: &commonEncodingVersion,
5353+
},
5354+
},
5355+
// Columns: Name, CommonEncodingVersion, StorageVersions, Age
5356+
expected: []metav1.TableRow{{Cells: []interface{}{"valid", "v1", "1=v1,2=v1", "0s"}}},
5357+
},
5358+
{
5359+
sv: apiserverinternal.StorageVersion{
5360+
ObjectMeta: metav1.ObjectMeta{
5361+
Name: "disagree",
5362+
CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5363+
},
5364+
Status: apiserverinternal.StorageVersionStatus{
5365+
StorageVersions: []apiserverinternal.ServerStorageVersion{
5366+
{
5367+
APIServerID: "1",
5368+
EncodingVersion: "v1",
5369+
DecodableVersions: []string{"v1"},
5370+
},
5371+
{
5372+
APIServerID: "2",
5373+
EncodingVersion: "v1",
5374+
DecodableVersions: []string{"v1", "v2"},
5375+
},
5376+
{
5377+
APIServerID: "3",
5378+
EncodingVersion: "v2",
5379+
DecodableVersions: []string{"v2"},
5380+
},
5381+
},
5382+
},
5383+
},
5384+
// Columns: Name, CommonEncodingVersion, StorageVersions, Age
5385+
expected: []metav1.TableRow{{Cells: []interface{}{"disagree", "<unset>", "1=v1,2=v1,3=v2", "0s"}}},
5386+
},
5387+
{
5388+
sv: apiserverinternal.StorageVersion{
5389+
ObjectMeta: metav1.ObjectMeta{
5390+
Name: "agreeWithMore",
5391+
CreationTimestamp: metav1.Time{Time: time.Now().Add(1.9e9)},
5392+
},
5393+
Status: apiserverinternal.StorageVersionStatus{
5394+
StorageVersions: []apiserverinternal.ServerStorageVersion{
5395+
{
5396+
APIServerID: "1",
5397+
EncodingVersion: "v1",
5398+
DecodableVersions: []string{"v1"},
5399+
},
5400+
{
5401+
APIServerID: "2",
5402+
EncodingVersion: "v1",
5403+
DecodableVersions: []string{"v1", "v2"},
5404+
},
5405+
{
5406+
APIServerID: "3",
5407+
EncodingVersion: "v1",
5408+
DecodableVersions: []string{"v1", "v2"},
5409+
},
5410+
{
5411+
APIServerID: "4",
5412+
EncodingVersion: "v1",
5413+
DecodableVersions: []string{"v1", "v2", "v3alpha1"},
5414+
},
5415+
},
5416+
CommonEncodingVersion: &commonEncodingVersion,
5417+
},
5418+
},
5419+
// Columns: Name, CommonEncodingVersion, StorageVersions, Age
5420+
expected: []metav1.TableRow{{Cells: []interface{}{"agreeWithMore", "v1", "1=v1,2=v1,3=v1 + 1 more...", "0s"}}},
5421+
},
5422+
}
5423+
5424+
for i, test := range tests {
5425+
rows, err := printStorageVersion(&test.sv, printers.GenerateOptions{})
5426+
if err != nil {
5427+
t.Fatal(err)
5428+
}
5429+
for i := range rows {
5430+
rows[i].Object.Object = nil
5431+
}
5432+
if !reflect.DeepEqual(test.expected, rows) {
5433+
t.Errorf("%d mismatch: %s", i, diff.ObjectReflectDiff(test.expected, rows))
5434+
}
5435+
}
5436+
}

0 commit comments

Comments
 (0)