Skip to content

Commit 4accd37

Browse files
authored
Merge pull request #5559 from fluxcd/backport-5558-to-release/v2.7.x
[release/v2.7.x] Improve `flux migrate` for live cluster migrations
2 parents 784a62c + 742baa6 commit 4accd37

File tree

3 files changed

+60
-39
lines changed

3 files changed

+60
-39
lines changed

cmd/flux/migrate.go

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,21 @@ package main
1818

1919
import (
2020
"context"
21+
"encoding/json"
2122
"fmt"
2223
"io/fs"
2324
"os"
2425
"path/filepath"
2526
"strings"
2627

28+
"github.com/fluxcd/pkg/ssa"
2729
"github.com/manifoldco/promptui"
2830
"github.com/spf13/cobra"
2931
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
3032
apierrors "k8s.io/apimachinery/pkg/api/errors"
3133
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3234
"k8s.io/apimachinery/pkg/runtime/schema"
35+
"k8s.io/apimachinery/pkg/types"
3336
"k8s.io/client-go/util/retry"
3437
"sigs.k8s.io/controller-runtime/pkg/client"
3538

@@ -54,6 +57,7 @@ type APIVersions struct {
5457
LatestVersions map[schema.GroupKind]string
5558
}
5659

60+
// TODO: Update this mapping when new Flux minor versions are released!
5761
// latestAPIVersions contains the latest API versions for each GroupKind
5862
// for each supported Flux version. We maintain the latest two minor versions.
5963
var latestAPIVersions = []APIVersions{
@@ -132,35 +136,29 @@ The command has two modes of operation:
132136
133137
- Cluster mode (default): migrates all the Flux custom resources stored in Kubernetes etcd to their latest API version.
134138
- File system mode (-f): migrates the Flux custom resources defined in the manifests located in the specified path.
135-
136-
Examples:
137-
138-
# Migrate all the Flux custom resources in the cluster.
139+
`,
140+
Example: ` # Migrate all the Flux custom resources in the cluster.
141+
# This uses the current kubeconfig context and requires cluster-admin permissions.
139142
flux migrate
140143
141-
# Migrate all manifests in a Git repository.
144+
# Migrate all the Flux custom resources in a Git repository
145+
# checked out in the current working directory.
142146
flux migrate -f .
143147
144-
# Migrate the Flux custom resources defined in the manifests located in the ./manifest.yaml file.
145-
flux migrate --path=./manifest.yaml
146-
147-
# Migrate the Flux custom resources defined in the manifests located in the ./manifests directory.
148-
flux migrate --path=./manifests
148+
# Migrate all Flux custom resources defined in YAML and Helm YAML template files.
149+
flux migrate -f . --extensions=.yml,.yaml,.tpl
149150
150-
# Migrate the Flux custom resources defined in the manifests located in the ./manifests directory
151-
# skipping confirmation prompts.
152-
flux migrate --path=./manifests --yes
151+
# Migrate the Flux custom resources to the latest API versions of Flux 2.6.
152+
flux migrate -f . --version=2.6
153153
154-
# Simulate the migration process without making any changes, only applicable with --path.
155-
flux migrate --path=./manifests --dry-run
154+
# Migrate the Flux custom resources defined in a multi-document YAML manifest file.
155+
flux migrate -f path/to/manifest.yaml
156156
157-
# Migrate the Flux custom resources defined in the manifests located in the ./manifests directory
158-
# considering YAML and Helm YAML template files.
159-
flux migrate --path=./manifests --extensions=.yml --extensions=.yaml --extensions=.tpl
157+
# Simulate the migration without making any changes.
158+
flux migrate -f . --dry-run
160159
161-
# Migrate the Flux custom resources defined in the manifests located in the ./manifests directory
162-
# for Flux 2.6. This will migrate the custom resources to their latest API versions in Flux 2.6.
163-
flux migrate --path=./manifests --version=2.6
160+
# Run the migration by skipping confirmation prompts.
161+
flux migrate -f . --yes
164162
`,
165163
RunE: runMigrateCmd,
166164
}
@@ -176,16 +174,16 @@ var migrateFlags struct {
176174
func init() {
177175
rootCmd.AddCommand(migrateCmd)
178176

179-
migrateCmd.Flags().BoolVarP(&migrateFlags.yes, "yes", "y", false,
180-
"skip confirmation prompts")
181-
migrateCmd.Flags().BoolVar(&migrateFlags.dryRun, "dry-run", false,
182-
"simulate the migration process without making any changes, only applicable with --path")
183177
migrateCmd.Flags().StringVarP(&migrateFlags.path, "path", "f", "",
184178
"the path to the directory containing the manifests to migrate")
185-
migrateCmd.Flags().StringArrayVarP(&migrateFlags.extensions, "extensions", "e", []string{".yaml", ".yml"},
186-
"the file extensions to consider when migrating manifests from the filesystem (only used with --path)")
179+
migrateCmd.Flags().StringSliceVarP(&migrateFlags.extensions, "extensions", "e", []string{".yaml", ".yml"},
180+
"the file extensions to consider when migrating manifests, only applicable --path")
187181
migrateCmd.Flags().StringVarP(&migrateFlags.version, "version", "v", "",
188-
"the target Flux version to migrate custom resource API versions to (defaults to the version of the CLI)")
182+
"the target Flux minor version to migrate manifests to, only applicable with --path (defaults to the version of the CLI)")
183+
migrateCmd.Flags().BoolVarP(&migrateFlags.yes, "yes", "y", false,
184+
"skip confirmation prompts when migrating manifests, only applicable with --path")
185+
migrateCmd.Flags().BoolVar(&migrateFlags.dryRun, "dry-run", false,
186+
"simulate the migration of manifests without making any changes, only applicable with --path")
189187
}
190188

191189
func runMigrateCmd(*cobra.Command, []string) error {
@@ -319,7 +317,7 @@ func (c *ClusterMigrator) migrateCRD(ctx context.Context, name string) error {
319317
return nil
320318
}
321319

322-
// migrateCR migrates all CRs for the given CRD to the specified version by patching them with an empty patch.
320+
// migrateCR migrates all CRs for the given CRD to the specified version by patching them.
323321
func (c *ClusterMigrator) migrateCR(ctx context.Context, crd *apiextensionsv1.CustomResourceDefinition, version string) error {
324322
list := &unstructured.UnstructuredList{}
325323

@@ -339,16 +337,39 @@ func (c *ClusterMigrator) migrateCR(ctx context.Context, crd *apiextensionsv1.Cu
339337
}
340338

341339
for _, item := range list.Items {
342-
// patch the resource with an empty patch to update the version
343-
if err := c.kubeClient.Patch(
344-
ctx,
345-
&item,
346-
client.RawPatch(client.Merge.Type(), []byte("{}")),
347-
); err != nil && !apierrors.IsNotFound(err) {
348-
return fmt.Errorf(" %s/%s/%s failed to migrate: %w",
340+
patches, err := ssa.PatchMigrateToVersion(&item, apiVersion)
341+
if err != nil {
342+
return fmt.Errorf("failed to create migration patch for %s/%s/%s: %w",
349343
item.GetKind(), item.GetNamespace(), item.GetName(), err)
350344
}
351345

346+
if len(patches) == 0 {
347+
// patch the resource with an empty patch to update the version
348+
if err := c.kubeClient.Patch(
349+
ctx,
350+
&item,
351+
client.RawPatch(client.Merge.Type(), []byte("{}")),
352+
); err != nil && !apierrors.IsNotFound(err) {
353+
return fmt.Errorf(" %s/%s/%s failed to migrate: %w",
354+
item.GetKind(), item.GetNamespace(), item.GetName(), err)
355+
}
356+
} else {
357+
// patch the resource to migrate the managed fields to the latest apiVersion
358+
rawPatch, err := json.Marshal(patches)
359+
if err != nil {
360+
return fmt.Errorf("failed to marshal migration patch for %s/%s/%s: %w",
361+
item.GetKind(), item.GetNamespace(), item.GetName(), err)
362+
}
363+
if err := c.kubeClient.Patch(
364+
ctx,
365+
&item,
366+
client.RawPatch(types.JSONPatchType, rawPatch),
367+
); err != nil && !apierrors.IsNotFound(err) {
368+
return fmt.Errorf(" %s/%s/%s failed to migrate managed fields: %w",
369+
item.GetKind(), item.GetNamespace(), item.GetName(), err)
370+
}
371+
}
372+
352373
logger.Successf("%s/%s/%s migrated to version %s",
353374
item.GetKind(), item.GetNamespace(), item.GetName(), version)
354375
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ require (
2828
github.com/fluxcd/pkg/oci v0.56.0
2929
github.com/fluxcd/pkg/runtime v0.86.0
3030
github.com/fluxcd/pkg/sourceignore v0.14.0
31-
github.com/fluxcd/pkg/ssa v0.58.0
31+
github.com/fluxcd/pkg/ssa v0.59.0
3232
github.com/fluxcd/pkg/ssh v0.21.0
3333
github.com/fluxcd/pkg/tar v0.14.0
3434
github.com/fluxcd/pkg/version v0.10.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ github.com/fluxcd/pkg/runtime v0.86.0 h1:q7aBSerJwt0N9hpurPVElG+HWpVhZcs6t96bcNQ
214214
github.com/fluxcd/pkg/runtime v0.86.0/go.mod h1:Wt9mUzQgMPQMu2D/wKl5pG4zh5vu/tfF5wq9pPobxOQ=
215215
github.com/fluxcd/pkg/sourceignore v0.14.0 h1:ZiZzbXtXb/Qp7I7JCStsxOlX8ri8rWwCvmvIrJ0UzQQ=
216216
github.com/fluxcd/pkg/sourceignore v0.14.0/go.mod h1:E3zKvyTyB+oQKqm/2I/jS6Rrt3B7fNuig/4bY2vi3bg=
217-
github.com/fluxcd/pkg/ssa v0.58.0 h1:W7m2LQFsZxPN9nn3lfGVDwXsZnIgCWWJ/+/K5hpzW+k=
218-
github.com/fluxcd/pkg/ssa v0.58.0/go.mod h1:iN/QDMqdJaVXKkqwbXqGa4PyWQwtyIy2WkeM2+9kfXA=
217+
github.com/fluxcd/pkg/ssa v0.59.0 h1:c88Q5w9e0MgrEi3Z7/+FWEVvtJFaVHfA9sxreMJUR7g=
218+
github.com/fluxcd/pkg/ssa v0.59.0/go.mod h1:iN/QDMqdJaVXKkqwbXqGa4PyWQwtyIy2WkeM2+9kfXA=
219219
github.com/fluxcd/pkg/ssh v0.21.0 h1:ZmyF0n9je0cTTkOpvFVgIhmdx9qtswnVE60TK4IzJh0=
220220
github.com/fluxcd/pkg/ssh v0.21.0/go.mod h1:nX+gvJOmjf0E7lxq5mKKzDIdPEL2jOUQZbkBMS+mDtk=
221221
github.com/fluxcd/pkg/tar v0.14.0 h1:9Gku8FIvPt2bixKldZnzXJ/t+7SloxePlzyVGOK8GVQ=

0 commit comments

Comments
 (0)