Skip to content

Commit

Permalink
Merge pull request #607 from joelanford/k8s-1.22
Browse files Browse the repository at this point in the history
⚠ bump to kubernetes 1.22.1, remove support for legacy v1beta1 CRDs and webhooks
  • Loading branch information
k8s-ci-robot authored Sep 19, 2021
2 parents 14c7780 + 09f1952 commit 9724ec3
Show file tree
Hide file tree
Showing 41 changed files with 1,122 additions and 1,111 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ require (
github.com/spf13/pflag v1.0.5
golang.org/x/tools v0.1.5
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.21.3
k8s.io/apiextensions-apiserver v0.21.3
k8s.io/apimachinery v0.21.3
k8s.io/api v0.22.2
k8s.io/apiextensions-apiserver v0.22.2
k8s.io/apimachinery v0.22.2
sigs.k8s.io/yaml v1.2.0
)
170 changes: 98 additions & 72 deletions go.sum

Large diffs are not rendered by default.

89 changes: 5 additions & 84 deletions pkg/crd/conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
apiextinternal "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
Expand All @@ -22,13 +21,15 @@ func init() {
if err := apiext.AddToScheme(conversionScheme); err != nil {
panic("must be able to add apiextensions/v1 to the CRD conversion Scheme")
}
if err := apiextv1beta1.AddToScheme(conversionScheme); err != nil {
panic("must be able to add apiextensions/v1beta1 to the CRD conversion Scheme")
}
}

// AsVersion converts a CRD from the canonical internal form (currently v1) to some external form.
func AsVersion(original apiext.CustomResourceDefinition, gv schema.GroupVersion) (runtime.Object, error) {
// TODO: Do we need to keep maintaining this conversion function
// post 1.22 when only CRDv1 is served by the apiserver?
if gv == apiextv1beta1.SchemeGroupVersion {
return nil, fmt.Errorf("apiVersion %q is not supported", gv.String())
}
// We can use the internal versions an existing conversions from kubernetes, since they're not in k/k itself.
// This punts the problem of conversion down the road for a future maintainer (or future instance of @directxman12)
// when we have to support older versions that get removed, or when API machinery decides to yell at us for this
Expand All @@ -40,83 +41,3 @@ func AsVersion(original apiext.CustomResourceDefinition, gv schema.GroupVersion)

return conversionScheme.ConvertToVersion(intVer, gv)
}

// mergeIdenticalSubresources checks to see if subresources are identical across
// all versions, and if so, merges them into a top-level version.
//
// This assumes you're not using trivial versions.
func mergeIdenticalSubresources(crd *apiextv1beta1.CustomResourceDefinition) {
subres := crd.Spec.Versions[0].Subresources
for _, ver := range crd.Spec.Versions {
if ver.Subresources == nil || !equality.Semantic.DeepEqual(subres, ver.Subresources) {
// either all nil, or not identical
return
}
}

// things are identical if we've gotten this far, so move the subresources up
// and discard the identical per-version ones
crd.Spec.Subresources = subres
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Subresources = nil
}
}

// mergeIdenticalSchemata checks to see if schemata are identical across
// all versions, and if so, merges them into a top-level version.
//
// This assumes you're not using trivial versions.
func mergeIdenticalSchemata(crd *apiextv1beta1.CustomResourceDefinition) {
schema := crd.Spec.Versions[0].Schema
for _, ver := range crd.Spec.Versions {
if ver.Schema == nil || !equality.Semantic.DeepEqual(schema, ver.Schema) {
// either all nil, or not identical
return
}
}

// things are identical if we've gotten this far, so move the schemata up
// to a single schema and discard the identical per-version ones
crd.Spec.Validation = schema
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Schema = nil
}
}

// mergeIdenticalPrinterColumns checks to see if schemata are identical across
// all versions, and if so, merges them into a top-level version.
//
// This assumes you're not using trivial versions.
func mergeIdenticalPrinterColumns(crd *apiextv1beta1.CustomResourceDefinition) {
cols := crd.Spec.Versions[0].AdditionalPrinterColumns
for _, ver := range crd.Spec.Versions {
if len(ver.AdditionalPrinterColumns) == 0 || !equality.Semantic.DeepEqual(cols, ver.AdditionalPrinterColumns) {
// either all nil, or not identical
return
}
}

// things are identical if we've gotten this far, so move the printer columns up
// and discard the identical per-version ones
crd.Spec.AdditionalPrinterColumns = cols
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].AdditionalPrinterColumns = nil
}
}

// MergeIdenticalVersionInfo makes sure that components of the Versions field that are identical
// across all versions get merged into the top-level fields in v1beta1.
//
// This is required by the Kubernetes API server validation.
//
// The reason is that a v1beta1 -> v1 -> v1beta1 conversion cycle would need to
// round-trip identically, v1 doesn't have top-level subresources, and without
// this restriction it would be ambiguous how a v1-with-identical-subresources
// converts into a v1beta1).
func MergeIdenticalVersionInfo(crd *apiextv1beta1.CustomResourceDefinition) {
if len(crd.Spec.Versions) > 0 {
mergeIdenticalSubresources(crd)
mergeIdenticalSchemata(crd)
mergeIdenticalPrinterColumns(crd)
}
}
267 changes: 0 additions & 267 deletions pkg/crd/crd_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,275 +18,8 @@ package crd_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
apiextlegacy "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"

"sigs.k8s.io/controller-tools/pkg/crd"
)

var _ = Describe("CRD Generation", func() {
Describe("Utilities", func() {
Describe("MergeIdenticalVersionInfo", func() {
It("should replace per-version schemata with a top-level schema if only one version", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Storage: true,
Schema: &apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
},
},
},
},
}
crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.Validation).To(Equal(&apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1", Storage: true},
}))
})
It("should replace per-version schemata with a top-level schema if all are identical", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Schema: &apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
},
},
{
Name: "v2",
Storage: true,
Schema: &apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
},
},
},
},
}
crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.Validation).To(Equal(&apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1"}, {Name: "v2", Storage: true},
}))
})

It("shouldn't merge different schemata", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Schema: &apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
},
},
{
Name: "v2",
Storage: true,
Schema: &apiextlegacy.CustomResourceValidation{
OpenAPIV3Schema: &apiextlegacy.JSONSchemaProps{
Required: []string{"foo"},
Type: "object",
Properties: map[string]apiextlegacy.JSONSchemaProps{"foo": {Type: "string"}},
},
},
},
},
},
}
orig := spec.DeepCopy()
crd.MergeIdenticalVersionInfo(spec)
Expect(spec).To(Equal(orig))
})

It("should replace per-version subresources with top-level subresources if only one version", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Storage: true,
Subresources: &apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
},
},
},
},
}

crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.Subresources).To(Equal(&apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1", Storage: true},
}))
})

It("should replace per-version subresources with top-level subresources if all are identical", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Subresources: &apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
},
},
{
Name: "v2",
Storage: true,
Subresources: &apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
},
},
},
},
}

crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.Subresources).To(Equal(&apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1"}, {Name: "v2", Storage: true},
}))
})

It("shouldn't merge different subresources", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Subresources: &apiextlegacy.CustomResourceSubresources{
Status: &apiextlegacy.CustomResourceSubresourceStatus{},
},
},
{
Name: "v2",
Storage: true,
},
},
},
}
orig := spec.DeepCopy()
crd.MergeIdenticalVersionInfo(spec)
Expect(spec).To(Equal(orig))
})

It("should replace per-version printer columns with top-level printer columns if only one version", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
Storage: true,
AdditionalPrinterColumns: []apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
},
},
},
},
}

crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.AdditionalPrinterColumns).To(Equal([]apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1", Storage: true},
}))
})

It("should replace per-version printer columns with top-level printer columns if all are identical", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
AdditionalPrinterColumns: []apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
},
},
{
Name: "v2",
Storage: true,
AdditionalPrinterColumns: []apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
},
},
},
},
}

crd.MergeIdenticalVersionInfo(spec)
Expect(spec.Spec.AdditionalPrinterColumns).To(Equal([]apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
}))
Expect(spec.Spec.Versions).To(Equal([]apiextlegacy.CustomResourceDefinitionVersion{
{Name: "v1"}, {Name: "v2", Storage: true},
}))
})

It("shouldn't merge different printer columns", func() {
spec := &apiextlegacy.CustomResourceDefinition{
Spec: apiextlegacy.CustomResourceDefinitionSpec{
Versions: []apiextlegacy.CustomResourceDefinitionVersion{
{
Name: "v1",
AdditionalPrinterColumns: []apiextlegacy.CustomResourceColumnDefinition{
{Name: "Cheddar", JSONPath: ".spec.cheddar"},
{Name: "Parmesan", JSONPath: ".status.parmesan"},
},
},
{
Name: "v2",
Storage: true,
},
},
},
}
orig := spec.DeepCopy()
crd.MergeIdenticalVersionInfo(spec)
Expect(spec).To(Equal(orig))
})
})
})
})
Loading

0 comments on commit 9724ec3

Please sign in to comment.