Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 198 additions & 0 deletions test/extended/operators/check_crd_status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
package operators

import (
"context"
"fmt"
"strings"

g "github.com/onsi/ginkgo"
o "github.com/onsi/gomega"
"k8s.io/kube-openapi/pkg/util/sets"
e2e "k8s.io/kubernetes/test/e2e/framework"

exutil "github.com/openshift/origin/test/extended/util"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// checkSubresourceStatus returns a list of names of CRDs that have a "status" in the CRD schema
// but no subresource.status defined.
// For now, it ignores the ones that are currently failing.
func checkSubresourceStatus(crdItemList []apiextensionsv1.CustomResourceDefinition) []string {

// These CRDs, at the time this test was written, do not have a "status" in the CRD schema
// and subresource.status.
// These can be skipped for now but we don't want the number to increase.
// These CRDs should be tidied up over time.
//
exceptionsList := sets.NewString(
"networks.config.openshift.io",
"networks.operator.openshift.io",
"operatorpkis.network.operator.openshift.io",
"profiles.tuned.openshift.io",
"tuneds.tuned.openshift.io",
)

failures := []string{}
for _, crdItem := range crdItemList {

// This test is interested only in CRDs that end with "openshift.io".
if !strings.HasSuffix(crdItem.ObjectMeta.Name, "openshift.io") {
continue
}

crdName := crdItem.ObjectMeta.Name

// Skip CRDs in the exceptions list for now.
if exceptionsList.Has(crdName) {
continue
}

// Iterate through all versions of the CustomResourceDefinition Spec looking for one with
// a schema status element,
foundStatusInSchema := false
var i int
for i = 0; i < len(crdItem.Spec.Versions); i++ {
if _, ok := crdItem.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"]; ok {
foundStatusInSchema = true
break
}
}

if foundStatusInSchema {
if !(crdItem.Spec.Versions[i].Subresources != nil && crdItem.Spec.Versions[i].Subresources.Status != nil) {
failures = append(failures, fmt.Sprintf("CRD %s has a status in the schema but no subresource.status", crdName))
}
}
}

return failures
}

// checkStatusInSchema returns a list of names of CRDs that don't have a "status" in the CRD schema.
// For now, it ignores the ones that are currently failing.
func checkStatusInSchema(crdItemList []apiextensionsv1.CustomResourceDefinition) []string {

// These CRDs, at the time this test was written, do not have a "status" in the CRD schema
// and subresource.status.
// These can be skipped for now but we don't want the number to increase.
// These CRDs should be tidied up over time.
//
Comment thread
deads2k marked this conversation as resolved.
exceptionsList := sets.NewString(
"builds.config.openshift.io",
"clusternetworks.network.openshift.io",
"consoleclidownloads.console.openshift.io",
"consoleexternalloglinks.console.openshift.io",
"consolelinks.console.openshift.io",
"consolenotifications.console.openshift.io",
"consoleplugins.console.openshift.io",
"consolequickstarts.console.openshift.io",
"consoleyamlsamples.console.openshift.io",
"egressnetworkpolicies.network.openshift.io",
"hostsubnets.network.openshift.io",
"imagecontentpolicies.config.openshift.io",
"imagecontentsourcepolicies.operator.openshift.io",
"machineconfigs.machineconfiguration.openshift.io",
"netnamespaces.network.openshift.io",
"rangeallocations.security.internal.openshift.io",
Comment thread
deads2k marked this conversation as resolved.
"rolebindingrestrictions.authorization.openshift.io",
Comment thread
deads2k marked this conversation as resolved.
"securitycontextconstraints.security.openshift.io",
)

failures := []string{}
for _, crdItem := range crdItemList {

// This test is interested only in CRDs that end with "openshift.io".
if !strings.HasSuffix(crdItem.ObjectMeta.Name, "openshift.io") {
continue
}

crdName := crdItem.ObjectMeta.Name

// Skip CRDs in the exceptions list for now.
if exceptionsList.Has(crdName) {
continue
}

// Iterate through all versions of the CustomResourceDefinition Spec looking for one with
// a schema status element,
foundStatusInSchema := false
var i int
for i = 0; i < len(crdItem.Spec.Versions); i++ {
if _, ok := crdItem.Spec.Versions[i].Schema.OpenAPIV3Schema.Properties["status"]; ok {
foundStatusInSchema = true
break
}
}

if !foundStatusInSchema {
Comment thread
deads2k marked this conversation as resolved.
failures = append(failures, fmt.Sprintf("CRD %s has no 'status' element in its schema", crdName))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, this isn't necessarily a bug.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. But I thought the purpose of this Jira/PR was to check for the presence of the status element in the schema.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. But I thought the purpose of this Jira/PR was to check for the presence of the status element in the schema.

We have two problems

  1. types with status must have a subresource. We've missed some in the past
  2. most types should have status.

The second is a lot less severe than the first. I suggest enforcement by separate tests and this PR just about perfect for 1 which is a lot more important.

}
Comment thread
deads2k marked this conversation as resolved.
}

return failures
}

var _ = g.Describe("[sig-arch][Early]", func() {

defer g.GinkgoRecover()

var (
crdItemList []apiextensionsv1.CustomResourceDefinition
)

oc := exutil.NewCLI("subresource-status-check")

g.BeforeEach(func() {
var err error
crdClient := apiextensionsclientset.NewForConfigOrDie(oc.AdminConfig())
crdItemList, err = getCRDItemList(*crdClient)
o.Expect(err).NotTo(o.HaveOccurred())
})

g.Describe("CRDs for openshift.io", func() {
g.It("should have subresource.status", func() {
failures := checkSubresourceStatus(crdItemList)
if len(failures) > 0 {
e2e.Fail(strings.Join(failures, "\n"))
}
})
})
})

var _ = g.Describe("[sig-arch][Early]", func() {

defer g.GinkgoRecover()

var (
crdItemList []apiextensionsv1.CustomResourceDefinition
)

oc := exutil.NewCLI("schema-status-check")

g.BeforeEach(func() {
var err error
crdClient := apiextensionsclientset.NewForConfigOrDie(oc.AdminConfig())
crdItemList, err = getCRDItemList(*crdClient)
o.Expect(err).NotTo(o.HaveOccurred())
})

g.Describe("CRDs for openshift.io", func() {
g.It("should have a status in the CRD schema", func() {
failures := checkStatusInSchema(crdItemList)
if len(failures) > 0 {
e2e.Fail(strings.Join(failures, "\n"))
}
})
})
})

func getCRDItemList(crdClient apiextensionsclientset.Clientset) ([]apiextensionsv1.CustomResourceDefinition, error) {

crdList, err := crdClient.ApiextensionsV1().CustomResourceDefinitions().List(context.Background(), metav1.ListOptions{})
if err != nil {
return nil, err
}
return crdList.Items, err
}
60 changes: 60 additions & 0 deletions test/extended/operators/check_crd_status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package operators

import (
"fmt"
"os"
"testing"

exutil "github.com/openshift/origin/test/extended/util"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
)

func Test_checkSubresourceStatus(t *testing.T) {

crdClient := setupLocalAPIClientset()
t.Run("Test_checkSubresourceStatus test", func(t *testing.T) {
crdList, err := getCRDItemList(*crdClient)
if err != nil {
t.Errorf("Fail: %s", err)
}
failures := checkSubresourceStatus(crdList)
if len(failures) > 0 {
t.Error("There should be no failures")
for _, i := range failures {
fmt.Println(i)
}
}
})
}

func Test_checkStatusInSchema(t *testing.T) {

crdClient := setupLocalAPIClientset()
t.Run("Test_checkStatusInSchema test", func(t *testing.T) {
crdList, err := getCRDItemList(*crdClient)
if err != nil {
t.Errorf("Fail: %s", err)
}
failures := checkStatusInSchema(crdList)
if len(failures) > 0 {
t.Error("There should be no failures")
for _, i := range failures {
fmt.Println(i)
}
}
})
}
func setupLocalAPIClientset() *apiextensionsclientset.Clientset {
// Get the kubeconfig by creating an Openshift cluster with cluster-bot, downloading it,
// and using the filename for KUBECONFIG.
home_dir := os.Getenv("HOME")
err := os.Setenv("KUBECONFIG", fmt.Sprintf("%s/Downloads/cluster-bot-2022-05-10-100029.kubeconfig.txt", home_dir))
kube_dir := os.Getenv("KUBECONFIG")
fmt.Println(kube_dir)
if err != nil {
fmt.Printf("Error setting KUBECONFIG: %s", err)
}
oc := exutil.NewCLI("default")
local_client := apiextensionsclientset.NewForConfigOrDie(oc.AdminConfig())
return local_client
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.