diff --git a/operatorcourier/validate.py b/operatorcourier/validate.py index 61e9fb6..5bffd13 100644 --- a/operatorcourier/validate.py +++ b/operatorcourier/validate.py @@ -188,6 +188,10 @@ def _csv_spec_validation(self, spec, bundleData): spec["customresourcedefinitions"], bundleData) is False: valid = False + if "apiservicedefinitions" in spec: + if self._csv_asd_validation(spec["apiservicedefinitions"]) is False: + valid = False + return valid def _csv_crd_validation(self, customresourcedefinitions, bundleData): @@ -307,6 +311,55 @@ def _csv_crd_validation(self, customresourcedefinitions, bundleData): return valid + def _csv_asd_validation(self, apiservicedefinitions): + valid = True + + if "owned" not in apiservicedefinitions: + self._log_error("spec.apiservicedefinitions.owned" + "not defined for csv") + return False + + # required attributes of owned apiservicedefinitions + attributeList = ["group", "version", "kind", "name", "deploymentName", + "displayName", "description"] + + # validate the owned apiservicedefinitions + def validate_owned(resource, attribute): + if attribute not in resource: + self._log_error( + "%s not defined for item in spec.apiservicedefinitions." % attribute) + return False + elif not resource[attribute]: + self._log_error("%s is empty for item in " + "spec.apiservicedefinitions." % attribute) + return False + return True + + for csvOwnedAsd in apiservicedefinitions["owned"]: + for attr in attributeList: + if validate_owned(csvOwnedAsd, attr) is False: + valid = False + + if "specDescriptors" in csvOwnedAsd and "name" in csvOwnedAsd: + if self._csv_descriptors_validation( + csvOwnedAsd["specDescriptors"], + csvOwnedAsd["name"]) is False: + valid = False + + if "statusDescriptors" in csvOwnedAsd and "name" in csvOwnedAsd: + if self._csv_descriptors_validation( + csvOwnedAsd["statusDescriptors"], + csvOwnedAsd["name"]) is False: + valid = False + + if "actionDescriptors" in csvOwnedAsd and "name" in csvOwnedAsd: + if self._csv_descriptors_validation( + csvOwnedAsd["actionDescriptors"], + csvOwnedAsd["name"]) is False: + valid = False + + return valid + def _csv_spec_install_validation(self, install): valid = True diff --git a/tests/test_files/bundles/verification/csvmissingasdownedattr.invalid.bundle.yaml b/tests/test_files/bundles/verification/csvmissingasdownedattr.invalid.bundle.yaml new file mode 100644 index 0000000..5a56ecb --- /dev/null +++ b/tests/test_files/bundles/verification/csvmissingasdownedattr.invalid.bundle.yaml @@ -0,0 +1,321 @@ +# CSV.spec.apiservicedefinitions.owned.{kind,deploymentName} and +# CSV.spec.apiservicedefinitions.owned.specDescriptors.{description,displayName} +# are empty in this file +data: + clusterServiceVersions: | + - apiVersion: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + metadata: + annotations: + alm-examples: '[{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdCluster","metadata":{"name":"example","namespace":"default"},"spec":{"size":3,"version":"3.2.13"}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdRestore","metadata":{"name":"example-etcd-cluster"},"spec":{"etcdCluster":{"name":"example-etcd-cluster"},"backupStorageType":"S3","s3":{"path":"","awsSecret":""}}},{"apiVersion":"etcd.database.coreos.com/v1beta2","kind":"EtcdBackup","metadata":{"name":"example-etcd-cluster-backup"},"spec":{"etcdEndpoints":[""],"storageType":"S3","s3":{"path":"","awsSecret":""}}}]' + categories: openshift required + certified: 'true' + containerImage: quay.io/openshift/origin-operator-marketplace:latest + createdAt: 2019/11/15 + description: An operator to run the OpenShift marketplace + healthIndex: B + repository: https://github.com/operator-framework/operator-marketplace + support: Red Hat + name: marketplace-operator.v0.0.1 + namespace: placeholder + spec: + apiservicedefinitions: + owned: + - description: Some description + displayName: Some Display Name + kind: SomeKind + name: somename.redhat.com + group: somegroup.redhat.com + version: v1alpha1 + deploymentName: some deployment name + - version: v1alpha1 + group: somegroup.redhat.com + kind: + description: Some description 2 + displayName: Some Display Name 2 + name: someothername.redhat.com + specDescriptors: + - path: type + customresourcedefinitions: + owned: + - description: Represents an OperatorSource. + displayName: Operator Source + kind: OperatorSource + name: operatorsources.marketplace.redhat.com + specDescriptors: + - description: The type of the operator source. + displayName: Type + path: type + - description: Points to the remote app registry server from where operator + manifests can be fetched. + displayName: Endpoint + path: endpoint + - description: 'The namespace in app registry. + + Only operator manifests under this namespace will be visible. + + Please note that this is not a k8s namespace.' + displayName: Registry Namespace + path: registryNamespace + statusDescriptors: + - description: Current status of the CatalogSourceConfig + displayName: Current Phase Name + path: currentPhase.phase.name + - description: Message associated with the current status + displayName: Current Phase Message + path: currentPhase.phase.message + version: v1alpha1 + - description: Represents a CatalogSourceConfig object which is used to configure + a CatalogSource. + displayName: Catalog Source Config + kind: CatalogSourceConfig + name: catalogsourceconfigs.marketplace.redhat.com + specDescriptors: + - description: The namespace where the operators will be enabled. + displayName: Target Namespace + path: targetNamespace + - description: List of operator(s) which will be enabled in the target namespace + displayName: Packages + path: packages + statusDescriptors: + - description: Current status of the CatalogSourceConfig + displayName: Current Phase Name + path: currentPhase.phase.name + - description: Message associated with the current status + displayName: Current Phase Message + path: currentPhase.phase.message + version: v1alpha1 + description: Marketplace is a gateway for users to consume off-cluster Operators + which will include Red Hat, ISV, optional OpenShift and community content. + displayName: marketplace-operator + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - marketplace.redhat.com + resources: + - '*' + verbs: + - '*' + - apiGroups: + - '' + resources: + - services + - configmaps + verbs: + - '*' + - apiGroups: + - operators.coreos.com + resources: + - catalogsources + verbs: + - '*' + serviceAccountName: marketplace-operator + deployments: + - name: marketplace-operator + spec: + replicas: 1 + selector: + matchLabels: + name: marketplace-operator + template: + metadata: + labels: + name: marketplace-operator + name: marketplace-operator + spec: + containers: + - command: + - marketplace-operator + env: + - name: WATCH_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: OPERATOR_NAME + value: marketplace-operator + image: quay.io/openshift/origin-operator-marketplace:latest + imagePullPolicy: Always + livenessProbe: + httpGet: + path: /healthz + port: 8080 + name: marketplace-operator + ports: + - containerPort: 60000 + name: metrics + - containerPort: 8080 + name: healthz + readinessProbe: + httpGet: + path: /healthz + port: 8080 + serviceAccountName: marketplace-operator + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - marketplace + - catalog + - olm + - admin + labels: + name: marketplace-operator + links: + - name: Markplace Operator Source Code + url: https://github.com/operator-framework/operator-marketplace + maintainers: + - email: aos-marketplace@redhat.com + name: AOS Marketplace Team + maturity: alpha + provider: + name: Red Hat + selector: + matchLabels: + name: marketplace-operator + version: 0.0.1 + customResourceDefinitions: | + - apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + metadata: + annotations: + description: Represents a CatalogSourceConfig. + displayName: Catalog Source Config + name: catalogsourceconfigs.marketplace.redhat.com + spec: + additionalPrinterColumns: + - JSONPath: .spec.targetNamespace + description: The namespace where the operators will be enabled + name: TargetNamespace + type: string + - JSONPath: .spec.packages + description: List of operator(s) which will be enabled in the target namespace + name: Packages + type: string + - JSONPath: .status.currentPhase.phase.name + description: Current status of the CatalogSourceConfig + name: Status + type: string + - JSONPath: .status.currentPhase.phase.message + description: Message associated with the current status + name: Message + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date + group: marketplace.redhat.com + names: + kind: CatalogSourceConfig + listKind: CatalogSourceConfigList + plural: catalogsourceconfigs + shortNames: + - csc + singular: catalogsourceconfig + scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + description: Spec for a CatalogSourceConfig + properties: + packages: + description: Comma separated list of operator(s) without spaces + which will be enabled in the target namespace + type: string + targetNamespace: + description: The namespace where the operators will be enabled + type: string + required: + - targetNamespace + - packages + type: object + version: v1alpha1 + - apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + metadata: + annotations: + description: Represents an OperatorSource. + displayName: Operator Source + name: operatorsources.marketplace.redhat.com + spec: + additionalPrinterColumns: + - JSONPath: .spec.type + description: The type of the OperatorSource + name: Type + type: string + - JSONPath: .spec.endpoint + description: The endpoint of the OperatorSource + name: Endpoint + type: string + - JSONPath: .spec.registryNamespace + description: App registry namespace + name: Registry + type: string + - JSONPath: .spec.displayName + description: Display (pretty) name to indicate the OperatorSource's name + name: DisplayName + type: string + - JSONPath: .spec.publisher + description: Publisher of the OperatorSource + name: Publisher + type: string + - JSONPath: .status.currentPhase.phase.name + description: Current status of the OperatorSource + name: Status + type: string + - JSONPath: .status.currentPhase.phase.message + description: Message associated with the current status + name: Message + type: string + - JSONPath: .metadata.creationTimestamp + name: Age + type: date + group: marketplace.redhat.com + names: + kind: OperatorSource + listKind: OperatorSourceList + plural: operatorsources + shortNames: + - opsrc + singular: operatorsource + scope: Namespaced + validation: + openAPIV3Schema: + properties: + spec: + description: Spec for an OperatorSource. + properties: + endpoint: + description: Points to the remote app registry server from where + operator manifests can be fetched. + type: string + registryNamespace: + description: 'The namespace in app registry. + + Only operator manifests under this namespace will be visible. + + Please note that this is not a k8s namespace.' + type: string + type: + description: The type of the OperatorSource + pattern: appregistry + type: string + required: + - type + - endpoint + - registryNamespace + type: object + version: v1alpha1 + packages: | + - channels: + - currentCSV: marketplace-operator.v0.0.1 + name: alpha + packageName: marketplace diff --git a/tests/test_files/yaml_source_dir/valid_yamls_with_single_crd/dynatrace-monitoring.v0.2.0.clusterserviceversion.yaml b/tests/test_files/yaml_source_dir/valid_yamls_with_single_crd/dynatrace-monitoring.v0.2.0.clusterserviceversion.yaml index 1034d34..a900816 100644 --- a/tests/test_files/yaml_source_dir/valid_yamls_with_single_crd/dynatrace-monitoring.v0.2.0.clusterserviceversion.yaml +++ b/tests/test_files/yaml_source_dir/valid_yamls_with_single_crd/dynatrace-monitoring.v0.2.0.clusterserviceversion.yaml @@ -38,7 +38,8 @@ metadata: name: dynatrace-monitoring.v0.2.0 namespace: "placeholder" spec: - apiservicedefinitions: {} + apiservicedefinitions: + owned: {} customresourcedefinitions: owned: - description: Dyantrace OneAgent monitoring agent diff --git a/tests/test_validate.py b/tests/test_validate.py index da24b97..c611453 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -69,8 +69,14 @@ def test_valid_bundles(bundle, expected_validation_results_dict): 'description is empty for descriptors in ' 'operatorsources.marketplace.redhat.com', 'path is empty for descriptors in ' - 'operatorsources.marketplace.redhat.com', - ], + 'operatorsources.marketplace.redhat.com'], + 'warnings': ['csv spec.icon not defined']}), + ("tests/test_files/bundles/verification/csvmissingasdownedattr.invalid.bundle.yaml", + {'errors': [ + 'kind is empty for item in spec.apiservicedefinitions.', + 'deploymentName not defined for item in spec.apiservicedefinitions.', + 'displayName is not defined for descriptors in someothername.redhat.com', + 'description is not defined for descriptors in someothername.redhat.com'], 'warnings': ['csv spec.icon not defined']}), ]) def test_invalid_bundle(bundle, expected_validation_results_dict):