github.com/crossplane/upjet@v1.3.0/pkg/migration/configurationpackage_steps.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  	"fmt"
     9  
    10  	v1 "github.com/crossplane/crossplane-runtime/apis/common/v1"
    11  	"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
    12  	"github.com/pkg/errors"
    13  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    14  )
    15  
    16  const (
    17  	errSetDeletionPolicyFmt        = "failed to put the patch file to set the deletion policy to %q: %s"
    18  	errEditConfigurationPackageFmt = `failed to put the edited Configuration package: %s`
    19  )
    20  
    21  func (pg *PlanGenerator) convertConfigurationPackage(o UnstructuredWithMetadata) error {
    22  	pkg, err := toConfigurationPackageV1(o.Object)
    23  	if err != nil {
    24  		return err
    25  	}
    26  
    27  	// add step for disabling the dependency resolution
    28  	// for the configuration package
    29  	s := pg.stepConfiguration(stepConfigurationPackageDisableDepResolution)
    30  	p := fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(o.Object))
    31  	s.Patch.Files = append(s.Patch.Files, p)
    32  	if err := pg.target.Put(UnstructuredWithMetadata{
    33  		Object: unstructured.Unstructured{
    34  			Object: addNameGVK(o.Object, map[string]any{
    35  				"spec": map[string]any{
    36  					"skipDependencyResolution": true,
    37  				},
    38  			}),
    39  		},
    40  		Metadata: Metadata{
    41  			Path: p,
    42  		},
    43  	}); err != nil {
    44  		return err
    45  	}
    46  
    47  	// add step for enabling the dependency resolution
    48  	// for the configuration package
    49  	s = pg.stepConfiguration(stepConfigurationPackageEnableDepResolution)
    50  	p = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(o.Object))
    51  	s.Patch.Files = append(s.Patch.Files, p)
    52  	if err := pg.target.Put(UnstructuredWithMetadata{
    53  		Object: unstructured.Unstructured{
    54  			Object: addNameGVK(o.Object, map[string]any{
    55  				"spec": map[string]any{
    56  					"skipDependencyResolution": false,
    57  				},
    58  			}),
    59  		},
    60  		Metadata: Metadata{
    61  			Path: p,
    62  		},
    63  	}); err != nil {
    64  		return err
    65  	}
    66  
    67  	// add the step for editing the configuration package
    68  	for _, pkgConv := range pg.registry.configurationPackageConverters {
    69  		if pkgConv.re == nil || pkgConv.converter == nil || !pkgConv.re.MatchString(pkg.Spec.Package) {
    70  			continue
    71  		}
    72  		err := pkgConv.converter.ConfigurationPackageV1(pkg)
    73  		if err != nil {
    74  			return errors.Wrapf(err, "failed to call converter on Configuration package: %s", pkg.Spec.Package)
    75  		}
    76  		// TODO: if a converter only converts a specific version,
    77  		// (or does not convert the given configuration),
    78  		// we will have a false positive. Better to compute and check
    79  		// a diff here.
    80  		target := &UnstructuredWithMetadata{
    81  			Object:   ToSanitizedUnstructured(pkg),
    82  			Metadata: o.Metadata,
    83  		}
    84  		if err := pg.stepEditConfigurationPackage(o, target); err != nil {
    85  			return err
    86  		}
    87  	}
    88  	return nil
    89  }
    90  
    91  func (pg *PlanGenerator) stepEditConfigurationPackage(source UnstructuredWithMetadata, t *UnstructuredWithMetadata) error {
    92  	if !pg.stepEnabled(stepEditConfigurationPackage) {
    93  		return nil
    94  	}
    95  	s := pg.stepConfigurationWithSubStep(stepEditConfigurationPackage, true)
    96  	t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
    97  	s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
    98  	patchMap, err := computeJSONMergePathDoc(source.Object, t.Object)
    99  	if err != nil {
   100  		return err
   101  	}
   102  	return errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
   103  		Object: unstructured.Unstructured{
   104  			Object: addNameGVK(t.Object, patchMap),
   105  		},
   106  		Metadata: t.Metadata,
   107  	}), errEditConfigurationPackageFmt, t.Object.GetName())
   108  }
   109  
   110  func (pg *PlanGenerator) stepOrhanMR(u UnstructuredWithMetadata) (bool, error) {
   111  	return pg.stepSetDeletionPolicy(u, stepOrphanMRs, v1.DeletionOrphan, true)
   112  }
   113  
   114  func (pg *PlanGenerator) stepRevertOrhanMR(u UnstructuredWithMetadata) (bool, error) {
   115  	return pg.stepSetDeletionPolicy(u, stepRevertOrphanMRs, v1.DeletionDelete, false)
   116  }
   117  
   118  func (pg *PlanGenerator) stepSetDeletionPolicy(u UnstructuredWithMetadata, step step, policy v1.DeletionPolicy, checkCurrentPolicy bool) (bool, error) {
   119  	if !pg.stepEnabled(step) {
   120  		return false, nil
   121  	}
   122  	pv := fieldpath.Pave(u.Object.Object)
   123  	p, err := pv.GetString("spec.deletionPolicy")
   124  	if err != nil && !fieldpath.IsNotFound(err) {
   125  		return false, errors.Wrapf(err, "failed to get the current deletion policy from MR: %s", u.Object.GetName())
   126  	}
   127  	if checkCurrentPolicy && err == nil && v1.DeletionPolicy(p) == policy {
   128  		return false, nil
   129  	}
   130  	s := pg.stepConfiguration(step)
   131  	u.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(u.Object))
   132  	s.Patch.Files = append(s.Patch.Files, u.Metadata.Path)
   133  	return true, errors.Wrapf(pg.target.Put(UnstructuredWithMetadata{
   134  		Object: unstructured.Unstructured{
   135  			Object: addNameGVK(u.Object, map[string]any{
   136  				"spec": map[string]any{
   137  					"deletionPolicy": string(policy),
   138  				},
   139  			}),
   140  		},
   141  		Metadata: u.Metadata,
   142  	}), errSetDeletionPolicyFmt, policy, u.Object.GetName())
   143  }