@@ -25,8 +25,11 @@ import (
2525 "strings"
2626 "time"
2727
28+ admv1 "k8s.io/api/admissionregistration/v1"
2829 corev1 "k8s.io/api/core/v1"
30+ k8sextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2931 kerrors "k8s.io/apimachinery/pkg/api/errors"
32+ "k8s.io/apimachinery/pkg/runtime/schema"
3033 "k8s.io/client-go/kubernetes"
3134 ctrl "sigs.k8s.io/controller-runtime"
3235 "sigs.k8s.io/controller-runtime/pkg/client"
@@ -43,6 +46,10 @@ import (
4346 "github.com/crossplane/crossplane-runtime/v2/pkg/parser"
4447 "github.com/crossplane/crossplane-runtime/v2/pkg/resource"
4548
49+ extv1 "github.com/crossplane/crossplane/v2/apis/apiextensions/v1"
50+ extv1alpha1 "github.com/crossplane/crossplane/v2/apis/apiextensions/v1alpha1"
51+ extv2 "github.com/crossplane/crossplane/v2/apis/apiextensions/v2"
52+ opsv1alpha1 "github.com/crossplane/crossplane/v2/apis/ops/v1alpha1"
4653 pkgmetav1 "github.com/crossplane/crossplane/v2/apis/pkg/meta/v1"
4754 v1 "github.com/crossplane/crossplane/v2/apis/pkg/v1"
4855 "github.com/crossplane/crossplane/v2/apis/pkg/v1beta1"
@@ -82,6 +89,7 @@ const (
8289 errInitParserBackend = "cannot initialize parser backend"
8390 errParsePackage = "cannot parse package contents"
8491 errLintPackage = "linting package contents failed"
92+ errValidatePackage = "validating package contents failed"
8593 errNotOneMeta = "cannot install package with multiple meta types"
8694 errIncompatible = "incompatible Crossplane version"
8795
@@ -108,6 +116,7 @@ const (
108116 reasonImageConfig event.Reason = "ImageConfigSelection"
109117 reasonParse event.Reason = "ParsePackage"
110118 reasonLint event.Reason = "LintPackage"
119+ reasonValidate event.Reason = "ValidatePackage"
111120 reasonDependencies event.Reason = "ResolveDependencies"
112121 reasonConvertCRD event.Reason = "ConvertCRDToMRD"
113122 reasonSync event.Reason = "SyncPackage"
@@ -204,6 +213,13 @@ func WithLinter(l parser.Linter) ReconcilerOption {
204213 }
205214}
206215
216+ // WithValidator specifies how the Reconciler should validate a package.
217+ func WithValidator (v xpkg.Validator ) ReconcilerOption {
218+ return func (r * Reconciler ) {
219+ r .validator = v
220+ }
221+ }
222+
207223// WithVersioner specifies how the Reconciler should fetch the current
208224// Crossplane version.
209225func WithVersioner (v version.Operations ) ReconcilerOption {
@@ -243,6 +259,7 @@ type Reconciler struct {
243259 objects Establisher
244260 parser parser.Parser
245261 linter parser.Linter
262+ validator xpkg.Validator
246263 versioner version.Operations
247264 backend parser.Backend
248265 config xpkg.ConfigStore
@@ -289,15 +306,24 @@ func SetupProviderRevision(mgr ctrl.Manager, o controller.Options) error {
289306 Watches (& v1beta1.Lock {}, EnqueuePackageRevisionsForLock (mgr .GetClient (), & v1.ProviderRevisionList {}, log )).
290307 Watches (& v1beta1.ImageConfig {}, EnqueuePackageRevisionsForImageConfig (mgr .GetClient (), & v1.ProviderRevisionList {}, log ))
291308
309+ est := NewFilteringEstablisher (
310+ NewAPIEstablisher (mgr .GetClient (), o .Namespace , o .MaxConcurrentPackageEstablishers ),
311+ extv1alpha1 .ManagedResourceDefinitionGroupVersionKind .GroupKind (),
312+ schema.GroupKind {Group : k8sextv1 .SchemeGroupVersion .Group , Kind : "CustomResourceDefinition" },
313+ schema.GroupKind {Group : admv1 .SchemeGroupVersion .Group , Kind : "ValidatingWebhookConfiguration" },
314+ schema.GroupKind {Group : admv1 .SchemeGroupVersion .Group , Kind : "MutatingWebhookConfiguration" },
315+ )
316+
292317 r := NewReconciler (mgr ,
293318 WithCache (o .Cache ),
294319 WithDependencyManager (NewPackageDependencyManager (mgr .GetClient (), dag .NewMapDag , v1 .ProviderGroupVersionKind , log )),
295- WithEstablisher (NewAPIEstablisher ( mgr . GetClient (), o . Namespace , o . MaxConcurrentPackageEstablishers ) ),
320+ WithEstablisher (est ),
296321 WithNewPackageRevisionFn (nr ),
297322 WithParser (parser .New (metaScheme , objScheme )),
298323 WithParserBackend (NewImageBackend (fetcher )),
299324 WithConfigStore (xpkg .NewImageConfigStore (mgr .GetClient (), o .Namespace )),
300325 WithLinter (xpkg .NewProviderLinter ()),
326+ WithValidator (xpkg .NewProviderValidator ()),
301327 WithLogger (log ),
302328 WithRecorder (event .NewAPIRecorder (mgr .GetEventRecorderFor (name ), o .EventFilterFunctions ... )),
303329 WithNamespace (o .Namespace ),
@@ -334,16 +360,27 @@ func SetupConfigurationRevision(mgr ctrl.Manager, o controller.Options) error {
334360 return errors .Wrap (err , errCannotBuildFetcher )
335361 }
336362
363+ est := NewFilteringEstablisher (
364+ NewAPIEstablisher (mgr .GetClient (), o .Namespace , o .MaxConcurrentPackageEstablishers ),
365+ extv2 .CompositeResourceDefinitionGroupVersionKind .GroupKind (),
366+ extv1 .CompositionGroupVersionKind .GroupKind (),
367+ extv1alpha1 .ManagedResourceActivationPolicyGroupVersionKind .GroupKind (),
368+ opsv1alpha1 .OperationGroupVersionKind .GroupKind (),
369+ opsv1alpha1 .CronOperationGroupVersionKind .GroupKind (),
370+ opsv1alpha1 .WatchOperationGroupVersionKind .GroupKind (),
371+ )
372+
337373 log := o .Logger .WithValues ("controller" , name )
338374 r := NewReconciler (mgr ,
339375 WithCache (o .Cache ),
340376 WithDependencyManager (NewPackageDependencyManager (mgr .GetClient (), dag .NewMapDag , v1 .ConfigurationGroupVersionKind , log )),
341377 WithNewPackageRevisionFn (nr ),
342- WithEstablisher (NewAPIEstablisher ( mgr . GetClient (), o . Namespace , o . MaxConcurrentPackageEstablishers ) ),
378+ WithEstablisher (est ),
343379 WithParser (parser .New (metaScheme , objScheme )),
344380 WithParserBackend (NewImageBackend (f )),
345381 WithConfigStore (xpkg .NewImageConfigStore (mgr .GetClient (), o .Namespace )),
346382 WithLinter (xpkg .NewConfigurationLinter ()),
383+ WithValidator (xpkg .NewConfigurationValidator ()),
347384 WithLogger (log ),
348385 WithRecorder (event .NewAPIRecorder (mgr .GetEventRecorderFor (name ), o .EventFilterFunctions ... )),
349386 WithNamespace (o .Namespace ),
@@ -393,15 +430,24 @@ func SetupFunctionRevision(mgr ctrl.Manager, o controller.Options) error {
393430 Watches (& v1beta1.Lock {}, EnqueuePackageRevisionsForLock (mgr .GetClient (), & v1.FunctionRevisionList {}, log )).
394431 Watches (& v1beta1.ImageConfig {}, EnqueuePackageRevisionsForImageConfig (mgr .GetClient (), & v1.FunctionRevisionList {}, log ))
395432
433+ // The xpkg spec allows for CRDs to be included in function packages, but
434+ // states that they will not be installed. This means we shouldn't install
435+ // any objects from function packages. Create an empty filtering establisher
436+ // to filter them all out.
437+ est := NewFilteringEstablisher (
438+ NewAPIEstablisher (mgr .GetClient (), o .Namespace , o .MaxConcurrentPackageEstablishers ),
439+ )
440+
396441 r := NewReconciler (mgr ,
397442 WithCache (o .Cache ),
398443 WithDependencyManager (NewPackageDependencyManager (mgr .GetClient (), dag .NewMapDag , v1 .FunctionGroupVersionKind , log )),
399- WithEstablisher (NewAPIEstablisher ( mgr . GetClient (), o . Namespace , o . MaxConcurrentPackageEstablishers ) ),
444+ WithEstablisher (est ),
400445 WithNewPackageRevisionFn (nr ),
401446 WithParser (parser .New (metaScheme , objScheme )),
402447 WithParserBackend (NewImageBackend (fetcher )),
403448 WithConfigStore (xpkg .NewImageConfigStore (mgr .GetClient (), o .Namespace )),
404449 WithLinter (xpkg .NewFunctionLinter ()),
450+ WithValidator (xpkg .NewFunctionValidator ()),
405451 WithLogger (log ),
406452 WithRecorder (event .NewAPIRecorder (mgr .GetEventRecorderFor (name ), o .EventFilterFunctions ... )),
407453 WithNamespace (o .Namespace ),
@@ -784,22 +830,29 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco
784830 return reconcile.Result {}, err
785831 }
786832
787- // Lint package using package-specific linter.
788- if err := r .linter .Lint (pkg ); err != nil {
789- err = errors .Wrap (err , errLintPackage )
833+ // Validate the package using a package-specific validator. If validation
834+ // fails, we won't try to install the package.
835+ if err := r .validator .Lint (pkg ); err != nil {
836+ err = errors .Wrap (err , errValidatePackage )
790837 status .MarkConditions (v1 .RevisionUnhealthy ().WithMessage (err .Error ()))
791838
792839 _ = r .client .Status ().Update (ctx , pr )
793840
794- r .record .Event (pr , event .Warning (reasonLint , err ))
841+ r .record .Event (pr , event .Warning (reasonValidate , err ))
795842
796- // NOTE(hasheddan): a failed lint typically will require manual
797- // intervention, but on the off chance that we read pod logs
798- // early, which caused a linting failure, we will requeue by
799- // returning an error.
800843 return reconcile.Result {}, err
801844 }
802845
846+ // Lint package using package-specific linter. We can proceed with
847+ // installation even there are lint errors; we just record them in an event
848+ // for the user's information since they may cause unexpected behavior.
849+ if err := r .linter .Lint (pkg ); err != nil {
850+ err = errors .Wrap (err , errLintPackage )
851+ r .record .Event (pr , event .Warning (reasonLint , err ))
852+ // TODO(adamwg): Should we also record lint errors in the status for
853+ // posterity? Events are ephemeral.
854+ }
855+
803856 // NOTE(hasheddan): the linter should check this property already, but
804857 // if a consumer forgets to pass an option to guarantee one meta object,
805858 // we check here to avoid a potential panic on 0 index below.
0 commit comments