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 }