Skip to content

Commit eb6a1b6

Browse files
authored
Merge pull request kubernetes#72942 from caesarxuchao/expose-storage-version-hash
Populate the storage version hash
2 parents c094f87 + 887cb93 commit eb6a1b6

File tree

29 files changed

+553
-23
lines changed

29 files changed

+553
-23
lines changed

cmd/kube-apiserver/app/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ go_library(
3939
"//staging/src/k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion:go_default_library",
4040
"//staging/src/k8s.io/apiextensions-apiserver/pkg/cmd/server/options:go_default_library",
4141
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
42+
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
4243
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
4344
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
4445
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",

cmd/kube-apiserver/app/aggregator.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030

3131
apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/internalversion"
3232
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33+
"k8s.io/apimachinery/pkg/runtime"
3334
"k8s.io/apimachinery/pkg/runtime/schema"
3435
"k8s.io/apimachinery/pkg/util/sets"
3536
"k8s.io/apiserver/pkg/admission"
@@ -79,6 +80,7 @@ func createAggregatorConfig(
7980
etcdOptions := *commandOptions.Etcd
8081
etcdOptions.StorageConfig.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking)
8182
etcdOptions.StorageConfig.Codec = aggregatorscheme.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion, v1.SchemeGroupVersion)
83+
etcdOptions.StorageConfig.EncodeVersioner = runtime.NewMultiGroupVersioner(v1beta1.SchemeGroupVersion, schema.GroupKind{Group: v1beta1.GroupName})
8284
genericConfig.RESTOptionsGetter = &genericoptions.SimpleRestOptionsFactory{Options: etcdOptions}
8385

8486
// override MergedResourceConfig with aggregator defaults and registry

cmd/kube-apiserver/app/apiextensions.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
2424
apiextensionsapiserver "k8s.io/apiextensions-apiserver/pkg/apiserver"
2525
apiextensionsoptions "k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
26+
"k8s.io/apimachinery/pkg/runtime"
27+
"k8s.io/apimachinery/pkg/runtime/schema"
2628
"k8s.io/apiserver/pkg/admission"
2729
"k8s.io/apiserver/pkg/features"
2830
genericapiserver "k8s.io/apiserver/pkg/server"
@@ -61,6 +63,7 @@ func createAPIExtensionsConfig(
6163
etcdOptions := *commandOptions.Etcd
6264
etcdOptions.StorageConfig.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking)
6365
etcdOptions.StorageConfig.Codec = apiextensionsapiserver.Codecs.LegacyCodec(v1beta1.SchemeGroupVersion)
66+
etcdOptions.StorageConfig.EncodeVersioner = runtime.NewMultiGroupVersioner(v1beta1.SchemeGroupVersion, schema.GroupKind{Group: v1beta1.GroupName})
6467
genericConfig.RESTOptionsGetter = &genericoptions.SimpleRestOptionsFactory{Options: etcdOptions}
6568

6669
// override MergedResourceConfig with apiextensions defaults and registry

pkg/master/BUILD

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,13 @@ go_test(
141141
deps = [
142142
"//pkg/api/legacyscheme:go_default_library",
143143
"//pkg/api/testapi:go_default_library",
144+
"//pkg/apis/batch:go_default_library",
144145
"//pkg/apis/core:go_default_library",
146+
"//pkg/apis/storage:go_default_library",
145147
"//pkg/generated/openapi:go_default_library",
146148
"//pkg/kubelet/client:go_default_library",
147149
"//pkg/master/reconcilers:go_default_library",
150+
"//pkg/master/storageversionhashdata:go_default_library",
148151
"//pkg/registry/certificates/rest:go_default_library",
149152
"//pkg/registry/core/rest:go_default_library",
150153
"//pkg/registry/registrytest:go_default_library",
@@ -154,16 +157,23 @@ go_test(
154157
"//staging/src/k8s.io/apimachinery/pkg/api/apitesting/naming:go_default_library",
155158
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
156159
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
160+
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
157161
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
158162
"//staging/src/k8s.io/apimachinery/pkg/util/intstr:go_default_library",
159163
"//staging/src/k8s.io/apimachinery/pkg/util/net:go_default_library",
160164
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
161165
"//staging/src/k8s.io/apimachinery/pkg/version:go_default_library",
166+
"//staging/src/k8s.io/apiserver/pkg/authorization/authorizerfactory:go_default_library",
162167
"//staging/src/k8s.io/apiserver/pkg/endpoints/openapi:go_default_library",
168+
"//staging/src/k8s.io/apiserver/pkg/features:go_default_library",
163169
"//staging/src/k8s.io/apiserver/pkg/server:go_default_library",
164170
"//staging/src/k8s.io/apiserver/pkg/server/options:go_default_library",
171+
"//staging/src/k8s.io/apiserver/pkg/server/resourceconfig:go_default_library",
165172
"//staging/src/k8s.io/apiserver/pkg/server/storage:go_default_library",
166173
"//staging/src/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library",
174+
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
175+
"//staging/src/k8s.io/apiserver/pkg/util/feature/testing:go_default_library",
176+
"//staging/src/k8s.io/client-go/discovery:go_default_library",
167177
"//staging/src/k8s.io/client-go/informers:go_default_library",
168178
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
169179
"//staging/src/k8s.io/client-go/kubernetes/fake:go_default_library",
@@ -191,6 +201,7 @@ filegroup(
191201
"//pkg/master/controller/crdregistration:all-srcs",
192202
"//pkg/master/ports:all-srcs",
193203
"//pkg/master/reconcilers:all-srcs",
204+
"//pkg/master/storageversionhashdata:all-srcs",
194205
"//pkg/master/tunneler:all-srcs",
195206
],
196207
tags = ["automanaged"],

pkg/master/master_test.go

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,32 @@ import (
3131
certificatesapiv1beta1 "k8s.io/api/certificates/v1beta1"
3232
apiv1 "k8s.io/api/core/v1"
3333
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34+
"k8s.io/apimachinery/pkg/runtime/schema"
3435
utilnet "k8s.io/apimachinery/pkg/util/net"
3536
"k8s.io/apimachinery/pkg/util/sets"
3637
"k8s.io/apimachinery/pkg/version"
38+
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
39+
"k8s.io/apiserver/pkg/features"
3740
genericapiserver "k8s.io/apiserver/pkg/server"
3841
"k8s.io/apiserver/pkg/server/options"
42+
"k8s.io/apiserver/pkg/server/resourceconfig"
3943
serverstorage "k8s.io/apiserver/pkg/server/storage"
4044
etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing"
45+
utilfeature "k8s.io/apiserver/pkg/util/feature"
46+
utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing"
47+
"k8s.io/client-go/discovery"
4148
"k8s.io/client-go/informers"
4249
"k8s.io/client-go/kubernetes"
4350
"k8s.io/client-go/kubernetes/fake"
4451
restclient "k8s.io/client-go/rest"
4552
"k8s.io/kubernetes/pkg/api/legacyscheme"
4653
"k8s.io/kubernetes/pkg/api/testapi"
54+
"k8s.io/kubernetes/pkg/apis/batch"
4755
api "k8s.io/kubernetes/pkg/apis/core"
56+
apisstorage "k8s.io/kubernetes/pkg/apis/storage"
4857
kubeletclient "k8s.io/kubernetes/pkg/kubelet/client"
4958
"k8s.io/kubernetes/pkg/master/reconcilers"
59+
"k8s.io/kubernetes/pkg/master/storageversionhashdata"
5060
certificatesrest "k8s.io/kubernetes/pkg/registry/certificates/rest"
5161
corerest "k8s.io/kubernetes/pkg/registry/core/rest"
5262
"k8s.io/kubernetes/pkg/registry/registrytest"
@@ -70,6 +80,14 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
7080
}
7181

7282
resourceEncoding := serverstorage.NewDefaultResourceEncodingConfig(legacyscheme.Scheme)
83+
// This configures the testing master the same way the real master is
84+
// configured. The storage versions of these resources are different
85+
// from the storage versions of other resources in their group.
86+
resourceEncodingOverrides := []schema.GroupVersionResource{
87+
batch.Resource("cronjobs").WithVersion("v1beta1"),
88+
apisstorage.Resource("volumeattachments").WithVersion("v1beta1"),
89+
}
90+
resourceEncoding = resourceconfig.MergeResourceEncodingConfigs(resourceEncoding, resourceEncodingOverrides)
7391
storageFactory := serverstorage.NewDefaultStorageFactory(*storageConfig, testapi.StorageMediaType(), legacyscheme.Codecs, resourceEncoding, DefaultAPIResourceConfigSource(), nil)
7492

7593
etcdOptions := options.NewEtcdOptions(storageConfig)
@@ -81,12 +99,12 @@ func setUp(t *testing.T) (*etcdtesting.EtcdTestServer, Config, *assert.Assertion
8199
}
82100

83101
kubeVersion := kubeversion.Get()
102+
config.GenericConfig.Authorization.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
84103
config.GenericConfig.Version = &kubeVersion
85104
config.ExtraConfig.StorageFactory = storageFactory
86105
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
87106
config.GenericConfig.PublicAddress = net.ParseIP("192.168.10.4")
88107
config.GenericConfig.LegacyAPIGroupPrefixes = sets.NewString("/api")
89-
config.GenericConfig.LoopbackClientConfig = &restclient.Config{APIPath: "/api", ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs}}
90108
config.ExtraConfig.KubeletClientConfig = kubeletclient.KubeletClientConfig{Port: 10250}
91109
config.ExtraConfig.ProxyTransport = utilnet.SetTransportDefaults(&http.Transport{
92110
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) { return nil, nil },
@@ -363,6 +381,112 @@ func TestAPIVersionOfDiscoveryEndpoints(t *testing.T) {
363381

364382
}
365383

384+
// This test doesn't cover the apiregistration and apiextensions group, as they are installed by other apiservers.
385+
func TestStorageVersionHashes(t *testing.T) {
386+
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StorageVersionHash, true)()
387+
master, etcdserver, _, _ := newMaster(t)
388+
defer etcdserver.Terminate(t)
389+
390+
server := httptest.NewServer(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux)
391+
392+
c := &restclient.Config{
393+
Host: server.URL,
394+
APIPath: "/api",
395+
ContentConfig: restclient.ContentConfig{NegotiatedSerializer: legacyscheme.Codecs},
396+
}
397+
discover := discovery.NewDiscoveryClientForConfigOrDie(c)
398+
all, err := discover.ServerResources()
399+
if err != nil {
400+
t.Error(err)
401+
}
402+
var count int
403+
for _, g := range all {
404+
for _, r := range g.APIResources {
405+
if strings.Contains(r.Name, "/") ||
406+
storageversionhashdata.NoStorageVersionHash.Has(g.GroupVersion+"/"+r.Name) {
407+
if r.StorageVersionHash != "" {
408+
t.Errorf("expect resource %s/%s to have empty storageVersionHash, got hash %q", g.GroupVersion, r.Name, r.StorageVersionHash)
409+
}
410+
continue
411+
}
412+
if r.StorageVersionHash == "" {
413+
t.Errorf("expect the storageVersionHash of %s/%s to exist", g.GroupVersion, r.Name)
414+
continue
415+
}
416+
// Uncomment the following line if you want to update storageversionhash/data.go
417+
// fmt.Printf("\"%s/%s\": \"%s\",\n", g.GroupVersion, r.Name, r.StorageVersionHash)
418+
expected := storageversionhashdata.GVRToStorageVersionHash[g.GroupVersion+"/"+r.Name]
419+
if r.StorageVersionHash != expected {
420+
t.Errorf("expect the storageVersionHash of %s/%s to be %q, got %q", g.GroupVersion, r.Name, expected, r.StorageVersionHash)
421+
}
422+
count++
423+
}
424+
}
425+
if count != len(storageversionhashdata.GVRToStorageVersionHash) {
426+
t.Errorf("please remove the redundant entries from GVRToStorageVersionHash")
427+
}
428+
}
429+
430+
func TestStorageVersionHashEqualities(t *testing.T) {
431+
defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StorageVersionHash, true)()
432+
master, etcdserver, _, assert := newMaster(t)
433+
defer etcdserver.Terminate(t)
434+
435+
server := httptest.NewServer(master.GenericAPIServer.Handler.GoRestfulContainer.ServeMux)
436+
437+
// Test 1: extensions/v1beta1/replicasets and apps/v1/replicasets have
438+
// the same storage version hash.
439+
resp, err := http.Get(server.URL + "/apis/extensions/v1beta1")
440+
assert.Empty(err)
441+
extList := metav1.APIResourceList{}
442+
assert.NoError(decodeResponse(resp, &extList))
443+
var extReplicasetHash, appsReplicasetHash string
444+
for _, r := range extList.APIResources {
445+
if r.Name == "replicasets" {
446+
extReplicasetHash = r.StorageVersionHash
447+
}
448+
}
449+
assert.NotEmpty(extReplicasetHash)
450+
451+
resp, err = http.Get(server.URL + "/apis/apps/v1")
452+
assert.Empty(err)
453+
appsList := metav1.APIResourceList{}
454+
assert.NoError(decodeResponse(resp, &appsList))
455+
for _, r := range appsList.APIResources {
456+
if r.Name == "replicasets" {
457+
appsReplicasetHash = r.StorageVersionHash
458+
}
459+
}
460+
assert.Equal(extReplicasetHash, appsReplicasetHash)
461+
462+
// Test 2: batch/v1/jobs and batch/v1beta1/cronjobs have different
463+
// storage version hashes.
464+
resp, err = http.Get(server.URL + "/apis/batch/v1")
465+
assert.Empty(err)
466+
batchv1 := metav1.APIResourceList{}
467+
assert.NoError(decodeResponse(resp, &batchv1))
468+
var jobsHash string
469+
for _, r := range batchv1.APIResources {
470+
if r.Name == "jobs" {
471+
jobsHash = r.StorageVersionHash
472+
}
473+
}
474+
assert.NotEmpty(jobsHash)
475+
476+
resp, err = http.Get(server.URL + "/apis/batch/v1beta1")
477+
assert.Empty(err)
478+
batchv1beta1 := metav1.APIResourceList{}
479+
assert.NoError(decodeResponse(resp, &batchv1beta1))
480+
var cronjobsHash string
481+
for _, r := range batchv1beta1.APIResources {
482+
if r.Name == "cronjobs" {
483+
cronjobsHash = r.StorageVersionHash
484+
}
485+
}
486+
assert.NotEmpty(cronjobsHash)
487+
assert.NotEqual(jobsHash, cronjobsHash)
488+
}
489+
366490
func TestNoAlphaVersionsEnabledByDefault(t *testing.T) {
367491
config := DefaultAPIResourceConfigSource()
368492
for gv, enable := range config.GroupVersionConfigs {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "go_default_library",
5+
srcs = ["data.go"],
6+
importpath = "k8s.io/kubernetes/pkg/master/storageversionhashdata",
7+
visibility = ["//visibility:public"],
8+
deps = ["//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library"],
9+
)
10+
11+
filegroup(
12+
name = "package-srcs",
13+
srcs = glob(["**"]),
14+
tags = ["automanaged"],
15+
visibility = ["//visibility:private"],
16+
)
17+
18+
filegroup(
19+
name = "all-srcs",
20+
srcs = [":package-srcs"],
21+
tags = ["automanaged"],
22+
visibility = ["//visibility:public"],
23+
)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
approvers:
2+
- api-approvers
3+
reviewers:
4+
- api-reviewers

0 commit comments

Comments
 (0)