add clone of 3node test using iptb instead of docker
rename directory and update vendored dep cleanup
Jeromy committed
Apr 21, 2015 at 11:41 UTC
89ff6dfdaab54f2a5034c596ec4b18f340a29557
7 files changed
+493
-1
Godeps/Godeps.json
+4
@@ -36,6 +36,10 @@
36
"ImportPath": "github.com/ActiveState/tail",
37
"Rev": "068b72961a6bc5b4a82cf4fc14ccc724c0cfa73a"
38
},
39
+ {
40
+ "ImportPath":"github.com/whyrusleeping/iptb",
41
+ "Rev": "5ee5bc0bb43502dfc798786a78df2448c91dd764"
42
+ },
43
{
44
"ImportPath": "github.com/Sirupsen/logrus",
45
"Comment": "v0.7.1",
Godeps/_workspace/src/github.com/whyrusleeping/iptb/LICENSE
new
+21
@@ -0,0 +1,21 @@
1
+The MIT License (MIT)
2
+
3
+Copyright (c) 2015 Jeromy Johnson
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy
6
+of this software and associated documentation files (the "Software"), to deal
7
+in the Software without restriction, including without limitation the rights
8
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+copies of the Software, and to permit persons to whom the Software is
10
+furnished to do so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in
13
+all copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+THE SOFTWARE.
Godeps/_workspace/src/github.com/whyrusleeping/iptb/README.md
new
+20
@@ -0,0 +1,20 @@
1
+#Ipfs Testbed
2
+
3
+##commands:
4
+
5
+### init -n=[number of nodes]
6
+creates and initializes 'n' repos
7
+
8
+### start
9
+starts up all testbed nodes
10
+
11
+### stop
12
+kills all testbed nodes
13
+
14
+### restart
15
+kills, then restarts all testbed nodes
16
+
17
+### shell [n]
18
+execs your shell with environment variables set as follows:
19
+- IPFS_PATH - set to testbed node n's IPFS_PATH
20
+- NODE[x] - set to the peer ID of node x
Godeps/_workspace/src/github.com/whyrusleeping/iptb/main.go
new
+403
@@ -0,0 +1,403 @@
1
+package main
2
+
3
+import (
4
+ "flag"
5
+ "fmt"
6
+ serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
7
+ "io/ioutil"
8
+ "log"
9
+ "net"
10
+ "os"
11
+ "os/exec"
12
+ "path"
13
+ "strconv"
14
+ "sync"
15
+ "syscall"
16
+ "time"
17
+)
18
+
19
+// GetNumNodes returns the number of testbed nodes configured in the testbed directory
20
+func GetNumNodes() int {
21
+ for i := 0; i < 2000; i++ {
22
+ _, err := os.Stat(IpfsDirN(i))
23
+ if os.IsNotExist(err) {
24
+ return i
25
+ }
26
+ }
27
+ panic("i dont know whats going on")
28
+}
29
+
30
+func TestBedDir() string {
31
+ tbd := os.Getenv("IPTB_ROOT")
32
+ if len(tbd) != 0 {
33
+ return tbd
34
+ }
35
+
36
+ home := os.Getenv("HOME")
37
+ if len(home) == 0 {
38
+ panic("could not find home")
39
+ }
40
+
41
+ return path.Join(home, "testbed")
42
+}
43
+
44
+func IpfsDirN(n int) string {
45
+ return path.Join(TestBedDir(), fmt.Sprint(n))
46
+}
47
+
48
+func YesNoPrompt(prompt string) bool {
49
+ var s string
50
+ for {
51
+ fmt.Println(prompt)
52
+ fmt.Scanf("%s", &s)
53
+ switch s {
54
+ case "y", "Y":
55
+ return true
56
+ case "n", "N":
57
+ return false
58
+ }
59
+ fmt.Println("Please press either 'y' or 'n'")
60
+ }
61
+}
62
+
63
+type initCfg struct {
64
+ Count int
65
+ Force bool
66
+ Bootstrap string
67
+}
68
+
69
+func IpfsInit(cfg *initCfg) error {
70
+ p := IpfsDirN(0)
71
+ if _, err := os.Stat(p); !os.IsNotExist(err) {
72
+ if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") {
73
+ return nil
74
+ }
75
+ err := os.RemoveAll(TestBedDir())
76
+ if err != nil {
77
+ return err
78
+ }
79
+ }
80
+ wait := sync.WaitGroup{}
81
+ for i := 0; i < cfg.Count; i++ {
82
+ wait.Add(1)
83
+ go func(v int) {
84
+ defer wait.Done()
85
+ dir := IpfsDirN(v)
86
+ err := os.MkdirAll(dir, 0777)
87
+ if err != nil {
88
+ log.Println("ERROR: ", err)
89
+ return
90
+ }
91
+
92
+ cmd := exec.Command("ipfs", "init", "-b=1024")
93
+ cmd.Env = append(cmd.Env, "IPFS_PATH="+dir)
94
+ out, err := cmd.CombinedOutput()
95
+ if err != nil {
96
+ log.Println("ERROR: ", err)
97
+ log.Println(string(out))
98
+ }
99
+ }(i)
100
+ }
101
+ wait.Wait()
102
+
103
+ // Now setup bootstrapping
104
+ switch cfg.Bootstrap {
105
+ case "star":
106
+ err := starBootstrap(cfg)
107
+ if err != nil {
108
+ return err
109
+ }
110
+ case "none":
111
+ err := clearBootstrapping(cfg)
112
+ if err != nil {
113
+ return err
114
+ }
115
+ default:
116
+ return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap)
117
+ }
118
+
119
+ return nil
120
+}
121
+
122
+func starBootstrap(cfg *initCfg) error {
123
+ // '0' node is the bootstrap node
124
+ cfgpath := path.Join(IpfsDirN(0), "config")
125
+ bcfg, err := serial.Load(cfgpath)
126
+ if err != nil {
127
+ return err
128
+ }
129
+ bcfg.Bootstrap = nil
130
+ bcfg.Addresses.Swarm = []string{"/ip4/127.0.0.1/tcp/4002"}
131
+ bcfg.Addresses.API = "/ip4/127.0.0.1/tcp/5002"
132
+ bcfg.Addresses.Gateway = ""
133
+ err = serial.WriteConfigFile(cfgpath, bcfg)
134
+ if err != nil {
135
+ return err
136
+ }
137
+
138
+ for i := 1; i < cfg.Count; i++ {
139
+ cfgpath := path.Join(IpfsDirN(i), "config")
140
+ cfg, err := serial.Load(cfgpath)
141
+ if err != nil {
142
+ return err
143
+ }
144
+
145
+ cfg.Bootstrap = []string{fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID)}
146
+ cfg.Addresses.Gateway = ""
147
+ cfg.Addresses.Swarm = []string{
148
+ fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", 4002+i),
149
+ }
150
+ cfg.Addresses.API = fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5002+i)
151
+ err = serial.WriteConfigFile(cfgpath, cfg)
152
+ if err != nil {
153
+ return err
154
+ }
155
+ }
156
+ return nil
157
+}
158
+
159
+func clearBootstrapping(cfg *initCfg) error {
160
+ for i := 0; i < cfg.Count; i++ {
161
+ cfgpath := path.Join(IpfsDirN(i), "config")
162
+ cfg, err := serial.Load(cfgpath)
163
+ if err != nil {
164
+ return err
165
+ }
166
+
167
+ cfg.Bootstrap = nil
168
+ cfg.Addresses.Gateway = ""
169
+ cfg.Addresses.Swarm = []string{
170
+ fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", 4002+i),
171
+ }
172
+ cfg.Addresses.API = fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", 5002+i)
173
+ err = serial.WriteConfigFile(cfgpath, cfg)
174
+ if err != nil {
175
+ return err
176
+ }
177
+ }
178
+ return nil
179
+}
180
+
181
+func IpfsPidOf(n int) (int, error) {
182
+ dir := IpfsDirN(n)
183
+ b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid"))
184
+ if err != nil {
185
+ return -1, err
186
+ }
187
+
188
+ return strconv.Atoi(string(b))
189
+}
190
+
191
+func IpfsKill() error {
192
+ n := GetNumNodes()
193
+ for i := 0; i < n; i++ {
194
+ pid, err := IpfsPidOf(i)
195
+ if err != nil {
196
+ fmt.Printf("error killing daemon %d: %s\n", i, err)
197
+ continue
198
+ }
199
+
200
+ p, err := os.FindProcess(pid)
201
+ if err != nil {
202
+ fmt.Printf("error killing daemon %d: %s\n", i, err)
203
+ continue
204
+ }
205
+ err = p.Kill()
206
+ if err != nil {
207
+ fmt.Printf("error killing daemon %d: %s\n", i, err)
208
+ continue
209
+ }
210
+
211
+ p.Wait()
212
+
213
+ err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid"))
214
+ if err != nil {
215
+ fmt.Printf("error removing pid file for daemon %d: %s\n", i, err)
216
+ continue
217
+ }
218
+ }
219
+ return nil
220
+}
221
+
222
+func IpfsStart(waitall bool) error {
223
+ n := GetNumNodes()
224
+ for i := 0; i < n; i++ {
225
+ dir := IpfsDirN(i)
226
+ cmd := exec.Command("ipfs", "daemon")
227
+ cmd.Dir = dir
228
+ cmd.Env = []string{"IPFS_PATH=" + dir}
229
+
230
+ cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
231
+
232
+ stdout, err := os.Create(path.Join(dir, "daemon.stdout"))
233
+ if err != nil {
234
+ return err
235
+ }
236
+
237
+ stderr, err := os.Create(path.Join(dir, "daemon.stderr"))
238
+ if err != nil {
239
+ return err
240
+ }
241
+
242
+ cmd.Stdout = stdout
243
+ cmd.Stderr = stderr
244
+
245
+ err = cmd.Start()
246
+ if err != nil {
247
+ return err
248
+ }
249
+ pid := cmd.Process.Pid
250
+
251
+ fmt.Printf("Started daemon %d, pid = %d\n", i, pid)
252
+ err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666)
253
+ if err != nil {
254
+ return err
255
+ }
256
+
257
+ // Make sure node 0 is up before starting the rest so
258
+ // bootstrapping works properly
259
+ if i == 0 || waitall {
260
+ err := waitForLive(fmt.Sprintf("localhost:%d", 5002+i))
261
+ if err != nil {
262
+ return err
263
+ }
264
+ }
265
+ }
266
+ return nil
267
+}
268
+
269
+// waitForLive polls the given endpoint until it is up, or until
270
+// a timeout
271
+func waitForLive(addr string) error {
272
+ for i := 0; i < 50; i++ {
273
+ c, err := net.Dial("tcp", addr)
274
+ if err == nil {
275
+ c.Close()
276
+ return nil
277
+ }
278
+ time.Sleep(time.Millisecond * 200)
279
+ }
280
+ return fmt.Errorf("node at %s failed to come online in given time period", addr)
281
+}
282
+
283
+// GetPeerID reads the config of node 'n' and returns its peer ID
284
+func GetPeerID(n int) (string, error) {
285
+ cfg, err := serial.Load(path.Join(IpfsDirN(n), "config"))
286
+ if err != nil {
287
+ return "", err
288
+ }
289
+ return cfg.Identity.PeerID, nil
290
+}
291
+
292
+// IpfsShell sets up environment variables for a new shell to more easily
293
+// control the given daemon
294
+func IpfsShell(n int) error {
295
+ shell := os.Getenv("SHELL")
296
+ if shell == "" {
297
+ return fmt.Errorf("couldnt find shell!")
298
+ }
299
+
300
+ dir := IpfsDirN(n)
301
+ nenvs := []string{"IPFS_PATH=" + dir}
302
+
303
+ nnodes := GetNumNodes()
304
+ for i := 0; i < nnodes; i++ {
305
+ peerid, err := GetPeerID(i)
306
+ if err != nil {
307
+ return err
308
+ }
309
+ nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid))
310
+ }
311
+ nenvs = append(os.Environ(), nenvs...)
312
+
313
+ return syscall.Exec(shell, []string{shell}, nenvs)
314
+}
315
+
316
+var helptext = `Ipfs Testbed
317
+
318
+Commands:
319
+ init
320
+ creates and initializes 'n' repos
321
+
322
+ Options:
323
+ -n=[number of nodes]
324
+ -f - force overwriting of existing nodes
325
+ -bootstrap - select bootstrapping style for cluster
326
+ choices: star, none
327
+
328
+ start
329
+ starts up all testbed nodes
330
+
331
+ Options:
332
+ -wait - wait until daemons are fully initialized
333
+ stop
334
+ kills all testbed nodes
335
+ restart
336
+ kills, then restarts all testbed nodes
337
+
338
+ shell [n]
339
+ execs your shell with environment variables set as follows:
340
+ IPFS_PATH - set to testbed node n's IPFS_PATH
341
+ NODE[x] - set to the peer ID of node x
342
+
343
+Env Vars:
344
+
345
+IPTB_ROOT:
346
+ Used to specify the directory that nodes will be created in.
347
+`
348
+
349
+func handleErr(s string, err error) {
350
+ if err != nil {
351
+ fmt.Println(s, err)
352
+ os.Exit(1)
353
+ }
354
+}
355
+
356
+func main() {
357
+ cfg := new(initCfg)
358
+ flag.IntVar(&cfg.Count, "n", 0, "number of ipfs nodes to initialize")
359
+ flag.BoolVar(&cfg.Force, "f", false, "force initialization (overwrite existing configs)")
360
+ flag.StringVar(&cfg.Bootstrap, "bootstrap", "star", "select bootstrapping style for cluster")
361
+
362
+ wait := flag.Bool("wait", false, "wait for nodes to come fully online before exiting")
363
+ flag.Usage = func() {
364
+ fmt.Println(helptext)
365
+ }
366
+
367
+ flag.Parse()
368
+
369
+ switch flag.Arg(0) {
370
+ case "init":
371
+ if cfg.Count == 0 {
372
+ fmt.Printf("please specify number of nodes: '%s -n=10 init'\n", os.Args[0])
373
+ os.Exit(1)
374
+ }
375
+ err := IpfsInit(cfg)
376
+ handleErr("ipfs init err: ", err)
377
+ case "start":
378
+ err := IpfsStart(*wait)
379
+ handleErr("ipfs start err: ", err)
380
+ case "stop", "kill":
381
+ err := IpfsKill()
382
+ handleErr("ipfs kill err: ", err)
383
+ case "restart":
384
+ err := IpfsKill()
385
+ handleErr("ipfs kill err: ", err)
386
+
387
+ err = IpfsStart(*wait)
388
+ handleErr("ipfs start err: ", err)
389
+ case "shell":
390
+ if len(flag.Args()) < 2 {
391
+ fmt.Println("please specify which node you want a shell for")
392
+ os.Exit(1)
393
+ }
394
+ n, err := strconv.Atoi(flag.Arg(1))
395
+ handleErr("parse err: ", err)
396
+
397
+ err = IpfsShell(n)
398
+ handleErr("ipfs shell err: ", err)
399
+ default:
400
+ flag.Usage()
401
+ os.Exit(1)
402
+ }
403
+}
test/Makefile
+5
@@ -4,6 +4,7 @@ IPFS_ROOT = ../
4
IPFS_CMD = ../cmd/ipfs
5
RANDOM_SRC = ../Godeps/_workspace/src/github.com/jbenet/go-random
6
MULTIHASH_SRC = ../Godeps/_workspace/src/github.com/jbenet/go-multihash
7
+IPTB_SRC = ../Godeps/_workspace/src/github.com/whyrusleeping/iptb
8
POLLENDPOINT_SRC= ../thirdparty/pollEndpoint
9
10
# User might want to override those on the command line
@@ -36,6 +37,10 @@ bin/pollEndpoint: $(call find_go_files, $(POLLENDPOINT_SRC)) IPFS-BUILD-OPTIONS
37
@echo "*** installing $@ ***"
38
go build $(GOFLAGS) -o bin/pollEndpoint $(POLLENDPOINT_SRC)
39
40
+bin/iptb: $(call find_go_files, $(IPTB_SRC)) IPFS-BUILD-OPTIONS
41
+ @echo "*** installing $@ ***"
42
+ go build $(GOFLAGS) -o bin/iptb $(IPTB_SRC)
43
+
44
test: test_expensive
45
46
test_expensive:
test/sharness/Makefile
+2
-1
@@ -7,7 +7,8 @@
7
# NOTE: run with TEST_VERBOSE=1 for verbose sharness tests.
8
9
T = $(sort $(wildcard t[0-9][0-9][0-9][0-9]-*.sh))
10
-BINS = bin/random bin/multihash bin/ipfs bin/pollEndpoint
10
+BINS = bin/random bin/multihash bin/ipfs bin/pollEndpoint \
11
+ bin/iptb
12
SHARNESS = lib/sharness/sharness.sh
13
IPFS_ROOT = ../..
14
test/sharness/t0130-multinode.sh
new
+38
@@ -0,0 +1,38 @@
1
+#!/bin/sh
2
+#
3
+# Copyright (c) 2015 Jeromy Johnson
4
+# MIT Licensed; see the LICENSE file in this repository.
5
+#
6
+
7
+test_description="Test multiple ipfs nodes"
8
+
9
+. lib/test-lib.sh
10
+
11
+export IPTB_ROOT="`pwd`/.iptb"
12
+
13
+test_expect_success "set up a few nodes" '
14
+ iptb -n=3 init &&
15
+ iptb -wait start
16
+'
17
+
18
+test_expect_success "add a file on node1" '
19
+ export IPFS_PATH="$IPTB_ROOT/1"
20
+ random 1000000 > filea &&
21
+ FILEA_HASH=`ipfs add -q filea`
22
+'
23
+
24
+test_expect_success "cat that file on node2" '
25
+ export IPFS_PATH="$IPTB_ROOT/2"
26
+ ipfs cat $FILEA_HASH | multihash > actual1
27
+'
28
+
29
+test_expect_success "verify files match" '
30
+ multihash filea > expected1 &&
31
+ test_cmp actual1 expected1
32
+'
33
+
34
+test_expect_success "shut down nodes" '
35
+ iptb stop
36
+'
37
+
38
+test_done