Skip to content

Commit b8d3022

Browse files
authored
Merge pull request #102 from ipfs/feat/9-10
feat: migration 9 to 10
2 parents 369e382 + 95414ba commit b8d3022

File tree

6 files changed

+437
-0
lines changed

6 files changed

+437
-0
lines changed

ipfs-9-to-10/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package main
2+
3+
import (
4+
migrate "github.com/ipfs/fs-repo-migrations/go-migrate"
5+
mg9 "github.com/ipfs/fs-repo-migrations/ipfs-9-to-10/migration"
6+
)
7+
8+
func main() {
9+
m := mg9.Migration{}
10+
migrate.Main(&m)
11+
}
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
package mg9
2+
3+
import (
4+
"encoding/json"
5+
"io"
6+
"io/ioutil"
7+
"os"
8+
"regexp"
9+
"strings"
10+
11+
"github.com/ipfs/fs-repo-migrations/ipfs-6-to-7/gx/ipfs/QmdYwCmx8pZRkzdcd8MhmLJqYVoVTC1aGsy5Q4reMGLNLg/atomicfile"
12+
log "github.com/ipfs/fs-repo-migrations/stump"
13+
)
14+
15+
var (
16+
ip4BootstrapAddr = "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
17+
quicBootstrapAddr = "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
18+
)
19+
20+
// convArray does an inplace conversion of an array of strings
21+
// configuration from one version to another
22+
type convArray func([]string) []string
23+
24+
// convAddrs does an inplace conversion of the swarm, announce
25+
// and noAnnounce arrays of strings from one version to another
26+
type convAddrs func([]string, []string, []string) ([]string, []string, []string)
27+
28+
// convertFile converts a config file from one version to another
29+
func convertFile(path string, convBootstrap convArray, convAddresses convAddrs) error {
30+
in, err := os.Open(path)
31+
if err != nil {
32+
return err
33+
}
34+
35+
// Create a temp file to write the output to on success
36+
out, err := atomicfile.New(path, 0600)
37+
if err != nil {
38+
in.Close()
39+
return err
40+
}
41+
42+
err = convert(in, out, convBootstrap, convAddresses)
43+
44+
in.Close()
45+
46+
if err != nil {
47+
// There was an error so abort writing the output and clean up temp file
48+
out.Abort()
49+
} else {
50+
// Write the output and clean up temp file
51+
out.Close()
52+
}
53+
54+
return err
55+
}
56+
57+
// convert converts the config from one version to another
58+
func convert(in io.Reader, out io.Writer, convBootstrap convArray, convAddresses convAddrs) error {
59+
data, err := ioutil.ReadAll(in)
60+
if err != nil {
61+
return err
62+
}
63+
confMap := make(map[string]interface{})
64+
if err = json.Unmarshal(data, &confMap); err != nil {
65+
return err
66+
}
67+
68+
// Convert bootstrap config
69+
convertBootstrap(confMap, convBootstrap)
70+
71+
// Convert addresses config
72+
convertAddresses(confMap, convAddresses)
73+
74+
fixed, err := json.MarshalIndent(confMap, "", " ")
75+
if err != nil {
76+
return err
77+
}
78+
79+
if _, err := out.Write(fixed); err != nil {
80+
return err
81+
}
82+
_, err = out.Write([]byte("\n"))
83+
return err
84+
}
85+
86+
// Convert Bootstrap addresses to/from QUIC
87+
func convertBootstrap(confMap map[string]interface{}, conv convArray) {
88+
bootstrapi, _ := confMap["Bootstrap"].([]interface{})
89+
if bootstrapi == nil {
90+
log.Log("No Bootstrap field in config, skipping")
91+
return
92+
}
93+
confMap["Bootstrap"] = conv(toStringArray(bootstrapi))
94+
}
95+
96+
// Convert Addresses.Swarm, Addresses.Announce, Addresses.NoAnnounce to/from QUIC
97+
func convertAddresses(confMap map[string]interface{}, conv convAddrs) {
98+
addressesi, _ := confMap["Addresses"].(map[string]interface{})
99+
if addressesi == nil {
100+
log.Log("Addresses field missing or of the wrong type")
101+
return
102+
}
103+
104+
swarm := toStringArray(addressesi["Swarm"])
105+
announce := toStringArray(addressesi["Announce"])
106+
noAnnounce := toStringArray(addressesi["NoAnnounce"])
107+
108+
s, a, na := conv(swarm, announce, noAnnounce)
109+
addressesi["Swarm"] = s
110+
addressesi["Announce"] = a
111+
addressesi["NoAnnounce"] = na
112+
}
113+
114+
func toStringArray(el interface{}) []string {
115+
listi, _ := el.([]interface{})
116+
if listi == nil {
117+
return []string{}
118+
}
119+
120+
list := make([]string, len(listi))
121+
for i := range listi {
122+
list[i] = listi[i].(string)
123+
}
124+
return list
125+
}
126+
127+
// Add QUIC Bootstrap address
128+
func ver9to10Bootstrap(bootstrap []string) []string {
129+
hasOld := false
130+
hasNew := false
131+
res := make([]string, 0, len(bootstrap)+1)
132+
for _, addr := range bootstrap {
133+
res = append(res, addr)
134+
if addr == ip4BootstrapAddr {
135+
hasOld = true
136+
} else if addr == quicBootstrapAddr {
137+
hasNew = true
138+
}
139+
}
140+
141+
// If the config has the old IP v4 bootstrapper, add the new QUIC
142+
// bootstrapper
143+
if hasOld && !hasNew {
144+
res = append(res, quicBootstrapAddr)
145+
}
146+
147+
return res
148+
}
149+
150+
// For each TCP address, add a QUIC address
151+
func ver9to10Addresses(swarm, announce, noAnnounce []string) ([]string, []string, []string) {
152+
for _, addr := range append(swarm, append(announce, noAnnounce...)...) {
153+
// If the old configuration already has a quic address in it, assume
154+
// the user has already set up their addresses for quic and leave
155+
// things as they are
156+
if strings.Contains(addr, "/udp/quic") {
157+
return swarm, announce, noAnnounce
158+
}
159+
}
160+
161+
return addQuic(swarm), addQuic(announce), addQuic(noAnnounce)
162+
}
163+
164+
var tcpRegexp = regexp.MustCompile(`/tcp/([0-9]+)`)
165+
166+
func addQuic(addrs []string) []string {
167+
res := make([]string, 0, len(addrs)*2)
168+
for _, addr := range addrs {
169+
res = append(res, addr)
170+
}
171+
172+
// For each tcp address, add a corresponding quic address
173+
for _, addr := range addrs {
174+
if tcpRegexp.MatchString(addr) {
175+
res = append(res, tcpRegexp.ReplaceAllString(addr, `/udp/$1/quic`))
176+
}
177+
}
178+
179+
return res
180+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
package mg9
2+
3+
import (
4+
"bytes"
5+
"regexp"
6+
"strings"
7+
"testing"
8+
)
9+
10+
var config = `{
11+
"Addresses": {
12+
"Announce": [
13+
"/ip4/1.2.3.4/tcp/1"
14+
],
15+
"NoAnnounce": [
16+
"/ip4/5.6.7.8/tcp/2"
17+
],
18+
"Swarm": [
19+
"/ip4/0.0.0.0/tcp/0",
20+
"/ip4/1.2.3.4/tcp/1",
21+
"/ip4/5.6.7.8/tcp/2"
22+
]
23+
},
24+
"Bootstrap": [
25+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
26+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
27+
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
28+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
29+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa"
30+
]
31+
}`
32+
33+
var expForwardConfig = `{
34+
"Addresses": {
35+
"Announce": [
36+
"/ip4/1.2.3.4/tcp/1",
37+
"/ip4/1.2.3.4/udp/1/quic"
38+
],
39+
"NoAnnounce": [
40+
"/ip4/5.6.7.8/tcp/2",
41+
"/ip4/5.6.7.8/udp/2/quic"
42+
],
43+
"Swarm": [
44+
"/ip4/0.0.0.0/tcp/0",
45+
"/ip4/1.2.3.4/tcp/1",
46+
"/ip4/5.6.7.8/tcp/2",
47+
"/ip4/0.0.0.0/udp/0/quic",
48+
"/ip4/1.2.3.4/udp/1/quic",
49+
"/ip4/5.6.7.8/udp/2/quic"
50+
]
51+
},
52+
"Bootstrap": [
53+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
54+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
55+
"/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
56+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
57+
"/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
58+
"/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ"
59+
]
60+
}`
61+
62+
func TestConversion(t *testing.T) {
63+
conf9to10 := new(bytes.Buffer)
64+
err := convert(strings.NewReader(config), conf9to10, ver9to10Bootstrap, ver9to10Addresses)
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
69+
forward := conf9to10.String()
70+
if noSpace(forward) != noSpace(expForwardConfig) {
71+
t.Fatalf("Mismatch\nConversion produced:\n%s\nExpected:\n%s\n", forward, expForwardConfig)
72+
}
73+
}
74+
75+
var whitespaceRe = regexp.MustCompile(`\s`)
76+
77+
func noSpace(str string) string {
78+
return whitespaceRe.ReplaceAllString(str, "")
79+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package mg9
2+
3+
import (
4+
"fmt"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strconv"
9+
10+
migrate "github.com/ipfs/fs-repo-migrations/go-migrate"
11+
lock "github.com/ipfs/fs-repo-migrations/ipfs-1-to-2/repolock"
12+
mfsr "github.com/ipfs/fs-repo-migrations/mfsr"
13+
log "github.com/ipfs/fs-repo-migrations/stump"
14+
)
15+
16+
type Migration struct{}
17+
18+
func (m Migration) Versions() string {
19+
return "9-to-10"
20+
}
21+
22+
func (m Migration) Reversible() bool {
23+
return true
24+
}
25+
26+
func (m Migration) Apply(opts migrate.Options) error {
27+
log.Verbose = opts.Verbose
28+
log.Log("applying %s repo migration", m.Versions())
29+
30+
log.VLog("locking repo at %q", opts.Path)
31+
lk, err := lock.Lock2(opts.Path)
32+
if err != nil {
33+
return err
34+
}
35+
defer lk.Close()
36+
37+
repo := mfsr.RepoPath(opts.Path)
38+
39+
log.VLog(" - verifying version is '9'")
40+
if err := repo.CheckVersion("9"); err != nil {
41+
return err
42+
}
43+
44+
log.Log("> Upgrading config to new format")
45+
46+
path := filepath.Join(opts.Path, "config")
47+
if err := convertFile(path, ver9to10Bootstrap, ver9to10Addresses); err != nil {
48+
return err
49+
}
50+
51+
if err := repo.WriteVersion("10"); err != nil {
52+
log.Error("failed to update version file to 10")
53+
return err
54+
}
55+
56+
log.Log("updated version file")
57+
58+
return nil
59+
}
60+
61+
func writePhase(file string, phase int) error {
62+
return ioutil.WriteFile(file, []byte(fmt.Sprint(phase)), 0666)
63+
}
64+
65+
func readPhase(file string) (int, error) {
66+
data, err := ioutil.ReadFile(file)
67+
if err != nil {
68+
if os.IsNotExist(err) {
69+
return 0, nil
70+
}
71+
return 0, err
72+
}
73+
74+
return strconv.Atoi(string(data))
75+
}
76+
77+
func (m Migration) Revert(opts migrate.Options) error {
78+
log.Verbose = opts.Verbose
79+
log.Log("reverting migration")
80+
lk, err := lock.Lock2(opts.Path)
81+
if err != nil {
82+
return err
83+
}
84+
defer lk.Close()
85+
86+
repo := mfsr.RepoPath(opts.Path)
87+
if err := repo.CheckVersion("10"); err != nil {
88+
return err
89+
}
90+
91+
if err := repo.WriteVersion("9"); err != nil {
92+
return err
93+
}
94+
if opts.Verbose {
95+
fmt.Println("lowered version number to 9")
96+
}
97+
98+
return nil
99+
}

sharness/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ BINS += bin/ipfs-5-to-6
2323
BINS += bin/ipfs-6-to-7
2424
BINS += bin/ipfs-7-to-8
2525
BINS += bin/ipfs-8-to-9
26+
BINS += bin/ipfs-9-to-10
2627
BINS += bin/ipfs-update
2728
BINS += bin/random-files
2829
BINS += bin/go-sleep
@@ -40,6 +41,7 @@ IPFS_5_TO_6_SRC = ../ipfs-5-to-6
4041
IPFS_6_TO_7_SRC = ../ipfs-6-to-7
4142
IPFS_7_TO_8_SRC = ../ipfs-7-to-8
4243
IPFS_8_TO_9_SRC = ../ipfs-8-to-9
44+
IPFS_9_TO_10_SRC = ../ipfs-9-to-10
4345

4446
# User might want to override those on the command line
4547
GOFLAGS =
@@ -131,6 +133,10 @@ bin/ipfs-8-to-9: $(call find_go_files, $(IPFS_8_TO_9_SRC)) BUILD-OPTIONS
131133
@echo "*** installing $@ ***"
132134
go build $(GOFLAGS) -o $@ $(IPFS_8_TO_9_SRC)
133135

136+
bin/ipfs-9-to-10: $(call find_go_files, $(IPFS_9_TO_10_SRC)) BUILD-OPTIONS
137+
@echo "*** installing $@ ***"
138+
go build $(GOFLAGS) -o $@ $(IPFS_9_TO_10_SRC)
139+
134140

135141
BUILD-OPTIONS: FORCE
136142
@bin/checkflags '$@' '$(GOFLAGS)' '*** new Go flags ***'

0 commit comments

Comments
 (0)