diff --git a/lib/resourceapply/apiext.go b/lib/resourceapply/apiext.go index 5ef3a7872..9cde74c86 100644 --- a/lib/resourceapply/apiext.go +++ b/lib/resourceapply/apiext.go @@ -2,15 +2,16 @@ package resourceapply import ( "github.com/openshift/cluster-version-operator/lib/resourcemerge" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextclientv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" apiextclientv1beta1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" - apiextlistersv1beta1 "k8s.io/apiextensions-apiserver/pkg/client/listers/apiextensions/v1beta1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/utils/pointer" ) -func ApplyCustomResourceDefinition(client apiextclientv1beta1.CustomResourceDefinitionsGetter, required *apiextv1beta1.CustomResourceDefinition) (*apiextv1beta1.CustomResourceDefinition, bool, error) { +func ApplyCustomResourceDefinitionV1beta1(client apiextclientv1beta1.CustomResourceDefinitionsGetter, required *apiextv1beta1.CustomResourceDefinition) (*apiextv1beta1.CustomResourceDefinition, bool, error) { existing, err := client.CustomResourceDefinitions().Get(required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { actual, err := client.CustomResourceDefinitions().Create(required) @@ -25,7 +26,7 @@ func ApplyCustomResourceDefinition(client apiextclientv1beta1.CustomResourceDefi } modified := pointer.BoolPtr(false) - resourcemerge.EnsureCustomResourceDefinition(modified, existing, *required) + resourcemerge.EnsureCustomResourceDefinitionV1beta1(modified, existing, *required) if !*modified { return existing, false, nil } @@ -34,8 +35,8 @@ func ApplyCustomResourceDefinition(client apiextclientv1beta1.CustomResourceDefi return actual, true, err } -func ApplyCustomResourceDefinitionFromCache(lister apiextlistersv1beta1.CustomResourceDefinitionLister, client apiextclientv1beta1.CustomResourceDefinitionsGetter, required *apiextv1beta1.CustomResourceDefinition) (*apiextv1beta1.CustomResourceDefinition, bool, error) { - existing, err := lister.Get(required.Name) +func ApplyCustomResourceDefinitionV1(client apiextclientv1.CustomResourceDefinitionsGetter, required *apiextv1.CustomResourceDefinition) (*apiextv1.CustomResourceDefinition, bool, error) { + existing, err := client.CustomResourceDefinitions().Get(required.Name, metav1.GetOptions{}) if apierrors.IsNotFound(err) { actual, err := client.CustomResourceDefinitions().Create(required) return actual, true, err @@ -48,9 +49,8 @@ func ApplyCustomResourceDefinitionFromCache(lister apiextlistersv1beta1.CustomRe return nil, false, nil } - existing = existing.DeepCopy() modified := pointer.BoolPtr(false) - resourcemerge.EnsureCustomResourceDefinition(modified, existing, *required) + resourcemerge.EnsureCustomResourceDefinitionV1(modified, existing, *required) if !*modified { return existing, false, nil } diff --git a/lib/resourcebuilder/apiext.go b/lib/resourcebuilder/apiext.go index 8d6193a78..b8f46f82c 100644 --- a/lib/resourcebuilder/apiext.go +++ b/lib/resourcebuilder/apiext.go @@ -8,7 +8,9 @@ import ( "github.com/openshift/cluster-version-operator/lib" "github.com/openshift/cluster-version-operator/lib/resourceapply" "github.com/openshift/cluster-version-operator/lib/resourceread" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + apiextclientv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" apiextclientv1beta1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -17,15 +19,17 @@ import ( ) type crdBuilder struct { - client *apiextclientv1beta1.ApiextensionsV1beta1Client - raw []byte - modifier MetaV1ObjectModifierFunc + raw []byte + modifier MetaV1ObjectModifierFunc + clientV1beta1 *apiextclientv1beta1.ApiextensionsV1beta1Client + clientV1 *apiextclientv1.ApiextensionsV1Client } func newCRDBuilder(config *rest.Config, m lib.Manifest) Interface { return &crdBuilder{ - client: apiextclientv1beta1.NewForConfigOrDie(withProtobuf(config)), - raw: m.Raw, + raw: m.Raw, + clientV1beta1: apiextclientv1beta1.NewForConfigOrDie(withProtobuf(config)), + clientV1: apiextclientv1.NewForConfigOrDie(withProtobuf(config)), } } @@ -39,34 +43,53 @@ func (b *crdBuilder) WithModifier(f MetaV1ObjectModifierFunc) Interface { } func (b *crdBuilder) Do(ctx context.Context) error { - crd := resourceread.ReadCustomResourceDefinitionV1Beta1OrDie(b.raw) - if b.modifier != nil { - b.modifier(crd) - } - _, updated, err := resourceapply.ApplyCustomResourceDefinition(b.client, crd) - if err != nil { - return err + crd := resourceread.ReadCustomResourceDefinitionOrDie(b.raw) + + var updated bool + var err error + var name string + + switch crd := crd.(type) { + case *apiextv1beta1.CustomResourceDefinition: + if b.modifier != nil { + b.modifier(crd) + } + _, updated, err = resourceapply.ApplyCustomResourceDefinitionV1beta1(b.clientV1beta1, crd) + if err != nil { + return err + } + name = crd.Name + case *apiextv1.CustomResourceDefinition: + if b.modifier != nil { + b.modifier(crd) + } + _, updated, err = resourceapply.ApplyCustomResourceDefinitionV1(b.clientV1, crd) + if err != nil { + return err + } + name = crd.Name } + if updated { - return waitForCustomResourceDefinitionCompletion(ctx, b.client, crd) + return waitForCustomResourceDefinitionCompletion(ctx, b.clientV1, name) } return nil } -func waitForCustomResourceDefinitionCompletion(ctx context.Context, client apiextclientv1beta1.CustomResourceDefinitionsGetter, crd *apiextv1beta1.CustomResourceDefinition) error { +func waitForCustomResourceDefinitionCompletion(ctx context.Context, client apiextclientv1.CustomResourceDefinitionsGetter, crd string) error { return wait.PollImmediateUntil(defaultObjectPollInterval, func() (bool, error) { - c, err := client.CustomResourceDefinitions().Get(crd.Name, metav1.GetOptions{}) + c, err := client.CustomResourceDefinitions().Get(crd, metav1.GetOptions{}) if errors.IsNotFound(err) { // exit early to recreate the crd. return false, err } if err != nil { - klog.Errorf("error getting CustomResourceDefinition %s: %v", crd.Name, err) + klog.Errorf("error getting CustomResourceDefinition %s: %v", crd, err) return false, nil } for _, condition := range c.Status.Conditions { - if condition.Type == apiextv1beta1.Established && condition.Status == apiextv1beta1.ConditionTrue { + if condition.Type == apiextv1.Established && condition.Status == apiextv1.ConditionTrue { return true, nil } } diff --git a/lib/resourcebuilder/register.go b/lib/resourcebuilder/register.go index 5806e540c..5de99be76 100644 --- a/lib/resourcebuilder/register.go +++ b/lib/resourcebuilder/register.go @@ -7,6 +7,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" rbacv1beta1 "k8s.io/api/rbac/v1beta1" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiregv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" apiregv1beta1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1beta1" @@ -15,6 +16,7 @@ import ( func init() { rm := NewResourceMapper() rm.RegisterGVK(apiextv1beta1.SchemeGroupVersion.WithKind("CustomResourceDefinition"), newCRDBuilder) + rm.RegisterGVK(apiextv1.SchemeGroupVersion.WithKind("CustomResourceDefinition"), newCRDBuilder) rm.RegisterGVK(apiregv1.SchemeGroupVersion.WithKind("APIService"), newAPIServiceBuilder) rm.RegisterGVK(apiregv1beta1.SchemeGroupVersion.WithKind("APIService"), newAPIServiceBuilder) rm.RegisterGVK(appsv1.SchemeGroupVersion.WithKind("Deployment"), newDeploymentBuilder) diff --git a/lib/resourcemerge/apiext.go b/lib/resourcemerge/apiext.go index 32e4043f6..2fbac35c6 100644 --- a/lib/resourcemerge/apiext.go +++ b/lib/resourcemerge/apiext.go @@ -1,15 +1,63 @@ package resourcemerge import ( + "strings" + + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" + "k8s.io/utils/pointer" + "k8s.io/apimachinery/pkg/api/equality" ) -// EnsureCustomResourceDefinition ensures that the existing matches the required. +// EnsureCustomResourceDefinitionV1beta1 ensures that the existing matches the required. // modified is set to true when existing had to be updated with required. -func EnsureCustomResourceDefinition(modified *bool, existing *apiextv1beta1.CustomResourceDefinition, required apiextv1beta1.CustomResourceDefinition) { +func EnsureCustomResourceDefinitionV1beta1(modified *bool, existing *apiextv1beta1.CustomResourceDefinition, required apiextv1beta1.CustomResourceDefinition) { EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta) + // apply defaults to blue print + if len(required.Spec.Versions) > 0 && len(required.Spec.Version) == 0 { + required.Spec.Version = required.Spec.Versions[0].Name + } + if len(required.Spec.Versions) == 0 && len(required.Spec.Version) > 0 { + required.Spec.Versions = []apiextv1beta1.CustomResourceDefinitionVersion{ + { + Name: required.Spec.Version, + Served: true, + Storage: true, + }, + } + } + if required.Spec.PreserveUnknownFields == nil { + required.Spec.PreserveUnknownFields = pointer.BoolPtr(true) + } + if len(required.Spec.Names.Singular) == 0 { + required.Spec.Names.Singular = strings.ToLower(required.Spec.Names.Kind) + } + if len(required.Spec.Names.ListKind) == 0 { + required.Spec.Names.ListKind = required.Spec.Names.Kind + "List" + } + + // we stomp everything + if !equality.Semantic.DeepEqual(existing.Spec, required.Spec) { + *modified = true + existing.Spec = required.Spec + } +} + +// EnsureCustomResourceDefinitionV1 ensures that the existing matches the required. +// modified is set to true when existing had to be updated with required. +func EnsureCustomResourceDefinitionV1(modified *bool, existing *apiextv1.CustomResourceDefinition, required apiextv1.CustomResourceDefinition) { + EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta) + + // apply defaults to blue print + if len(required.Spec.Names.Singular) == 0 { + required.Spec.Names.Singular = strings.ToLower(required.Spec.Names.Kind) + } + if len(required.Spec.Names.ListKind) == 0 { + required.Spec.Names.ListKind = required.Spec.Names.Kind + "List" + } + // we stomp everything if !equality.Semantic.DeepEqual(existing.Spec, required.Spec) { *modified = true diff --git a/lib/resourceread/apiext.go b/lib/resourceread/apiext.go index ed6fbeb16..0f6010eb9 100644 --- a/lib/resourceread/apiext.go +++ b/lib/resourceread/apiext.go @@ -1,6 +1,7 @@ package resourceread import ( + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer" @@ -15,13 +16,16 @@ func init() { if err := apiextv1beta1.AddToScheme(apiExtensionsScheme); err != nil { panic(err) } + if err := apiextv1.AddToScheme(apiExtensionsScheme); err != nil { + panic(err) + } } -// ReadCustomResourceDefinitionV1Beta1OrDie reads crd object from bytes. Panics on error. -func ReadCustomResourceDefinitionV1Beta1OrDie(objBytes []byte) *apiextv1beta1.CustomResourceDefinition { +// ReadCustomResourceDefinitionOrDie reads crd object from bytes as v1 or v1beta1. Panics on error. +func ReadCustomResourceDefinitionOrDie(objBytes []byte) runtime.Object { requiredObj, err := runtime.Decode(apiExtensionsCodecs.UniversalDecoder(apiextv1beta1.SchemeGroupVersion), objBytes) if err != nil { panic(err) } - return requiredObj.(*apiextv1beta1.CustomResourceDefinition) + return requiredObj }