diff --git a/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go b/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go index 191fae03c90..f872fd527a8 100644 --- a/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go +++ b/pkg/api/apis/operators/v1alpha1/clusterserviceversion_types.go @@ -102,14 +102,23 @@ type APIServiceDefinitions struct { Required []APIServiceDescription `json:"required,omitempty"` } -// ClusterServiceVersionSpec declarations tell the OLM how to install an operator -// that can manage apps for given version and AppType. +// NativeAPI describes the GVK of a Kubernetes resource that is required by an +// Operator, but must be provided by the underlying cluster and not an extension. +type NativeAPI struct { + Group string `json:"group"` + Version string `json:"version"` + Kind string `json:"kind"` +} + +// ClusterServiceVersionSpec declarations tell OLM how to install an operator +// that can manage apps for a given version. type ClusterServiceVersionSpec struct { InstallStrategy NamedInstallStrategy `json:"install"` Version semver.Version `json:"version,omitempty"` Maturity string `json:"maturity,omitempty"` CustomResourceDefinitions CustomResourceDefinitions `json:"customresourcedefinitions,omitempty"` APIServiceDefinitions APIServiceDefinitions `json:"apiservicedefinitions,omitempty"` + NativeAPIs []NativeAPI `json:"nativeAPIs,omitempty"` DisplayName string `json:"displayName"` Description string `json:"description,omitempty"` Keywords []string `json:"keywords,omitempty"` diff --git a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go index 3ccf374c4a1..761e3aa67aa 100644 --- a/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go @@ -402,6 +402,7 @@ func (in *ClusterServiceVersionSpec) DeepCopyInto(out *ClusterServiceVersionSpec out.Version = in.Version in.CustomResourceDefinitions.DeepCopyInto(&out.CustomResourceDefinitions) in.APIServiceDefinitions.DeepCopyInto(&out.APIServiceDefinitions) + out.NativeAPIs = in.NativeAPIs if in.Keywords != nil { in, out := &in.Keywords, &out.Keywords *out = make([]string, len(*in)) @@ -755,6 +756,22 @@ func (in *NamedInstallStrategy) DeepCopy() *NamedInstallStrategy { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *NativeAPI) DeepCopyInto(out *NativeAPI) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NativeAPI. +func (in *NativeAPI) DeepCopy() *NativeAPI { + if in == nil { + return nil + } + out := new(NativeAPI) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RequirementStatus) DeepCopyInto(out *RequirementStatus) { *out = *in diff --git a/pkg/controller/operators/olm/requirements.go b/pkg/controller/operators/olm/requirements.go index ba464fc4e4c..019fc25708f 100644 --- a/pkg/controller/operators/olm/requirements.go +++ b/pkg/controller/operators/olm/requirements.go @@ -13,7 +13,8 @@ import ( ) func (a *Operator) requirementStatus(strategyDetailsDeployment *install.StrategyDetailsDeployment, crdDescs []v1alpha1.CRDDescription, - ownedAPIServiceDescs []v1alpha1.APIServiceDescription, requiredAPIServiceDescs []v1alpha1.APIServiceDescription) (met bool, statuses []v1alpha1.RequirementStatus) { + ownedAPIServiceDescs []v1alpha1.APIServiceDescription, requiredAPIServiceDescs []v1alpha1.APIServiceDescription, + requiredNativeAPIs []v1alpha1.NativeAPI) (met bool, statuses []v1alpha1.RequirementStatus) { met = true // Check for CRDs @@ -126,6 +127,27 @@ func (a *Operator) requirementStatus(strategyDetailsDeployment *install.Strategy } } + for _, r := range requiredNativeAPIs { + name := fmt.Sprintf("%s.%s", r.Version, r.Group) + status := v1alpha1.RequirementStatus{ + Group: r.Group, + Version: r.Version, + Kind: r.Kind, + Name: name, + } + + if err := a.isGVKRegistered(r.Group, r.Version, r.Kind); err != nil { + status.Status = v1alpha1.RequirementStatusReasonNotPresent + met = false + statuses = append(statuses, status) + continue + } else { + status.Status = v1alpha1.RequirementStatusReasonPresent + statuses = append(statuses, status) + continue + } + } + return } @@ -239,7 +261,7 @@ func (a *Operator) requirementAndPermissionStatus(csv *v1alpha1.ClusterServiceVe return false, nil, fmt.Errorf("could not cast install strategy as type %T", strategyDetailsDeployment) } - reqMet, reqStatuses := a.requirementStatus(strategyDetailsDeployment, csv.GetAllCRDDescriptions(), csv.GetOwnedAPIServiceDescriptions(), csv.GetRequiredAPIServiceDescriptions()) + reqMet, reqStatuses := a.requirementStatus(strategyDetailsDeployment, csv.GetAllCRDDescriptions(), csv.GetOwnedAPIServiceDescriptions(), csv.GetRequiredAPIServiceDescriptions(), csv.Spec.NativeAPIs) ruleChecker := install.NewCSVRuleChecker(a.roleLister, a.roleBindingLister, a.clusterRoleLister, a.clusterRoleBindingLister, csv) permMet, permStatuses, err := a.permissionStatus(strategyDetailsDeployment, ruleChecker, csv.GetNamespace())