15
15
package etcdutl
16
16
17
17
import (
18
- "errors"
19
18
"fmt"
20
19
"strings"
21
20
@@ -25,12 +24,10 @@ import (
25
24
26
25
"go.etcd.io/etcd/api/v3/version"
27
26
"go.etcd.io/etcd/pkg/v3/cobrautl"
28
- "go.etcd.io/etcd/server/v3/etcdserver/api/snap"
29
27
"go.etcd.io/etcd/server/v3/storage/backend"
30
28
"go.etcd.io/etcd/server/v3/storage/datadir"
31
29
"go.etcd.io/etcd/server/v3/storage/schema"
32
30
"go.etcd.io/etcd/server/v3/storage/wal"
33
- "go.etcd.io/etcd/server/v3/storage/wal/walpb"
34
31
)
35
32
36
33
// NewMigrateCommand prints out the version of etcd.
@@ -77,8 +74,9 @@ func (o *migrateOptions) AddFlags(cmd *cobra.Command) {
77
74
78
75
func (o * migrateOptions ) Config () (* migrateConfig , error ) {
79
76
c := & migrateConfig {
80
- force : o .force ,
81
- lg : GetLogger (),
77
+ force : o .force ,
78
+ dataDir : o .dataDir ,
79
+ lg : GetLogger (),
82
80
}
83
81
var err error
84
82
dotCount := strings .Count (o .targetVersion , "." )
@@ -93,67 +91,69 @@ func (o *migrateOptions) Config() (*migrateConfig, error) {
93
91
return nil , fmt .Errorf (`target version %q not supported. Minimal "3.5"` , storageVersionToString (c .targetVersion ))
94
92
}
95
93
96
- dbPath := datadir . ToBackendFileName ( o . dataDir )
97
- c . be = backend . NewDefaultBackend ( GetLogger (), dbPath )
94
+ return c , nil
95
+ }
98
96
99
- walPath := datadir .ToWALDir (o .dataDir )
100
- walSnap , err := getLatestWALSnap (c .lg , o .dataDir )
97
+ type migrateConfig struct {
98
+ lg * zap.Logger
99
+ be backend.Backend
100
+ targetVersion * semver.Version
101
+ walVersion schema.WALVersion
102
+ dataDir string
103
+ force bool
104
+ }
105
+
106
+ func (c * migrateConfig ) finalize () error {
107
+ walPath := datadir .ToWALDir (c .dataDir )
108
+ walSnap , err := getLatestWALSnap (c .lg , c .dataDir )
101
109
if err != nil {
102
- return nil , fmt .Errorf ("failed to get the lastest snapshot: %w" , err )
110
+ return fmt .Errorf ("failed to get the lastest snapshot: %w" , err )
103
111
}
104
112
w , err := wal .OpenForRead (c .lg , walPath , walSnap )
105
113
if err != nil {
106
- return nil , fmt .Errorf (`failed to open wal: %w` , err )
114
+ return fmt .Errorf (`failed to open wal: %w` , err )
107
115
}
108
116
defer w .Close ()
109
117
c .walVersion , err = wal .ReadWALVersion (w )
110
118
if err != nil {
111
- return nil , fmt .Errorf (`failed to read wal: %w` , err )
112
- }
113
-
114
- return c , nil
115
- }
116
-
117
- func getLatestWALSnap (lg * zap.Logger , dataDir string ) (walpb.Snapshot , error ) {
118
- walPath := datadir .ToWALDir (dataDir )
119
- walSnaps , err := wal .ValidSnapshotEntries (lg , walPath )
120
- if err != nil {
121
- return walpb.Snapshot {}, err
122
- }
123
-
124
- ss := snap .New (lg , datadir .ToSnapDir (dataDir ))
125
- snapshot , err := ss .LoadNewestAvailable (walSnaps )
126
- if err != nil && ! errors .Is (err , snap .ErrNoSnapshot ) {
127
- return walpb.Snapshot {}, err
128
- }
129
-
130
- var walsnap walpb.Snapshot
131
- if snapshot != nil {
132
- walsnap .Index , walsnap .Term = snapshot .Metadata .Index , snapshot .Metadata .Term
119
+ return fmt .Errorf (`failed to read wal: %w` , err )
133
120
}
134
- return walsnap , nil
135
- }
136
121
137
- type migrateConfig struct {
138
- lg * zap.Logger
139
- be backend.Backend
140
- targetVersion * semver.Version
141
- walVersion schema.WALVersion
142
- force bool
122
+ return nil
143
123
}
144
124
145
125
func migrateCommandFunc (c * migrateConfig ) error {
126
+ dbPath := datadir .ToBackendFileName (c .dataDir )
127
+ c .be = backend .NewDefaultBackend (GetLogger (), dbPath )
146
128
defer c .be .Close ()
129
+
147
130
tx := c .be .BatchTx ()
148
131
current , err := schema .DetectSchemaVersion (c .lg , c .be .ReadTx ())
149
132
if err != nil {
150
- c .lg .Error ("failed to detect storage version. Please make sure you are using data dir from etcd v3.5 and older" )
133
+ c .lg .Error ("failed to detect storage version. Please make sure you are using data dir from etcd v3.5 and older" , zap . Error ( err ) )
151
134
return err
152
135
}
153
136
if current == * c .targetVersion {
154
137
c .lg .Info ("storage version up-to-date" , zap .String ("storage-version" , storageVersionToString (& current )))
155
138
return nil
156
139
}
140
+
141
+ // Update cluster version
142
+ be := schema .NewMembershipBackend (c .lg , c .be )
143
+ be .MustSaveClusterVersionToBackend (c .targetVersion )
144
+
145
+ // forcibly create a v2 snapshot file
146
+ // TODO: remove in 3.8
147
+ if err = createV2SnapshotFromV3Store (c .dataDir , c .be ); err != nil {
148
+ c .lg .Error ("Failed to create v2 snapshot file" , zap .Error (err ))
149
+ return err
150
+ }
151
+
152
+ if err = c .finalize (); err != nil {
153
+ c .lg .Error ("Failed to finalize config" , zap .Error (err ))
154
+ return err
155
+ }
156
+
157
157
err = schema .Migrate (c .lg , tx , c .walVersion , * c .targetVersion )
158
158
if err != nil {
159
159
if ! c .force {
@@ -162,7 +162,9 @@ func migrateCommandFunc(c *migrateConfig) error {
162
162
c .lg .Info ("normal migrate failed, trying with force" , zap .Error (err ))
163
163
migrateForce (c .lg , tx , c .targetVersion )
164
164
}
165
+
165
166
c .be .ForceCommit ()
167
+
166
168
return nil
167
169
}
168
170
0 commit comments