github.com/crossplane/upjet@v1.3.0/pkg/migration/registry.go (about) 1 // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io> 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 5 package migration 6 7 import ( 8 "regexp" 9 10 "github.com/crossplane/crossplane-runtime/pkg/resource" 11 xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1" 12 xpmetav1 "github.com/crossplane/crossplane/apis/pkg/meta/v1" 13 xpmetav1alpha1 "github.com/crossplane/crossplane/apis/pkg/meta/v1alpha1" 14 xppkgv1 "github.com/crossplane/crossplane/apis/pkg/v1" 15 xppkgv1beta1 "github.com/crossplane/crossplane/apis/pkg/v1beta1" 16 "github.com/pkg/errors" 17 "k8s.io/apimachinery/pkg/runtime" 18 "k8s.io/apimachinery/pkg/runtime/schema" 19 ) 20 21 var ( 22 // AllCompositions matches all v1.Composition names. 23 AllCompositions = regexp.MustCompile(`.*`) 24 // AllConfigurations matches all metav1.Configuration names. 25 AllConfigurations = regexp.MustCompile(`.*`) 26 // CrossplaneLockName is the Crossplane package lock's `metadata.name` 27 CrossplaneLockName = regexp.MustCompile(`^lock$`) 28 ) 29 30 const ( 31 errAddToScheme = "failed to register types with the registry's scheme" 32 errFmtNewObject = "failed to instantiate a new runtime.Object using runtime.Scheme for: %s" 33 errFmtNotManagedResource = "specified GVK does not belong to a managed resource: %s" 34 ) 35 36 type patchSetConverter struct { 37 // re is the regular expression against which a Composition's name 38 // will be matched to determine whether the conversion function 39 // will be invoked. 40 re *regexp.Regexp 41 // converter is the PatchSetConverter to be run on the Composition's 42 // patch sets. 43 converter PatchSetConverter 44 } 45 46 type configurationMetadataConverter struct { 47 // re is the regular expression against which a Configuration's name 48 // will be matched to determine whether the conversion function 49 // will be invoked. 50 re *regexp.Regexp 51 // converter is the ConfigurationMetadataConverter to be run on the Configuration's 52 // metadata. 53 converter ConfigurationMetadataConverter 54 } 55 56 type configurationPackageConverter struct { 57 // re is the regular expression against which a Configuration package's 58 // reference will be matched to determine whether the conversion function 59 // will be invoked. 60 re *regexp.Regexp 61 // converter is the ConfigurationPackageConverter to be run on the 62 // Configuration package. 63 converter ConfigurationPackageConverter 64 } 65 66 type providerPackageConverter struct { 67 // re is the regular expression against which a Provider package's 68 // reference will be matched to determine whether the conversion function 69 // will be invoked. 70 re *regexp.Regexp 71 // converter is the ProviderPackageConverter to be run on the 72 // Provider package. 73 converter ProviderPackageConverter 74 } 75 76 type packageLockConverter struct { 77 // re is the regular expression against which a package Lock's name 78 // will be matched to determine whether the conversion function 79 // will be invoked. 80 re *regexp.Regexp 81 // converter is the PackageLockConverter to be run on the package Lock. 82 converter PackageLockConverter 83 } 84 85 // Registry is a registry of `migration.Converter`s keyed with 86 // the associated `schema.GroupVersionKind`s and an associated 87 // runtime.Scheme with which the corresponding types are registered. 88 type Registry struct { 89 unstructuredPreProcessors map[Category][]UnstructuredPreProcessor 90 resourcePreProcessors []ManagedPreProcessor 91 resourceConverters map[schema.GroupVersionKind]ResourceConverter 92 templateConverters map[schema.GroupVersionKind]ComposedTemplateConverter 93 patchSetConverters []patchSetConverter 94 configurationMetaConverters []configurationMetadataConverter 95 configurationPackageConverters []configurationPackageConverter 96 providerPackageConverters []providerPackageConverter 97 packageLockConverters []packageLockConverter 98 categoricalConverters map[Category][]CategoricalConverter 99 scheme *runtime.Scheme 100 claimTypes []schema.GroupVersionKind 101 compositeTypes []schema.GroupVersionKind 102 } 103 104 // NewRegistry returns a new Registry initialized with 105 // the specified runtime.Scheme. 106 func NewRegistry(scheme *runtime.Scheme) *Registry { 107 return &Registry{ 108 resourceConverters: make(map[schema.GroupVersionKind]ResourceConverter), 109 templateConverters: make(map[schema.GroupVersionKind]ComposedTemplateConverter), 110 categoricalConverters: make(map[Category][]CategoricalConverter), 111 unstructuredPreProcessors: make(map[Category][]UnstructuredPreProcessor), 112 scheme: scheme, 113 } 114 } 115 116 // make sure a converter is being registered for a managed resource, 117 // and it's registered with our runtime scheme. 118 // This will be needed, during runtime, for properly converting resources. 119 func (r *Registry) assertManagedResource(gvk schema.GroupVersionKind) { 120 obj, err := r.scheme.New(gvk) 121 if err != nil { 122 panic(errors.Wrapf(err, errFmtNewObject, gvk)) 123 } 124 if _, ok := obj.(resource.Managed); !ok { 125 panic(errors.Errorf(errFmtNotManagedResource, gvk)) 126 } 127 } 128 129 // RegisterResourceConverter registers the specified ResourceConverter 130 // for the specified GVK with this Registry. 131 func (r *Registry) RegisterResourceConverter(gvk schema.GroupVersionKind, conv ResourceConverter) { 132 r.assertManagedResource(gvk) 133 r.resourceConverters[gvk] = conv 134 } 135 136 // RegisterTemplateConverter registers the specified ComposedTemplateConverter 137 // for the specified GVK with this Registry. 138 func (r *Registry) RegisterTemplateConverter(gvk schema.GroupVersionKind, conv ComposedTemplateConverter) { 139 r.assertManagedResource(gvk) 140 r.templateConverters[gvk] = conv 141 } 142 143 // RegisterCompositionConverter is a convenience method for registering both 144 // a ResourceConverter and a ComposedTemplateConverter that act on the same 145 // managed resource kind and are implemented by the same type. 146 func (r *Registry) RegisterCompositionConverter(gvk schema.GroupVersionKind, conv CompositionConverter) { 147 r.RegisterResourceConverter(gvk, conv) 148 r.RegisterTemplateConverter(gvk, conv) 149 } 150 151 // RegisterPatchSetConverter registers the given PatchSetConverter for 152 // the compositions whose name match the given regular expression. 153 func (r *Registry) RegisterPatchSetConverter(re *regexp.Regexp, psConv PatchSetConverter) { 154 r.patchSetConverters = append(r.patchSetConverters, patchSetConverter{ 155 re: re, 156 converter: psConv, 157 }) 158 } 159 160 // RegisterConfigurationMetadataConverter registers the given ConfigurationMetadataConverter 161 // for the configurations whose name match the given regular expression. 162 func (r *Registry) RegisterConfigurationMetadataConverter(re *regexp.Regexp, confConv ConfigurationMetadataConverter) { 163 r.configurationMetaConverters = append(r.configurationMetaConverters, configurationMetadataConverter{ 164 re: re, 165 converter: confConv, 166 }) 167 } 168 169 // RegisterConfigurationMetadataV1ConversionFunction registers the specified 170 // ConfigurationMetadataV1ConversionFn for the v1 configurations whose name match 171 // the given regular expression. 172 func (r *Registry) RegisterConfigurationMetadataV1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationMetadataV1ConversionFn) { 173 r.RegisterConfigurationMetadataConverter(re, &delegatingConverter{ 174 confMetaV1Fn: confConversionFn, 175 }) 176 } 177 178 // RegisterConfigurationMetadataV1Alpha1ConversionFunction registers the specified 179 // ConfigurationMetadataV1Alpha1ConversionFn for the v1alpha1 configurations 180 // whose name match the given regular expression. 181 func (r *Registry) RegisterConfigurationMetadataV1Alpha1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationMetadataV1Alpha1ConversionFn) { 182 r.RegisterConfigurationMetadataConverter(re, &delegatingConverter{ 183 confMetaV1Alpha1Fn: confConversionFn, 184 }) 185 } 186 187 // RegisterConfigurationPackageConverter registers the specified 188 // ConfigurationPackageConverter for the Configuration v1 packages whose reference 189 // match the given regular expression. 190 func (r *Registry) RegisterConfigurationPackageConverter(re *regexp.Regexp, pkgConv ConfigurationPackageConverter) { 191 r.configurationPackageConverters = append(r.configurationPackageConverters, configurationPackageConverter{ 192 re: re, 193 converter: pkgConv, 194 }) 195 } 196 197 // RegisterConfigurationPackageV1ConversionFunction registers the specified 198 // ConfigurationPackageV1ConversionFn for the Configuration v1 packages whose reference 199 // match the given regular expression. 200 func (r *Registry) RegisterConfigurationPackageV1ConversionFunction(re *regexp.Regexp, confConversionFn ConfigurationPackageV1ConversionFn) { 201 r.RegisterConfigurationPackageConverter(re, &delegatingConverter{ 202 confPackageV1Fn: confConversionFn, 203 }) 204 } 205 206 // RegisterProviderPackageConverter registers the given ProviderPackageConverter 207 // for the provider packages whose references match the given regular expression. 208 func (r *Registry) RegisterProviderPackageConverter(re *regexp.Regexp, pkgConv ProviderPackageConverter) { 209 r.providerPackageConverters = append(r.providerPackageConverters, providerPackageConverter{ 210 re: re, 211 converter: pkgConv, 212 }) 213 } 214 215 // RegisterProviderPackageV1ConversionFunction registers the specified 216 // ProviderPackageV1ConversionFn for the provider v1 packages whose reference 217 // match the given regular expression. 218 func (r *Registry) RegisterProviderPackageV1ConversionFunction(re *regexp.Regexp, pkgConversionFn ProviderPackageV1ConversionFn) { 219 r.RegisterProviderPackageConverter(re, &delegatingConverter{ 220 providerPackageV1Fn: pkgConversionFn, 221 }) 222 } 223 224 // RegisterPackageLockConverter registers the given PackageLockConverter. 225 func (r *Registry) RegisterPackageLockConverter(re *regexp.Regexp, lockConv PackageLockConverter) { 226 r.packageLockConverters = append(r.packageLockConverters, packageLockConverter{ 227 re: re, 228 converter: lockConv, 229 }) 230 } 231 232 // RegisterCategoricalConverter registers the specified CategoricalConverter 233 // for the specified Category of resources. 234 func (r *Registry) RegisterCategoricalConverter(c Category, converter CategoricalConverter) { 235 r.categoricalConverters[c] = append(r.categoricalConverters[c], converter) 236 } 237 238 // RegisterCategoricalConverterFunction registers the specified 239 // CategoricalConverterFunctionFn for the specified Category. 240 func (r *Registry) RegisterCategoricalConverterFunction(c Category, converterFn CategoricalConverterFunctionFn) { 241 r.RegisterCategoricalConverter(c, &delegatingConverter{ 242 categoricalConverterFn: converterFn, 243 }) 244 } 245 246 // RegisterPackageLockV1Beta1ConversionFunction registers the specified 247 // RegisterPackageLockV1Beta1ConversionFunction for the package v1beta1 locks. 248 func (r *Registry) RegisterPackageLockV1Beta1ConversionFunction(re *regexp.Regexp, lockConversionFn PackageLockV1Beta1ConversionFn) { 249 r.RegisterPackageLockConverter(re, &delegatingConverter{ 250 packageLockV1Beta1Fn: lockConversionFn, 251 }) 252 } 253 254 // AddToScheme registers types with this Registry's runtime.Scheme 255 func (r *Registry) AddToScheme(sb func(scheme *runtime.Scheme) error) error { 256 return errors.Wrap(sb(r.scheme), errAddToScheme) 257 } 258 259 // AddCompositionTypes registers the Composition types with 260 // the registry's scheme. Only the v1 API of Compositions 261 // is currently supported. 262 func (r *Registry) AddCompositionTypes() error { 263 return r.AddToScheme(xpv1.AddToScheme) 264 } 265 266 // AddCrossplanePackageTypes registers the 267 // {Provider,Configuration,Lock, etc.}.pkg types with 268 // the registry's scheme. 269 func (r *Registry) AddCrossplanePackageTypes() error { 270 if err := r.AddToScheme(xppkgv1beta1.AddToScheme); err != nil { 271 return err 272 } 273 return r.AddToScheme(xppkgv1.AddToScheme) 274 } 275 276 // AddClaimType registers a new composite resource claim type 277 // with the given GVK 278 func (r *Registry) AddClaimType(gvk schema.GroupVersionKind) { 279 r.claimTypes = append(r.claimTypes, gvk) 280 } 281 282 // AddCompositeType registers a new composite resource type with the given GVK 283 func (r *Registry) AddCompositeType(gvk schema.GroupVersionKind) { 284 r.compositeTypes = append(r.compositeTypes, gvk) 285 } 286 287 // GetManagedResourceGVKs returns a list of all registered managed resource 288 // GVKs 289 func (r *Registry) GetManagedResourceGVKs() []schema.GroupVersionKind { 290 gvks := make([]schema.GroupVersionKind, 0, len(r.resourceConverters)+len(r.templateConverters)) 291 for gvk := range r.resourceConverters { 292 gvks = append(gvks, gvk) 293 } 294 for gvk := range r.templateConverters { 295 gvks = append(gvks, gvk) 296 } 297 return gvks 298 } 299 300 // GetCompositionGVKs returns the registered Composition GVKs. 301 func (r *Registry) GetCompositionGVKs() []schema.GroupVersionKind { 302 // Composition types are registered with this registry's scheme 303 if _, ok := r.scheme.AllKnownTypes()[xpv1.CompositionGroupVersionKind]; ok { 304 return []schema.GroupVersionKind{xpv1.CompositionGroupVersionKind} 305 } 306 return nil 307 } 308 309 // GetCrossplanePackageGVKs returns the registered Crossplane package GVKs. 310 func (r *Registry) GetCrossplanePackageGVKs() []schema.GroupVersionKind { 311 if r.scheme.AllKnownTypes()[xppkgv1.ProviderGroupVersionKind] == nil || 312 r.scheme.AllKnownTypes()[xppkgv1.ConfigurationGroupVersionKind] == nil || 313 r.scheme.AllKnownTypes()[xppkgv1beta1.LockGroupVersionKind] == nil { 314 return nil 315 } 316 return []schema.GroupVersionKind{ 317 xppkgv1.ProviderGroupVersionKind, 318 xppkgv1.ConfigurationGroupVersionKind, 319 xppkgv1beta1.LockGroupVersionKind, 320 } 321 } 322 323 // GetAllRegisteredGVKs returns a list of registered GVKs 324 // including v1.CompositionGroupVersionKind, 325 // metav1.ConfigurationGroupVersionKind, 326 // metav1alpha1.ConfigurationGroupVersionKind 327 // pkg.ConfigurationGroupVersionKind, 328 // pkg.ProviderGroupVersionKind, 329 // pkg.LockGroupVersionKind. 330 func (r *Registry) GetAllRegisteredGVKs() []schema.GroupVersionKind { 331 gvks := make([]schema.GroupVersionKind, 0, len(r.claimTypes)+len(r.compositeTypes)+len(r.resourceConverters)+len(r.templateConverters)+1) 332 gvks = append(gvks, r.claimTypes...) 333 gvks = append(gvks, r.compositeTypes...) 334 gvks = append(gvks, r.GetManagedResourceGVKs()...) 335 gvks = append(gvks, xpv1.CompositionGroupVersionKind, xpmetav1.ConfigurationGroupVersionKind, xpmetav1alpha1.ConfigurationGroupVersionKind, 336 xppkgv1.ConfigurationGroupVersionKind, xppkgv1.ProviderGroupVersionKind, xppkgv1beta1.LockGroupVersionKind) 337 return gvks 338 } 339 340 // ResourceConversionFn is a function that converts the specified migration 341 // source managed resource to one or more migration target managed resources. 342 type ResourceConversionFn func(mg resource.Managed) ([]resource.Managed, error) 343 344 // ComposedTemplateConversionFn is a function that converts from the specified 345 // migration source v1.ComposedTemplate to one or more migration 346 // target v1.ComposedTemplates. 347 type ComposedTemplateConversionFn func(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error 348 349 // PatchSetsConversionFn is a function that converts 350 // the `spec.patchSets` of a Composition from the migration source provider's 351 // schema to the migration target provider's schema. 352 type PatchSetsConversionFn func(psMap map[string]*xpv1.PatchSet) error 353 354 // ConfigurationMetadataV1ConversionFn is a function that converts the specified 355 // migration source Configuration v1 metadata to the migration target 356 // Configuration metadata. 357 type ConfigurationMetadataV1ConversionFn func(configuration *xpmetav1.Configuration) error 358 359 // ConfigurationMetadataV1Alpha1ConversionFn is a function that converts the specified 360 // migration source Configuration v1alpha1 metadata to the migration target 361 // Configuration metadata. 362 type ConfigurationMetadataV1Alpha1ConversionFn func(configuration *xpmetav1alpha1.Configuration) error 363 364 // PackageLockV1Beta1ConversionFn is a function that converts the specified 365 // migration source package v1beta1 lock to the migration target 366 // package lock. 367 type PackageLockV1Beta1ConversionFn func(pkg *xppkgv1beta1.Lock) error 368 369 // ConfigurationPackageV1ConversionFn is a function that converts the specified 370 // migration source Configuration v1 package to the migration target 371 // Configuration package(s). 372 type ConfigurationPackageV1ConversionFn func(pkg *xppkgv1.Configuration) error 373 374 // ProviderPackageV1ConversionFn is a function that converts the specified 375 // migration source provider v1 package to the migration target 376 // Provider package(s). 377 type ProviderPackageV1ConversionFn func(pkg xppkgv1.Provider) ([]xppkgv1.Provider, error) 378 379 // CategoricalConverterFunctionFn is a function that converts resources of a 380 // Category. Because it receives an unstructured argument, it should be 381 // used for implementing generic conversion functions acting on a specific 382 // category. 383 type CategoricalConverterFunctionFn func(u *UnstructuredWithMetadata) error 384 385 type delegatingConverter struct { 386 rFn ResourceConversionFn 387 cmpFn ComposedTemplateConversionFn 388 psFn PatchSetsConversionFn 389 confMetaV1Fn ConfigurationMetadataV1ConversionFn 390 confMetaV1Alpha1Fn ConfigurationMetadataV1Alpha1ConversionFn 391 confPackageV1Fn ConfigurationPackageV1ConversionFn 392 providerPackageV1Fn ProviderPackageV1ConversionFn 393 packageLockV1Beta1Fn PackageLockV1Beta1ConversionFn 394 categoricalConverterFn CategoricalConverterFunctionFn 395 } 396 397 func (d *delegatingConverter) Convert(u *UnstructuredWithMetadata) error { 398 if d.categoricalConverterFn == nil { 399 return nil 400 } 401 return d.categoricalConverterFn(u) 402 } 403 404 func (d *delegatingConverter) ConfigurationPackageV1(pkg *xppkgv1.Configuration) error { 405 if d.confPackageV1Fn == nil { 406 return nil 407 } 408 return d.confPackageV1Fn(pkg) 409 } 410 411 func (d *delegatingConverter) PackageLockV1Beta1(lock *xppkgv1beta1.Lock) error { 412 if d.packageLockV1Beta1Fn == nil { 413 return nil 414 } 415 return d.packageLockV1Beta1Fn(lock) 416 } 417 418 func (d *delegatingConverter) ProviderPackageV1(pkg xppkgv1.Provider) ([]xppkgv1.Provider, error) { 419 if d.providerPackageV1Fn == nil { 420 return []xppkgv1.Provider{pkg}, nil 421 } 422 return d.providerPackageV1Fn(pkg) 423 } 424 425 func (d *delegatingConverter) ConfigurationMetadataV1(c *xpmetav1.Configuration) error { 426 if d.confMetaV1Fn == nil { 427 return nil 428 } 429 return d.confMetaV1Fn(c) 430 } 431 432 func (d *delegatingConverter) ConfigurationMetadataV1Alpha1(c *xpmetav1alpha1.Configuration) error { 433 if d.confMetaV1Alpha1Fn == nil { 434 return nil 435 } 436 return d.confMetaV1Alpha1Fn(c) 437 } 438 439 func (d *delegatingConverter) PatchSets(psMap map[string]*xpv1.PatchSet) error { 440 if d.psFn == nil { 441 return nil 442 } 443 return d.psFn(psMap) 444 } 445 446 // Resource takes a managed resource and returns zero or more managed 447 // resources to be created by calling the configured ResourceConversionFn. 448 func (d *delegatingConverter) Resource(mg resource.Managed) ([]resource.Managed, error) { 449 if d.rFn == nil { 450 return []resource.Managed{mg}, nil 451 } 452 return d.rFn(mg) 453 } 454 455 // ComposedTemplate converts from the specified migration source 456 // v1.ComposedTemplate to the migration target schema by calling the configured 457 // ComposedTemplateConversionFn. 458 func (d *delegatingConverter) ComposedTemplate(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error { 459 if d.cmpFn == nil { 460 return nil 461 } 462 return d.cmpFn(sourceTemplate, convertedTemplates...) 463 } 464 465 // DefaultCompositionConverter is a generic composition converter 466 // conversionMap: is fieldpath map for conversion 467 // Key of the conversionMap points to the source field 468 // Value of the conversionMap points to the target field 469 // Example: "spec.forProvider.assumeRolePolicyDocument": "spec.forProvider.assumeRolePolicy", 470 // fns are functions that manipulate the patchsets 471 func DefaultCompositionConverter(conversionMap map[string]string, fns ...func(sourceTemplate xpv1.ComposedTemplate) ([]xpv1.Patch, error)) ComposedTemplateConversionFn { 472 return func(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error { 473 var patchesToAdd []xpv1.Patch 474 for _, fn := range fns { 475 patches, err := fn(sourceTemplate) 476 if err != nil { 477 return errors.Wrap(err, "cannot run the patch sets converter function") 478 } 479 patchesToAdd = append(patchesToAdd, patches...) 480 } 481 patchesToAdd = append(patchesToAdd, ConvertComposedTemplatePatchesMap(sourceTemplate, conversionMap)...) 482 for i := range convertedTemplates { 483 convertedTemplates[i].Patches = append(convertedTemplates[i].Patches, patchesToAdd...) 484 } 485 return nil 486 } 487 } 488 489 // RegisterAPIConversionFunctions registers the supplied ResourceConversionFn and 490 // ComposedTemplateConversionFn for the specified GVK, and the supplied 491 // PatchSetsConversionFn for all the discovered Compositions. 492 // The specified GVK must belong to a Crossplane managed resource type and 493 // the type must already have been registered with this registry's scheme 494 // by calling Registry.AddToScheme. 495 func (r *Registry) RegisterAPIConversionFunctions(gvk schema.GroupVersionKind, rFn ResourceConversionFn, cmpFn ComposedTemplateConversionFn, psFn PatchSetsConversionFn) { 496 d := &delegatingConverter{ 497 rFn: rFn, 498 cmpFn: cmpFn, 499 psFn: psFn, 500 } 501 r.RegisterPatchSetConverter(AllCompositions, d) 502 r.RegisterCompositionConverter(gvk, d) 503 } 504 505 // RegisterConversionFunctions registers the supplied ResourceConversionFn and 506 // ComposedTemplateConversionFn for the specified GVK, and the supplied 507 // PatchSetsConversionFn for all the discovered Compositions. 508 // The specified GVK must belong to a Crossplane managed resource type and 509 // the type must already have been registered with this registry's scheme 510 // by calling Registry.AddToScheme. 511 // Deprecated: Use RegisterAPIConversionFunctions instead. 512 func (r *Registry) RegisterConversionFunctions(gvk schema.GroupVersionKind, rFn ResourceConversionFn, cmpFn ComposedTemplateConversionFn, psFn PatchSetsConversionFn) { 513 r.RegisterAPIConversionFunctions(gvk, rFn, cmpFn, psFn) 514 } 515 516 func (r *Registry) RegisterPreProcessor(category Category, pp UnstructuredPreProcessor) { 517 r.unstructuredPreProcessors[category] = append(r.unstructuredPreProcessors[category], pp) 518 } 519 520 // PreProcessor is a function type to convert pre-processor functions to 521 // UnstructuredPreProcessor. 522 type PreProcessor func(u UnstructuredWithMetadata) error 523 524 func (pp PreProcessor) PreProcess(u UnstructuredWithMetadata) error { 525 if pp == nil { 526 return nil 527 } 528 return pp(u) 529 } 530 531 func (r *Registry) RegisterResourcePreProcessor(pp ManagedPreProcessor) { 532 r.resourcePreProcessors = append(r.resourcePreProcessors, pp) 533 } 534 535 type ResourcePreProcessor func(mg resource.Managed) error 536 537 func (pp ResourcePreProcessor) ResourcePreProcessor(mg resource.Managed) error { 538 if pp == nil { 539 return nil 540 } 541 return pp(mg) 542 }