Skip to content

Commit 7c4d149

Browse files
authored
refactor: remove flags & fixes (#2574)
1 parent 3d1c50e commit 7c4d149

File tree

14 files changed

+353
-148
lines changed

14 files changed

+353
-148
lines changed

cmd/vcluster/cmd/restore.go

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,33 @@ import (
1010
"io"
1111
"os"
1212
"path/filepath"
13+
"strings"
1314

1415
vclusterconfig "github.com/loft-sh/vcluster/config"
1516
"github.com/loft-sh/vcluster/pkg/config"
1617
"github.com/loft-sh/vcluster/pkg/constants"
1718
"github.com/loft-sh/vcluster/pkg/etcd"
19+
"github.com/loft-sh/vcluster/pkg/mappings/store"
20+
"github.com/loft-sh/vcluster/pkg/scheme"
1821
"github.com/loft-sh/vcluster/pkg/snapshot"
1922
"github.com/spf13/cobra"
23+
corev1 "k8s.io/api/core/v1"
24+
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/apimachinery/pkg/runtime/serializer"
26+
"k8s.io/apimachinery/pkg/runtime/serializer/protobuf"
2027
"k8s.io/klog/v2"
2128
)
2229

2330
type RestoreOptions struct {
2431
Snapshot snapshot.Options
32+
33+
NewVCluster bool
2534
}
2635

36+
var (
37+
podGVK = corev1.SchemeGroupVersion.WithKind("Pod")
38+
)
39+
2740
func NewRestoreCommand() *cobra.Command {
2841
options := &RestoreOptions{}
2942
envOptions, err := parseOptionsFromEnv()
@@ -42,12 +55,15 @@ func NewRestoreCommand() *cobra.Command {
4255
},
4356
}
4457

45-
// add storage flags
46-
snapshot.AddFlags(cmd.Flags(), &options.Snapshot)
58+
cmd.Flags().BoolVar(&options.NewVCluster, "new-vcluster", false, "Restore a new vCluster from snapshot instead of restoring into an existing vCluster")
4759
return cmd
4860
}
4961

5062
func (o *RestoreOptions) Run(ctx context.Context) error {
63+
// create decoder and encoder
64+
decoder := serializer.NewCodecFactory(scheme.Scheme).UniversalDeserializer()
65+
encoder := protobuf.NewSerializer(scheme.Scheme, scheme.Scheme)
66+
5167
// parse vCluster config
5268
vConfig, err := config.ParseConfig(constants.DefaultVClusterConfigLocation, os.Getenv("VCLUSTER_NAME"), nil)
5369
if err != nil {
@@ -67,7 +83,7 @@ func (o *RestoreOptions) Run(ctx context.Context) error {
6783
}
6884

6985
// create store
70-
objectStore, err := createStore(ctx, &o.Snapshot)
86+
objectStore, err := snapshot.CreateStore(ctx, &o.Snapshot)
7187
if err != nil {
7288
return fmt.Errorf("failed to create store: %w", err)
7389
}
@@ -103,6 +119,26 @@ func (o *RestoreOptions) Run(ctx context.Context) error {
103119
break
104120
}
105121

122+
// transform value if we are restoring to a new vCluster
123+
if o.NewVCluster {
124+
// skip mappings
125+
splitKey := strings.Split(string(key), "/")
126+
if strings.HasPrefix(string(key), store.MappingsPrefix) {
127+
continue
128+
} else if len(splitKey) == 5 && splitKey[2] == "configmaps" && splitKey[4] == "kube-root-ca.crt" {
129+
// we will get separate certificates, so we need to skip these
130+
continue
131+
}
132+
133+
// transform pods
134+
if strings.HasPrefix(string(key), "/registry/pods/") {
135+
value, err = transformPod(value, decoder, encoder)
136+
if err != nil {
137+
return fmt.Errorf("transform value: %w", err)
138+
}
139+
}
140+
}
141+
106142
// write the value to etcd
107143
klog.V(1).Infof("Restore key %s", string(key))
108144
err = etcdClient.Put(ctx, string(key), value)
@@ -122,6 +158,30 @@ func (o *RestoreOptions) Run(ctx context.Context) error {
122158
return nil
123159
}
124160

161+
func transformPod(value []byte, decoder runtime.Decoder, encoder runtime.Encoder) ([]byte, error) {
162+
// decode value
163+
obj := &corev1.Pod{}
164+
_, _, err := decoder.Decode(value, &podGVK, obj)
165+
if err != nil {
166+
return nil, fmt.Errorf("decode value: %w", err)
167+
} else if obj.DeletionTimestamp != nil {
168+
return value, nil
169+
}
170+
171+
// make sure to delete nodename & status or otherwise vCluster will delete the pod on start
172+
obj.Spec.NodeName = ""
173+
obj.Status = corev1.PodStatus{}
174+
175+
// encode value
176+
buf := &bytes.Buffer{}
177+
err = encoder.Encode(obj, buf)
178+
if err != nil {
179+
return nil, fmt.Errorf("encode value: %w", err)
180+
}
181+
182+
return buf.Bytes(), nil
183+
}
184+
125185
func newRestoreEtcdClient(ctx context.Context, vConfig *config.VirtualClusterConfig) (etcd.Client, error) {
126186
// delete existing storage:
127187
// * embedded etcd: just delete the files locally

cmd/vcluster/cmd/snapshot.go

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,13 @@ import (
2020
"github.com/loft-sh/vcluster/pkg/pro"
2121
"github.com/loft-sh/vcluster/pkg/setup"
2222
"github.com/loft-sh/vcluster/pkg/snapshot"
23-
"github.com/loft-sh/vcluster/pkg/snapshot/file"
24-
"github.com/loft-sh/vcluster/pkg/snapshot/oci"
25-
"github.com/loft-sh/vcluster/pkg/snapshot/s3"
2623
"github.com/loft-sh/vcluster/pkg/util/servicecidr"
2724
"github.com/spf13/cobra"
2825
"go.uber.org/zap"
2926
"google.golang.org/grpc/grpclog"
3027
"k8s.io/klog/v2"
3128
)
3229

33-
type Storage interface {
34-
Target() string
35-
PutObject(ctx context.Context, body io.Reader) error
36-
GetObject(ctx context.Context) (io.ReadCloser, error)
37-
}
38-
3930
type SnapshotOptions struct {
4031
Snapshot snapshot.Options
4132
}
@@ -58,8 +49,6 @@ func NewSnapshotCommand() *cobra.Command {
5849
},
5950
}
6051

61-
// add storage flags
62-
snapshot.AddFlags(cmd.Flags(), &options.Snapshot)
6352
return cmd
6453
}
6554

@@ -83,7 +72,7 @@ func (o *SnapshotOptions) Run(ctx context.Context) error {
8372
}
8473

8574
// create store
86-
objectStore, err := createStore(ctx, &o.Snapshot)
75+
objectStore, err := snapshot.CreateStore(ctx, &o.Snapshot)
8776
if err != nil {
8877
return fmt.Errorf("failed to create store: %w", err)
8978
}
@@ -99,7 +88,7 @@ func (o *SnapshotOptions) Run(ctx context.Context) error {
9988
return nil
10089
}
10190

102-
func (o *SnapshotOptions) writeSnapshot(ctx context.Context, etcdClient etcd.Client, objectStore Storage) error {
91+
func (o *SnapshotOptions) writeSnapshot(ctx context.Context, etcdClient etcd.Client, objectStore snapshot.Storage) error {
10392
// now stream objects from etcd to object store
10493
errChan := make(chan error)
10594
reader, writer, err := os.Pipe()
@@ -123,6 +112,19 @@ func (o *SnapshotOptions) writeSnapshot(ctx context.Context, etcdClient etcd.Cli
123112
tarWriter := tar.NewWriter(gzipWriter)
124113
defer tarWriter.Close()
125114

115+
// write the vCluster config as first thing
116+
if o.Snapshot.Release != nil {
117+
releaseBytes, err := json.Marshal(o.Snapshot.Release)
118+
if err != nil {
119+
return fmt.Errorf("failed to marshal vCluster release: %w", err)
120+
}
121+
122+
err = writeKeyValue(tarWriter, []byte(snapshot.SnapshotReleaseKey), releaseBytes)
123+
if err != nil {
124+
return fmt.Errorf("failed to snapshot vCluster release: %w", err)
125+
}
126+
}
127+
126128
// now write the snapshot
127129
backedUpKeys := 0
128130
for {
@@ -359,24 +361,6 @@ func generateCertificates(ctx context.Context, vConfig *config.VirtualClusterCon
359361
return certificatesDir, nil
360362
}
361363

362-
func createStore(ctx context.Context, options *snapshot.Options) (Storage, error) {
363-
if options.Type == "s3" {
364-
objectStore := s3.NewStore(klog.FromContext(ctx))
365-
err := objectStore.Init(&options.S3)
366-
if err != nil {
367-
return nil, fmt.Errorf("failed to init s3 object store: %w", err)
368-
}
369-
370-
return objectStore, nil
371-
} else if options.Type == "file" {
372-
return file.NewStore(&options.File), nil
373-
} else if options.Type == "oci" {
374-
return oci.NewStore(&options.OCI), nil
375-
}
376-
377-
return nil, fmt.Errorf("unknown storage: %s", options.Type)
378-
}
379-
380364
func writeKeyValue(tarWriter *tar.Writer, key, value []byte) error {
381365
err := tarWriter.WriteHeader(&tar.Header{
382366
Typeflag: tar.TypeReg,

cmd/vclusterctl/cmd/restore.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,18 @@ Example:
4141
vcluster restore my-vcluster oci://ghcr.io/my-user/my-repo:my-tag
4242
# Restore from s3 bucket
4343
vcluster restore my-vcluster s3://my-bucket/my-bucket-key
44-
# Restore from vCluster pvc
45-
vcluster restore my-vcluster file:///data/my-local-snapshot.tar.gz
44+
# Restore from vCluster container filesystem
45+
vcluster restore my-vcluster container:///data/my-local-snapshot.tar.gz
4646
#######################################################
4747
`,
4848
Args: nameValidator,
4949
ValidArgsFunction: completion.NewValidVClusterNameFunc(globalFlags),
5050
RunE: func(cobraCmd *cobra.Command, args []string) error {
51-
return cli.Restore(cobraCmd.Context(), args, cmd.GlobalFlags, &cmd.Snapshot, &cmd.Pod, cmd.Log)
51+
return cli.Restore(cobraCmd.Context(), args, cmd.GlobalFlags, &cmd.Snapshot, &cmd.Pod, false, cmd.Log)
5252
},
5353
}
5454

5555
// add storage flags
56-
snapshot.AddFlags(cobraCmd.Flags(), &cmd.Snapshot)
5756
pod.AddFlags(cobraCmd.Flags(), &cmd.Pod, true)
5857
return cobraCmd
5958
}

cmd/vclusterctl/cmd/snapshot.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ Example:
4141
vcluster snapshot my-vcluster oci://ghcr.io/my-user/my-repo:my-tag
4242
# Snapshot to s3 bucket
4343
vcluster snapshot my-vcluster s3://my-bucket/my-bucket-key
44-
# Snapshot to vCluster pvc
45-
vcluster snapshot my-vcluster file:///data/my-local-snapshot.tar.gz
44+
# Snapshot to vCluster container filesystem
45+
vcluster snapshot my-vcluster container:///data/my-local-snapshot.tar.gz
4646
#######################################################
4747
`,
4848
Args: nameValidator,
@@ -53,7 +53,6 @@ vcluster snapshot my-vcluster file:///data/my-local-snapshot.tar.gz
5353
}
5454

5555
// add storage flags
56-
snapshot.AddFlags(cobraCmd.Flags(), &cmd.Snapshot)
5756
pod.AddFlags(cobraCmd.Flags(), &cmd.Pod, false)
5857
return cobraCmd
5958
}

0 commit comments

Comments
 (0)