github.com/crossplane/upjet@v1.3.0/pkg/migration/provider_package_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  	"strings"
    10  
    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  	errPutSSOPPackageFmt = "failed to put the SSOP package: %s"
    18  	errActivateSSOP      = "failed to put the activated SSOP package: %s"
    19  )
    20  
    21  func (pg *PlanGenerator) convertProviderPackage(o UnstructuredWithMetadata) (bool, error) { //nolint:gocyclo
    22  	pkg, err := toProviderPackage(o.Object)
    23  	if err != nil {
    24  		return false, err
    25  	}
    26  	isConverted := false
    27  	for _, pkgConv := range pg.registry.providerPackageConverters {
    28  		if pkgConv.re == nil || pkgConv.converter == nil || !pkgConv.re.MatchString(pkg.Spec.Package) {
    29  			continue
    30  		}
    31  		targetPkgs, err := pkgConv.converter.ProviderPackageV1(*pkg)
    32  		if err != nil {
    33  			return false, errors.Wrapf(err, "failed to call converter on Provider package: %s", pkg.Spec.Package)
    34  		}
    35  		if len(targetPkgs) == 0 {
    36  			continue
    37  		}
    38  		// TODO: if a configuration converter only converts a specific version,
    39  		// (or does not convert the given configuration),
    40  		// we will have a false positive. Better to compute and check
    41  		// a diff here.
    42  		isConverted = true
    43  		converted := make([]*UnstructuredWithMetadata, 0, len(targetPkgs))
    44  		for _, p := range targetPkgs {
    45  			p := p
    46  			converted = append(converted, &UnstructuredWithMetadata{
    47  				Object:   ToSanitizedUnstructured(&p),
    48  				Metadata: o.Metadata,
    49  			})
    50  		}
    51  		if err := pg.stepNewSSOPs(o, converted); err != nil {
    52  			return false, err
    53  		}
    54  		if err := pg.stepActivateSSOPs(converted); err != nil {
    55  			return false, err
    56  		}
    57  		if err := pg.stepCheckHealthOfNewProvider(o, converted); err != nil {
    58  			return false, err
    59  		}
    60  		if err := pg.stepCheckInstallationOfNewProvider(o, converted); err != nil {
    61  			return false, err
    62  		}
    63  	}
    64  	return isConverted, nil
    65  }
    66  
    67  func (pg *PlanGenerator) stepDeleteMonolith(source UnstructuredWithMetadata) error {
    68  	// delete the monolithic provider package
    69  	s := pg.stepConfigurationWithSubStep(stepDeleteMonolithicProvider, true)
    70  	source.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(source.Object))
    71  	s.Delete.Resources = []Resource{
    72  		{
    73  			GroupVersionKind: FromGroupVersionKind(source.Object.GroupVersionKind()),
    74  			Name:             source.Object.GetName(),
    75  		},
    76  	}
    77  	return nil
    78  }
    79  
    80  // add steps for the new SSOPs
    81  func (pg *PlanGenerator) stepNewSSOPs(source UnstructuredWithMetadata, targets []*UnstructuredWithMetadata) error {
    82  	var s *Step
    83  	isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
    84  	if err != nil {
    85  		return errors.Wrapf(err, "could not decide whether the provider family config")
    86  	}
    87  	if isFamilyConfig {
    88  		s = pg.stepConfigurationWithSubStep(stepNewFamilyProvider, true)
    89  	} else {
    90  		s = pg.stepConfigurationWithSubStep(stepNewServiceScopedProvider, true)
    91  	}
    92  	for _, t := range targets {
    93  		t.Object.Object = addGVK(source.Object, t.Object.Object)
    94  		t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
    95  		s.Apply.Files = append(s.Apply.Files, t.Metadata.Path)
    96  		if err := pg.target.Put(*t); err != nil {
    97  			return errors.Wrapf(err, errPutSSOPPackageFmt, t.Metadata.Path)
    98  		}
    99  	}
   100  	return nil
   101  }
   102  
   103  // add steps for activating SSOPs
   104  func (pg *PlanGenerator) stepActivateSSOPs(targets []*UnstructuredWithMetadata) error {
   105  	var s *Step
   106  	isFamilyConfig, err := checkContainsFamilyConfigProvider(targets)
   107  	if err != nil {
   108  		return errors.Wrapf(err, "could not decide whether the provider family config")
   109  	}
   110  	if isFamilyConfig {
   111  		s = pg.stepConfigurationWithSubStep(stepActivateFamilyProviderRevision, true)
   112  	} else {
   113  		s = pg.stepConfigurationWithSubStep(stepActivateServiceScopedProviderRevision, true)
   114  	}
   115  	for _, t := range targets {
   116  		t.Metadata.Path = fmt.Sprintf("%s/%s.yaml", s.Name, getVersionedName(t.Object))
   117  		s.Patch.Files = append(s.Patch.Files, t.Metadata.Path)
   118  		if err := pg.target.Put(UnstructuredWithMetadata{
   119  			Object: unstructured.Unstructured{
   120  				Object: addNameGVK(t.Object, map[string]any{
   121  					"spec": map[string]any{
   122  						"revisionActivationPolicy": "Automatic",
   123  					},
   124  				}),
   125  			},
   126  			Metadata: t.Metadata,
   127  		}); err != nil {
   128  			return errors.Wrapf(err, errActivateSSOP, t.Metadata.Path)
   129  		}
   130  	}
   131  	return nil
   132  }
   133  
   134  func checkContainsFamilyConfigProvider(targets []*UnstructuredWithMetadata) (bool, error) {
   135  	for _, t := range targets {
   136  		paved := fieldpath.Pave(t.Object.Object)
   137  		pkg, err := paved.GetString("spec.package")
   138  		if err != nil {
   139  			return false, errors.Wrap(err, "could not get package of provider")
   140  		}
   141  		if strings.Contains(pkg, "provider-family") {
   142  			return true, nil
   143  		}
   144  	}
   145  	return false, nil
   146  }