mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00
Make sure all CDI crds have structural schemas (#1171)
* Make sure all CDI crds have structural schemas Signed-off-by: Alexander Wels <awels@redhat.com> * Removed unneeded apiVersion, Kind, Metadata from validation Signed-off-by: Alexander Wels <awels@redhat.com>
This commit is contained in:
parent
fba04c868b
commit
bdb079f7bf
@ -50,6 +50,18 @@ function kill_running_operator {
|
||||
done
|
||||
}
|
||||
|
||||
function check_structural_schema {
|
||||
for crd in "$@"; do
|
||||
status=$(_kubectl get crd $crd -o jsonpath={.status.conditions[?\(@.type==\"NonStructuralSchema\"\)].status})
|
||||
if [ "$status" == "True" ]; then
|
||||
echo "ERROR CRD $crd is not a structural schema!, please fix"
|
||||
_kubectl get crd $crd -o yaml
|
||||
exit 1
|
||||
fi
|
||||
echo "CRD $crd is a StructuralSchema"
|
||||
done
|
||||
}
|
||||
|
||||
seed_images
|
||||
|
||||
# Install CDI
|
||||
@ -134,6 +146,13 @@ if [[ ! -z "$UPGRADE_FROM" ]]; then
|
||||
_kubectl wait cdis.cdi.kubevirt.io/cdi --for=condition=Available --timeout=${CDI_AVAILABLE_TIMEOUT}s
|
||||
fi
|
||||
|
||||
# Grab all the CDI crds so we can check if they are structural schemas
|
||||
cdi_crds=$(_kubectl get crd -l cdi.kubevirt.io -o jsonpath={.items[*].metadata.name})
|
||||
crds=($cdi_crds)
|
||||
operator_crds=$(_kubectl get crd -l operator.cdi.kubevirt.io -o jsonpath={.items[*].metadata.name})
|
||||
crds+=($operator_crds)
|
||||
check_structural_schema "${crds[@]}"
|
||||
|
||||
configure_storage
|
||||
|
||||
# Start functional test HTTP server.
|
||||
|
@ -28,6 +28,70 @@ func createCDIConfigCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
Version: "v1alpha1",
|
||||
Scope: "Cluster",
|
||||
Validation: &extv1beta1.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &extv1beta1.JSONSchemaProps{
|
||||
Description: "CDIConfig is the configuration object for Containerized Data Importer",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"spec": {
|
||||
Description: "Specification of CDIConfig",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"uploadProxyURLOverride": {
|
||||
Description: "Override the URL used when uploading to a DataVolume",
|
||||
Type: "string",
|
||||
},
|
||||
"scratchSpaceStorageClass": {
|
||||
Description: "Override the storage class to used for scratch space during transfer operations. The scratch space storage class is determined in the following order: 1. value of scratchSpaceStorageClass, if that doesn't exist, use the default storage class, if there is no default storage class, use the storage class of the DataVolume, if no storage class specified, use no storage class for scratch space",
|
||||
Type: "string",
|
||||
},
|
||||
"podResourceRequirements": {
|
||||
Description: "The default resource requirements put on all CDI pods",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"limits": {
|
||||
Description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
Type: "object",
|
||||
},
|
||||
"requests": {
|
||||
Description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
Type: "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
Type: "object",
|
||||
Description: "The most recently observed status of the CDI Config resource",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"uploadProxyURL": {
|
||||
Description: "The calculated upload proxy URL",
|
||||
Type: "string",
|
||||
},
|
||||
"scratchSpaceStorageClass": {
|
||||
Description: "The calculated storage class to be used for scratch space",
|
||||
Type: "string",
|
||||
},
|
||||
"defaultPodResourceRequirements": {
|
||||
Description: "The default resource requirements put on all CDI pods",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"limits": {
|
||||
Description: "Limits describes the maximum amount of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
Type: "object",
|
||||
},
|
||||
"requests": {
|
||||
Description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
Type: "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -50,25 +50,32 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
Scope: "Namespaced",
|
||||
Validation: &extv1beta1.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &extv1beta1.JSONSchemaProps{
|
||||
Description: "DataVolumes are an abstraction on top of PersistentVolumeClaims to allow easy population of those PersistentVolumeClaims with relation to VirtualMachines",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"apiVersion": {
|
||||
Type: "string",
|
||||
},
|
||||
"kind": {
|
||||
Type: "string",
|
||||
},
|
||||
"metadata": {},
|
||||
"spec": {
|
||||
Description: "Specification of DataVolumes",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"source": {
|
||||
Description: "The source type used to populate the DataVolume",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"http": {
|
||||
Description: "Source type of http, can be either an http or https endpoint, with an optional basic auth user name and password, and an optional configmap containing additional CAs",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"url": {
|
||||
Type: "string",
|
||||
Description: "The URL of the http(s) endpoint",
|
||||
Type: "string",
|
||||
},
|
||||
"secretRef": {
|
||||
Type: "string",
|
||||
Description: "A configmap reference, the configmap should contain accessKeyId (user name) base64 encoded, and secretKey (password) also base64 encoded",
|
||||
Type: "string",
|
||||
},
|
||||
"certConfigMap": {
|
||||
Description: "A configmap reference, containing a ca.pem key, and a base64 encoded pem certificate",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Required: []string{
|
||||
@ -76,12 +83,20 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
},
|
||||
"s3": {
|
||||
Description: "Source type of S3 bucket, with an optional basic auth user name and password, and an optional configmap containing additional CAs",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"url": {
|
||||
Type: "string",
|
||||
Description: "The URL of the s3 endpoint",
|
||||
Type: "string",
|
||||
},
|
||||
"secretRef": {
|
||||
Type: "string",
|
||||
Description: "A configmap reference, the configmap should contain accessKeyId (user name) base64 encoded, and secretKey (password) also base64 encoded",
|
||||
Type: "string",
|
||||
},
|
||||
"certConfigMap": {
|
||||
Description: "A configmap reference, containing a ca.pem key, and a base64 encoded pem certificate",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Required: []string{
|
||||
@ -89,12 +104,20 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
},
|
||||
"registry": {
|
||||
Description: "Source type of registry, with an optional basic auth user name and password, and an optional configmap containing additional CAs",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"url": {
|
||||
Type: "string",
|
||||
Description: "The URL of the registry endpoint",
|
||||
Type: "string",
|
||||
},
|
||||
"secretRef": {
|
||||
Type: "string",
|
||||
Description: "A configmap reference, the configmap should contain accessKeyId (user name) base64 encoded, and secretKey (password) also base64 encoded",
|
||||
Type: "string",
|
||||
},
|
||||
"certConfigMap": {
|
||||
Description: "A configmap reference, containing a ca.pem key, and a base64 encoded pem certificate",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Required: []string{
|
||||
@ -102,12 +125,16 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
},
|
||||
"pvc": {
|
||||
Description: "Source type of PVC, will initiate a clone from the source PVC and source Namespace into this DataVolume",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"namespace": {
|
||||
Type: "string",
|
||||
Description: "The namespace of the source PVC",
|
||||
Type: "string",
|
||||
},
|
||||
"name": {
|
||||
Type: "string",
|
||||
Description: "The name of the source PVC",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
Required: []string{
|
||||
@ -115,18 +142,31 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
"name",
|
||||
},
|
||||
},
|
||||
"upload": {},
|
||||
"blank": {},
|
||||
"upload": {
|
||||
Description: "Source type of upload, starts an upload server pod in the current namespace, that saves the uploaded data in the DataVolume",
|
||||
Type: "object",
|
||||
},
|
||||
"blank": {
|
||||
Description: "Source type of blank, creates a blank raw disk image in the DataVolume",
|
||||
Type: "object",
|
||||
},
|
||||
},
|
||||
},
|
||||
"pvc": {
|
||||
Description: "Spec defines the desired characteristics of a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims\nPersistentVolumeClaimSpec describes the common attributes of storage devices and allows a Source for provider-specific attributes",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"resources": {
|
||||
Description: "Resources represents the minimum resources the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"requests": {
|
||||
Description: "Requests describes the minimum amount of compute resources required. If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, otherwise to an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/",
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"storage": {
|
||||
Type: "string",
|
||||
Description: "Storage Quantity is a fixed-point representation of a number. It provides convenient marshaling/unmarshaling in JSON and YAML, in addition to String() and AsInt64() accessors. The serialization format is: <quantity> ::= <signedNumber><suffix> (Note that <suffix> may be empty, from the \"\" case in <decimalSI>.) <digit> ::= 0 | 1 | ... | 9 <digits> ::= <digit> | <digit><digits> <number> ::= <digits> | <digits>.<digits> | <digits>. | .<digits> <sign> ::= \"+\" | \"-\" <signedNumber> ::= <number> | <sign><number> <suffix> ::= <binarySI> | <decimalExponent> | <decimalSI> <binarySI> ::= Ki | Mi | Gi | Ti | Pi | Ei (International System of units; See: http://physics.nist.gov/cuu/Units/binary.html) <decimalSI> ::= m | \"\" | k | M | G | T | P | E (Note that 1024 = 1Ki but 1000 = 1k; I didn't choose the capitalization.) <decimalExponent> ::= \"e\" <signedNumber> | \"E\" <signedNumber> No matter which of the three exponent forms is used, no quantity may represent a number greater than 2^63-1 in magnitude, nor may it have more than 3 decimal places. Numbers larger or more precise will be capped or rounded up. (E.g.: 0.1m will rounded up to 1m.) This may be extended in the future if we require larger or smaller quantities. When a Quantity is parsed from a string, it will remember the type of suffix it had, and will use the same type again when it is serialized. Before serializing, Quantity will be put in \"canonical form\". This means that Exponent/suffix will be adjusted up or down (with a corresponding increase or decrease in Mantissa) such that: a. No precision is lost b. No fractional digits will be emitted c. The exponent (or suffix) is as large as possible. The sign will be omitted unless the number is negative. Examples: 1.5 will be serialized as \"1500m\" 1.5Gi will be serialized as \"1536Mi\" Note that the quantity will NEVER be internally represented by a floating point number. That is the whole point of this exercise. Non-canonical values will still parse as long as they are well formed, but will be re-emitted in their canonical form. (So always use canonical form, or don't diff.) This format is intended to make it difficult to use these numbers without writing some sort of special handling code in the hopes that that will cause implementors to also use a fixed point implementation",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -136,10 +176,17 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
},
|
||||
"storageClassName": {
|
||||
Type: "string",
|
||||
Description: "Name of the StorageClass required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1",
|
||||
Type: "string",
|
||||
},
|
||||
"accessModes": {
|
||||
Type: "array",
|
||||
Description: "AccessModes contains the desired access modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1",
|
||||
Type: "array",
|
||||
Items: &extv1beta1.JSONSchemaPropsOrArray{
|
||||
Schema: &extv1beta1.JSONSchemaProps{
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{
|
||||
@ -149,6 +196,24 @@ func createDataVolumeCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
},
|
||||
},
|
||||
"status": {
|
||||
Type: "object",
|
||||
Description: "The most recently observed status of the DataVolume",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"phase": {
|
||||
Description: "The current phase of the DataVolume",
|
||||
Type: "string",
|
||||
},
|
||||
"progress": {
|
||||
Description: "The progress of the transfer phase in percentage from 0 to 100, or N/A if unable to determine progress",
|
||||
Type: "string",
|
||||
},
|
||||
"restartCount": {
|
||||
Description: "The number of times the pod populating the DataVolume has restarted",
|
||||
Type: "integer",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -313,17 +313,8 @@ func createCDIListCRD() *extv1beta1.CustomResourceDefinition {
|
||||
|
||||
Validation: &extv1beta1.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &extv1beta1.JSONSchemaProps{
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"apiVersion": {
|
||||
Type: "string",
|
||||
},
|
||||
"kind": {
|
||||
Type: "string",
|
||||
},
|
||||
"metadata": {
|
||||
Type: "object",
|
||||
},
|
||||
|
||||
"spec": {
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"imagePullPolicy": {
|
||||
@ -354,6 +345,61 @@ func createCDIListCRD() *extv1beta1.CustomResourceDefinition {
|
||||
},
|
||||
Type: "object",
|
||||
},
|
||||
"status": {
|
||||
Type: "object",
|
||||
Description: "The most recently observed status of the CDI resource",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"targetVersion": {
|
||||
Description: "The desired version of the CDI resource",
|
||||
Type: "string",
|
||||
},
|
||||
"observedVersion": {
|
||||
Description: "The observed version of the CDI resource",
|
||||
Type: "string",
|
||||
},
|
||||
"operatorVersion": {
|
||||
Description: "The version of the CDI resource as defined by the operator",
|
||||
Type: "string",
|
||||
},
|
||||
"phase": {
|
||||
Description: "The current phase of the CDI resource",
|
||||
Type: "string",
|
||||
},
|
||||
"conditions": {
|
||||
Description: "A list of current conditions of the CDI resource",
|
||||
Type: "array",
|
||||
Items: &extv1beta1.JSONSchemaPropsOrArray{
|
||||
Schema: &extv1beta1.JSONSchemaProps{
|
||||
Type: "object",
|
||||
Properties: map[string]extv1beta1.JSONSchemaProps{
|
||||
"lastHeartbeatTime": {
|
||||
Description: "Last time the state of the condition was checked",
|
||||
Type: "string",
|
||||
Format: "date-time",
|
||||
},
|
||||
"lastTransitionTime": {
|
||||
Description: "Last time the state of the condition changed",
|
||||
Type: "string",
|
||||
Format: "date-time",
|
||||
},
|
||||
"message": {
|
||||
Description: "Message related to the last condition change",
|
||||
Type: "string",
|
||||
},
|
||||
"reason": {
|
||||
Description: "Reason the last condition changed",
|
||||
Type: "string",
|
||||
},
|
||||
"status": {
|
||||
Description: "Current status of the condition, True, False, Unknown",
|
||||
Type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -56,6 +56,7 @@ go_test(
|
||||
"//vendor/k8s.io/api/extensions/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/rbac/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/storage/v1:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
|
@ -223,7 +223,7 @@ var _ = Describe("[rfe_id:1130][crit:medium][posneg:negative][vendor:cnv-qe@redh
|
||||
},
|
||||
table.Entry("[test_id:1760]fail with blank image source and contentType archive", "manifests/dvBlankArchive.yaml", true, "SourceType cannot be blank and the contentType be archive"),
|
||||
table.Entry("[test_id:1761]fail with invalid contentType", "manifests/dvInvalidContentType.yaml", true, "ContentType not one of: kubevirt, archive"),
|
||||
table.Entry("[test_id:1762]fail with missing source", "manifests/dvMissingSource.yaml", true, "Missing Data volume source"),
|
||||
table.Entry("[test_id:1762]fail with missing source", "manifests/dvMissingSource.yaml", true, "Missing Data volume source", "spec.source in body must be of type object"),
|
||||
table.Entry("[test_id:1763]fail with multiple sources", "manifests/dvMultiSource.yaml", true, "Multiple Data volume sources"),
|
||||
table.Entry("[test_id:1764]fail with invalid URL for http source", "manifests/dvInvalidURL.yaml", true, "spec.source Invalid source URL"),
|
||||
table.Entry("[test_id:1765]fail with invalid source PVC", "manifests/dvInvalidSourcePVC.yaml", true, "spec.source.pvc.name in body is required", "spec.source.pvc.name: Required value"),
|
||||
@ -231,16 +231,16 @@ var _ = Describe("[rfe_id:1130][crit:medium][posneg:negative][vendor:cnv-qe@redh
|
||||
table.Entry("[test_id:1767]fail with missing PVC spec", "manifests/dvMissingPVCSpec.yaml", true, "Missing Data volume PVC"),
|
||||
table.Entry("[test_id:3920]fail with missing PVC accessModes", "manifests/dvMissingPVCAccessModes.yaml", true, "spec.pvc.accessModes in body is required", "spec.pvc.accessModes: Required value"),
|
||||
table.Entry("[test_id:1768]fail with missing resources spec", "manifests/dvMissingResourceSpec.yaml", true, "spec.pvc.resources in body is required", "spec.pvc.resources: Required value"),
|
||||
table.Entry("[test_id:3921]fail with missing PVC size", "manifests/dvMissingPVCSize.yaml", true, "PVC size is missing"),
|
||||
table.Entry("[test_id:3921]fail with missing PVC size", "manifests/dvMissingPVCSize.yaml", true, "PVC size is missing", "spec.pvc.resources.requests in body must be of type object"),
|
||||
table.Entry("[test_id:1769]fail with 0 size PVC", "manifests/dv0SizePVC.yaml", true, "PVC size can't be equal or less than zero"),
|
||||
table.Entry("[test_id:1937]fail with invalid content type on blank image", "manifests/dvBlankInvalidContentType.yaml", true, "ContentType not one of: kubevirt, archive"),
|
||||
table.Entry("[test_id:1931][posneg:positive]succeed with leading zero in requests storage size", "manifests/dvLeadingZero.yaml", false, ""),
|
||||
table.Entry("[test_id:1925]fail with invalid request storage size", "manifests/dvInvalidStorageSizeQuantity.yaml", true, "quantities must match the regular expression '^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$"),
|
||||
table.Entry("[test_id:1923]fail with missing storage size", "manifests/dvMissingRequestSpec.yaml", true, "PVC size is missing"),
|
||||
table.Entry("[test_id:1923]fail with missing storage size", "manifests/dvMissingRequestSpec.yaml", true, "PVC size is missing", "spec.pvc.resources in body must be of type object"),
|
||||
table.Entry("[test_id:1915]fail with invalid access modes", "manifests/dvInvalidAccessModes.yaml", true, "supported values: \"ReadOnlyMany\", \"ReadWriteMany\", \"ReadWriteOnce\""),
|
||||
table.Entry("[test_id:3922]fail with multiple access modes", "manifests/dvMultipleAccessModes.yaml", true, "PVC multiple accessModes"),
|
||||
table.Entry("[test_id:1861]fail with missing source (but source key)", "manifests/dvMissingSource2.yaml", true, "Missing Data volume source"),
|
||||
table.Entry("[test_id:1860]fail with missing http url key", "manifests/dvMissingSourceHttp.yaml", true, "Missing Data volume source"),
|
||||
table.Entry("[test_id:1860]fail with missing http url key", "manifests/dvMissingSourceHttp.yaml", true, "Missing Data volume source", "spec.source.http in body must be of type object"),
|
||||
table.Entry("[test_id:1858]fail with missing datavolume spec", "manifests/dvMissingCompleteSpec.yaml", true, "Missing Data volume source"),
|
||||
// k8s < 1.15 return Required value: name or generateName is required, >= 1.15 return error validating data: unknown object type "nil" in DataVolume.metadata
|
||||
table.Entry("[test_id:1857]fail without datavolume name", "manifests/dvNoName.yaml", true, "Required value: name or generateName is required", "error validating data: unknown object type \"nil\" in DataVolume.metadata"),
|
||||
|
@ -4,8 +4,13 @@ import (
|
||||
"fmt"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
"github.com/onsi/ginkgo/extensions/table"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
extv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"kubevirt.io/containerized-data-importer/tests"
|
||||
"kubevirt.io/containerized-data-importer/tests/framework"
|
||||
)
|
||||
@ -103,6 +108,28 @@ var _ = Describe("[rfe_id:1347][crit:high][vendor:cnv-qe@redhat.com][level:compo
|
||||
ValidateRBACForResource(f, secretsExpectedResult, "secrets", sa)
|
||||
})
|
||||
})
|
||||
|
||||
Context("CRDs must be a structural schema", func() {
|
||||
table.DescribeTable("crd name", func(crdName string) {
|
||||
crd, err := f.ExtClient.ApiextensionsV1().CustomResourceDefinitions().Get(crdName, metav1.GetOptions{})
|
||||
if k8serrors.IsNotFound(err) {
|
||||
Skip("Doesn't work on openshift 3.11")
|
||||
}
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(crd.ObjectMeta.Name).To(Equal(crdName))
|
||||
for _, cond := range crd.Status.Conditions {
|
||||
if cond.Type == extv1.CustomResourceDefinitionConditionType("NonStructuralSchema") {
|
||||
if cond.Status == extv1.ConditionTrue {
|
||||
Fail(fmt.Sprintf("CRD %s is not a structural schema", crdName))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
table.Entry("CDIConfigs", "cdiconfigs.cdi.kubevirt.io"),
|
||||
table.Entry("CDIs", "cdis.cdi.kubevirt.io"),
|
||||
table.Entry("Datavolumes", "datavolumes.cdi.kubevirt.io"),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
func ValidateRBACForResource(f *framework.Framework, expectedResults map[string]string, resource string, sa string) {
|
||||
|
@ -22,6 +22,7 @@ go_library(
|
||||
"//vendor/github.com/onsi/gomega:go_default_library",
|
||||
"//vendor/github.com/pkg/errors:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
extclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||
apierrs "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -79,6 +80,8 @@ type Framework struct {
|
||||
CdiClient *cdiClientset.Clientset
|
||||
// CsiClient provides our CSI client pointer
|
||||
CsiClient *csiClientset.Clientset
|
||||
// ExtClient provides our CSI client pointer
|
||||
ExtClient *extclientset.Clientset
|
||||
// RestConfig provides a pointer to our REST client config.
|
||||
RestConfig *rest.Config
|
||||
// Namespace provides a namespace for each test generated/unique ns per test
|
||||
@ -208,6 +211,12 @@ func NewFramework(prefix string, config Config) (*Framework, error) {
|
||||
}
|
||||
f.CsiClient = csics
|
||||
|
||||
extcs, err := f.GetExtClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "ERROR, unable to create CsiClient")
|
||||
}
|
||||
f.ExtClient = extcs
|
||||
|
||||
ginkgo.BeforeEach(f.BeforeEach)
|
||||
ginkgo.AfterEach(f.AfterEach)
|
||||
f.reporter = NewKubernetesReporter()
|
||||
@ -356,6 +365,19 @@ func (f *Framework) GetCsiClient() (*csiClientset.Clientset, error) {
|
||||
return csiClient, nil
|
||||
}
|
||||
|
||||
// GetExtClient gets an instance of a kubernetes client that includes all the api extensions.
|
||||
func (f *Framework) GetExtClient() (*extclientset.Clientset, error) {
|
||||
cfg, err := clientcmd.BuildConfigFromFlags(f.Master, f.KubeConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
extClient, err := extclientset.NewForConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extClient, nil
|
||||
}
|
||||
|
||||
// GetCdiClientForServiceAccount returns a cdi client for a service account
|
||||
func (f *Framework) GetCdiClientForServiceAccount(namespace, name string) (*cdiClientset.Clientset, error) {
|
||||
var secretName string
|
||||
|
Loading…
Reference in New Issue
Block a user