1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-06-28 17:03:58 +08:00

Merge pull request #2545 from chriscool/use-gx-for-iptb

Use gx for iptb
This commit is contained in:
Jeromy Johnson
2016-05-03 15:15:31 -07:00
8 changed files with 45 additions and 922 deletions

View File

@ -1,13 +0,0 @@
// +build !windows
package iptbutil
import (
"os/exec"
"syscall"
)
func init() {
setupOpt = func(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
}
}

View File

@ -1,542 +0,0 @@
package iptbutil
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"os/exec"
"path"
"strconv"
"strings"
"sync"
"syscall"
"time"
serial "github.com/ipfs/go-ipfs/repo/fsrepo/serialize"
manet "gx/ipfs/QmTrxSBY8Wqd5aBB4MeizeSzS5xFbK8dQBrYaMsiGnCBhb/go-multiaddr-net"
ma "gx/ipfs/QmcobAGsCjYt5DXoq9et9L8yR8er7o7Cu3DTvpaq12jYSz/go-multiaddr"
)
var setupOpt = func(cmd *exec.Cmd) {}
// GetNumNodes returns the number of testbed nodes configured in the testbed directory
func GetNumNodes() int {
for i := 0; i < 2000; i++ {
_, err := os.Stat(IpfsDirN(i))
if os.IsNotExist(err) {
return i
}
}
panic("i dont know whats going on")
}
func TestBedDir() string {
tbd := os.Getenv("IPTB_ROOT")
if len(tbd) != 0 {
return tbd
}
home := os.Getenv("HOME")
if len(home) == 0 {
panic("could not find home")
}
return path.Join(home, "testbed")
}
func IpfsDirN(n int) string {
return path.Join(TestBedDir(), fmt.Sprint(n))
}
type InitCfg struct {
Count int
Force bool
Bootstrap string
PortStart int
Mdns bool
Utp bool
Override string
}
func (c *InitCfg) swarmAddrForPeer(i int) string {
str := "/ip4/0.0.0.0/tcp/%d"
if c.Utp {
str = "/ip4/0.0.0.0/udp/%d/utp"
}
if c.PortStart == 0 {
return fmt.Sprintf(str, 0)
}
return fmt.Sprintf(str, c.PortStart+i)
}
func (c *InitCfg) apiAddrForPeer(i int) string {
if c.PortStart == 0 {
return "/ip4/127.0.0.1/tcp/0"
}
return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", c.PortStart+1000+i)
}
func YesNoPrompt(prompt string) bool {
var s string
for {
fmt.Println(prompt)
fmt.Scanf("%s", &s)
switch s {
case "y", "Y":
return true
case "n", "N":
return false
}
fmt.Println("Please press either 'y' or 'n'")
}
}
func IpfsInit(cfg *InitCfg) error {
p := IpfsDirN(0)
if _, err := os.Stat(p); !os.IsNotExist(err) {
if !cfg.Force && !YesNoPrompt("testbed nodes already exist, overwrite? [y/n]") {
return nil
}
err := os.RemoveAll(TestBedDir())
if err != nil {
return err
}
}
wait := sync.WaitGroup{}
for i := 0; i < cfg.Count; i++ {
wait.Add(1)
go func(v int) {
defer wait.Done()
dir := IpfsDirN(v)
err := os.MkdirAll(dir, 0777)
if err != nil {
log.Println("ERROR: ", err)
return
}
cmd := exec.Command("ipfs", "init", "-b=1024")
cmd.Env = append(cmd.Env, "IPFS_PATH="+dir)
out, err := cmd.CombinedOutput()
if err != nil {
log.Println("ERROR: ", err)
log.Println(string(out))
}
}(i)
}
wait.Wait()
// Now setup bootstrapping
switch cfg.Bootstrap {
case "star":
err := starBootstrap(cfg)
if err != nil {
return err
}
case "none":
err := clearBootstrapping(cfg)
if err != nil {
return err
}
default:
return fmt.Errorf("unrecognized bootstrapping option: %s", cfg.Bootstrap)
}
/*
if cfg.Override != "" {
err := ApplyConfigOverride(cfg)
if err != nil {
return err
}
}
*/
return nil
}
func ApplyConfigOverride(cfg *InitCfg) error {
fir, err := os.Open(cfg.Override)
if err != nil {
return err
}
defer fir.Close()
var configs map[string]interface{}
err = json.NewDecoder(fir).Decode(&configs)
if err != nil {
return err
}
for i := 0; i < cfg.Count; i++ {
err := applyOverrideToNode(configs, i)
if err != nil {
return err
}
}
return nil
}
func applyOverrideToNode(ovr map[string]interface{}, node int) error {
for k, v := range ovr {
_ = k
switch v.(type) {
case map[string]interface{}:
default:
}
}
panic("not implemented")
}
func starBootstrap(icfg *InitCfg) error {
// '0' node is the bootstrap node
cfgpath := path.Join(IpfsDirN(0), "config")
bcfg, err := serial.Load(cfgpath)
if err != nil {
return err
}
bcfg.Bootstrap = nil
bcfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(0)}
bcfg.Addresses.API = icfg.apiAddrForPeer(0)
bcfg.Addresses.Gateway = ""
bcfg.Discovery.MDNS.Enabled = icfg.Mdns
err = serial.WriteConfigFile(cfgpath, bcfg)
if err != nil {
return err
}
for i := 1; i < icfg.Count; i++ {
cfgpath := path.Join(IpfsDirN(i), "config")
cfg, err := serial.Load(cfgpath)
if err != nil {
return err
}
ba := fmt.Sprintf("%s/ipfs/%s", bcfg.Addresses.Swarm[0], bcfg.Identity.PeerID)
ba = strings.Replace(ba, "0.0.0.0", "127.0.0.1", -1)
cfg.Bootstrap = []string{ba}
cfg.Addresses.Gateway = ""
cfg.Discovery.MDNS.Enabled = icfg.Mdns
cfg.Addresses.Swarm = []string{
icfg.swarmAddrForPeer(i),
}
cfg.Addresses.API = icfg.apiAddrForPeer(i)
err = serial.WriteConfigFile(cfgpath, cfg)
if err != nil {
return err
}
}
return nil
}
func clearBootstrapping(icfg *InitCfg) error {
for i := 0; i < icfg.Count; i++ {
cfgpath := path.Join(IpfsDirN(i), "config")
cfg, err := serial.Load(cfgpath)
if err != nil {
return err
}
cfg.Bootstrap = nil
cfg.Addresses.Gateway = ""
cfg.Addresses.Swarm = []string{icfg.swarmAddrForPeer(i)}
cfg.Addresses.API = icfg.apiAddrForPeer(i)
cfg.Discovery.MDNS.Enabled = icfg.Mdns
err = serial.WriteConfigFile(cfgpath, cfg)
if err != nil {
return err
}
}
return nil
}
func IpfsPidOf(n int) (int, error) {
dir := IpfsDirN(n)
b, err := ioutil.ReadFile(path.Join(dir, "daemon.pid"))
if err != nil {
return -1, err
}
return strconv.Atoi(string(b))
}
func KillNode(i int) error {
pid, err := IpfsPidOf(i)
if err != nil {
return fmt.Errorf("error killing daemon %d: %s", i, err)
}
p, err := os.FindProcess(pid)
if err != nil {
return fmt.Errorf("error killing daemon %d: %s", i, err)
}
err = p.Kill()
if err != nil {
return fmt.Errorf("error killing daemon %d: %s\n", i, err)
}
p.Wait()
err = os.Remove(path.Join(IpfsDirN(i), "daemon.pid"))
if err != nil {
return fmt.Errorf("error removing pid file for daemon %d: %s\n", i, err)
}
return nil
}
func IpfsKillAll() error {
n := GetNumNodes()
for i := 0; i < n; i++ {
err := KillNode(i)
if err != nil {
return err
}
}
return nil
}
func envForDaemon(n int) []string {
envs := os.Environ()
npath := "IPFS_PATH=" + IpfsDirN(n)
for i, e := range envs {
p := strings.Split(e, "=")
if p[0] == "IPFS_PATH" {
envs[i] = npath
return envs
}
}
return append(envs, npath)
}
func IpfsStart(waitall bool) error {
var addrs []string
n := GetNumNodes()
for i := 0; i < n; i++ {
dir := IpfsDirN(i)
cmd := exec.Command("ipfs", "daemon")
cmd.Dir = dir
cmd.Env = envForDaemon(i)
setupOpt(cmd)
stdout, err := os.Create(path.Join(dir, "daemon.stdout"))
if err != nil {
return err
}
stderr, err := os.Create(path.Join(dir, "daemon.stderr"))
if err != nil {
return err
}
cmd.Stdout = stdout
cmd.Stderr = stderr
err = cmd.Start()
if err != nil {
return err
}
pid := cmd.Process.Pid
fmt.Printf("Started daemon %d, pid = %d\n", i, pid)
err = ioutil.WriteFile(path.Join(dir, "daemon.pid"), []byte(fmt.Sprint(pid)), 0666)
if err != nil {
return err
}
// Make sure node 0 is up before starting the rest so
// bootstrapping works properly
cfg, err := serial.Load(path.Join(IpfsDirN(i), "config"))
if err != nil {
return err
}
maddr := ma.StringCast(cfg.Addresses.API)
_, addr, err := manet.DialArgs(maddr)
if err != nil {
return err
}
addrs = append(addrs, addr)
err = waitOnAPI(cfg.Identity.PeerID, i)
if err != nil {
return err
}
}
if waitall {
for i := 0; i < n; i++ {
err := waitOnSwarmPeers(i)
if err != nil {
return err
}
}
}
return nil
}
func waitOnAPI(peerid string, nnum int) error {
for i := 0; i < 50; i++ {
err := tryAPICheck(peerid, nnum)
if err == nil {
return nil
}
time.Sleep(time.Millisecond * 200)
}
return fmt.Errorf("node %d failed to come online in given time period", nnum)
}
func GetNodesAPIAddr(nnum int) (string, error) {
addrb, err := ioutil.ReadFile(path.Join(IpfsDirN(nnum), "api"))
if err != nil {
return "", err
}
maddr, err := ma.NewMultiaddr(string(addrb))
if err != nil {
fmt.Println("error parsing multiaddr: ", err)
return "", err
}
_, addr, err := manet.DialArgs(maddr)
if err != nil {
fmt.Println("error on multiaddr dialargs: ", err)
return "", err
}
return addr, nil
}
func tryAPICheck(peerid string, nnum int) error {
addr, err := GetNodesAPIAddr(nnum)
if err != nil {
return err
}
resp, err := http.Get("http://" + addr + "/api/v0/id")
if err != nil {
return err
}
out := make(map[string]interface{})
err = json.NewDecoder(resp.Body).Decode(&out)
if err != nil {
return fmt.Errorf("liveness check failed: %s", err)
}
id, ok := out["ID"]
if !ok {
return fmt.Errorf("liveness check failed: ID field not present in output")
}
idstr := id.(string)
if idstr != peerid {
return fmt.Errorf("liveness check failed: unexpected peer at endpoint")
}
return nil
}
func waitOnSwarmPeers(nnum int) error {
addr, err := GetNodesAPIAddr(nnum)
if err != nil {
return err
}
for i := 0; i < 50; i++ {
resp, err := http.Get("http://" + addr + "/api/v0/swarm/peers")
if err == nil {
out := make(map[string]interface{})
err := json.NewDecoder(resp.Body).Decode(&out)
if err != nil {
return fmt.Errorf("liveness check failed: %s", err)
}
peers := out["Strings"].([]interface{})
if len(peers) == 0 {
time.Sleep(time.Millisecond * 200)
continue
}
return nil
}
time.Sleep(time.Millisecond * 200)
}
return fmt.Errorf("node at %s failed to bootstrap in given time period", addr)
}
// GetPeerID reads the config of node 'n' and returns its peer ID
func GetPeerID(n int) (string, error) {
cfg, err := serial.Load(path.Join(IpfsDirN(n), "config"))
if err != nil {
return "", err
}
return cfg.Identity.PeerID, nil
}
// IpfsShell sets up environment variables for a new shell to more easily
// control the given daemon
func IpfsShell(n int) error {
shell := os.Getenv("SHELL")
if shell == "" {
return fmt.Errorf("couldnt find shell!")
}
dir := IpfsDirN(n)
nenvs := []string{"IPFS_PATH=" + dir}
nnodes := GetNumNodes()
for i := 0; i < nnodes; i++ {
peerid, err := GetPeerID(i)
if err != nil {
return err
}
nenvs = append(nenvs, fmt.Sprintf("NODE%d=%s", i, peerid))
}
nenvs = append(os.Environ(), nenvs...)
return syscall.Exec(shell, []string{shell}, nenvs)
}
func ConnectNodes(from, to int) error {
if from == to {
// skip connecting to self..
return nil
}
fmt.Printf("connecting %d -> %d\n", from, to)
cmd := exec.Command("ipfs", "id", "-f", "<addrs>")
cmd.Env = []string{"IPFS_PATH=" + IpfsDirN(to)}
out, err := cmd.Output()
if err != nil {
fmt.Println("ERR: ", string(out))
return err
}
addr := strings.Split(string(out), "\n")[0]
connectcmd := exec.Command("ipfs", "swarm", "connect", addr)
connectcmd.Env = []string{"IPFS_PATH=" + IpfsDirN(from)}
out, err = connectcmd.CombinedOutput()
if err != nil {
fmt.Println(string(out))
return err
}
return nil
}
func GetAttr(attr string, node int) (string, error) {
switch attr {
case "id":
return GetPeerID(node)
default:
return "", errors.New("unrecognized attribute")
}
}

View File

@ -59,6 +59,16 @@
"hash": "QmdhsRK1EK2fvAz2i2SH5DEfkL6seDuyMYEsxKa9Braim3",
"name": "client_golang",
"version": "0.0.0"
},
{
"hash": "QmSx5xkktduyo1hBL7kZxdiZq1P9TrgeGkNW8qtoY14bSk",
"name": "iptb",
"version": "0.0.0"
},
{
"hash": "QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku",
"name": "go-multihash",
"version": "0.0.0"
}
],
"gxVersion": "0.4.0",

View File

@ -4,17 +4,20 @@ IPFS_ROOT = ../
IPFS_CMD = ../cmd/ipfs
RANDOM_SRC = ../Godeps/_workspace/src/github.com/jbenet/go-random
RANDOM_FILES_SRC = ../Godeps/_workspace/src/github.com/jbenet/go-random-files
MULTIHASH_SRC = ../../../../gx/ipfs/QmYf7ng2hG5XBtJA3tN34DQ2GUN5HNksEw1rLDkmr6vGku/go-multihash
IPTB_SRC = ./dependencies/iptb
POLLENDPOINT_SRC= ../thirdparty/pollEndpoint
GOSLEEP_SRC = ./dependencies/go-sleep
GX_RELATIVE_PATH = ../../../../gx/ipfs
# User might want to override those on the command line
GOFLAGS =
all: deps
deps: bins
global-deps:
make -C .. deps
deps: global-deps bins
clean:
rm $(BINS)
@ -23,6 +26,8 @@ bins: $(BINS)
find_go_files = $(shell find $(1) -name "*.go")
# Non gx dependencies
bin/random: $(call find_go_files, $(RANDOM_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/random $(RANDOM_SRC)/random
@ -31,10 +36,6 @@ bin/random-files:
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/random-files $(RANDOM_FILES_SRC)/random-files
bin/multihash: $(call find_go_files, $(MULTIHASH_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/multihash $(MULTIHASH_SRC)/multihash
bin/ipfs: $(call find_go_files, $(IPFS_ROOT)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/ipfs $(IPFS_CMD)
@ -43,14 +44,30 @@ bin/pollEndpoint: $(call find_go_files, $(POLLENDPOINT_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/pollEndpoint $(POLLENDPOINT_SRC)
bin/iptb: $(call find_go_files, $(IPTB_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/iptb $(IPTB_SRC)
bin/go-sleep: $(call find_go_files, $(GOSLEEP_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/go-sleep $(GOSLEEP_SRC)
# gx dependencies
multihash_src:
$(eval MULTIHASH_HASH := $(shell cd .. && gx deps find go-multihash))
$(eval MULTIHASH_SRC := $(GX_RELATIVE_PATH)/$(MULTIHASH_HASH)/go-multihash)
bin/multihash: multihash_src $(call find_go_files, $(MULTIHASH_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/multihash $(MULTIHASH_SRC)/multihash
iptb_src:
$(eval IPTB_HASH := $(shell cd .. && gx deps find iptb))
$(eval IPTB_SRC := $(GX_RELATIVE_PATH)/$(IPTB_HASH)/iptb)
bin/iptb: iptb_src $(call find_go_files, $(IPTB_SRC)) IPFS-BUILD-OPTIONS
@echo "*** installing $@ ***"
go build $(GOFLAGS) -o bin/iptb $(IPTB_SRC)
# Tests
test: test_expensive
test_expensive: verify_gofmt
@ -67,6 +84,8 @@ test_race: verify_gofmt
cd 3nodetest && make GOFLAGS=-race
cd dependencies && make GOFLAGS=-race
# Misc
coverage: coverage_sharness
coverage_sharness:

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Jeromy Johnson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -1,40 +0,0 @@
# IPTB
iptb is a program used to manage a cluster of ipfs nodes locally on your
computer. It allows the creation of up to 1000 (limited by poor port choice)
nodes, and allows for various other setup options to be selected such as
different bootstrapping patterns. iptb makes testing networks in ipfs
easy!
### Commands:
- init
- creates and initializes 'n' repos
- Options:
- -n=[number of nodes]
- -f : force overwriting of existing nodes
- -bootstrap : select bootstrapping style for cluster choices: star, none
- -mdns=[true||false] : defaults to false
- -p=[start port] : port to start allocations from
- start
- starts up all testbed nodes
- Options:
- -wait : wait until daemons are fully initialized
- stop
- kills all testbed nodes
- restart
- kills and then restarts all testbed nodes
- shell [n]
- execs your shell with environment variables set as follows:
- IPFS_PATH - set to testbed node n's IPFS_PATH
- NODE[x] - set to the peer ID of node x
- get [attr] [n]
- gets the specified attribute from then given node
- available attributes: id
### Configuration
By default, iptb uses `$HOME/testbed` to store created nodes. This path is
configurable via the environment variables `IPTB_ROOT`.

View File

@ -1,293 +0,0 @@
package main
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"strings"
cli "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codegangsta/cli"
util "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/whyrusleeping/iptb/util"
)
func parseRange(s string) ([]int, error) {
if strings.HasPrefix(s, "[") && strings.HasSuffix(s, "]") {
ranges := strings.Split(s[1:len(s)-1], ",")
var out []int
for _, r := range ranges {
rng, err := expandDashRange(r)
if err != nil {
return nil, err
}
out = append(out, rng...)
}
return out, nil
} else {
i, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
return []int{i}, nil
}
}
func expandDashRange(s string) ([]int, error) {
parts := strings.Split(s, "-")
if len(parts) == 0 {
i, err := strconv.Atoi(s)
if err != nil {
return nil, err
}
return []int{i}, nil
}
low, err := strconv.Atoi(parts[0])
if err != nil {
return nil, err
}
hi, err := strconv.Atoi(parts[1])
if err != nil {
return nil, err
}
var out []int
for i := low; i <= hi; i++ {
out = append(out, i)
}
return out, nil
}
func handleErr(s string, err error) {
if err != nil {
fmt.Fprintln(os.Stderr, s, err)
os.Exit(1)
}
}
func main() {
app := cli.NewApp()
app.Commands = []cli.Command{
initCmd,
startCmd,
killCmd,
restartCmd,
shellCmd,
getCmd,
connectCmd,
dumpStacksCmd,
}
err := app.Run(os.Args)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
}
var initCmd = cli.Command{
Name: "init",
Usage: "create and initialize testbed nodes",
Flags: []cli.Flag{
cli.IntFlag{
Name: "count, n",
Usage: "number of ipfs nodes to initialize",
},
cli.IntFlag{
Name: "port, p",
Usage: "port to start allocations from",
},
cli.BoolFlag{
Name: "force, f",
Usage: "force initialization (overwrite existing configs)",
},
cli.BoolFlag{
Name: "mdns",
Usage: "turn on mdns for nodes",
},
cli.StringFlag{
Name: "bootstrap",
Usage: "select bootstrapping style for cluster",
Value: "star",
},
cli.BoolFlag{
Name: "utp",
Usage: "use utp for addresses",
},
cli.StringFlag{
Name: "cfg",
Usage: "override default config with values from the given file",
},
},
Action: func(c *cli.Context) {
if c.Int("count") == 0 {
fmt.Printf("please specify number of nodes: '%s init -n 10'\n", os.Args[0])
os.Exit(1)
}
cfg := &util.InitCfg{
Bootstrap: c.String("bootstrap"),
Force: c.Bool("f"),
Count: c.Int("count"),
Mdns: c.Bool("mdns"),
Utp: c.Bool("utp"),
PortStart: c.Int("port"),
Override: c.String("cfg"),
}
err := util.IpfsInit(cfg)
handleErr("ipfs init err: ", err)
},
}
var startCmd = cli.Command{
Name: "start",
Usage: "starts up all testbed nodes",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "wait",
Usage: "wait for nodes to fully come online before returning",
},
},
Action: func(c *cli.Context) {
err := util.IpfsStart(c.Bool("wait"))
handleErr("ipfs start err: ", err)
},
}
var killCmd = cli.Command{
Name: "kill",
Usage: "kill a given node (or all nodes if none specified)",
Aliases: []string{"stop"},
Action: func(c *cli.Context) {
if c.Args().Present() {
i, err := strconv.Atoi(c.Args()[0])
if err != nil {
fmt.Println("failed to parse node number: ", err)
os.Exit(1)
}
err = util.KillNode(i)
if err != nil {
fmt.Println("failed to kill node: ", err)
}
return
}
err := util.IpfsKillAll()
handleErr("ipfs kill err: ", err)
},
}
var restartCmd = cli.Command{
Name: "restart",
Usage: "kill all nodes, then restart",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "wait",
Usage: "wait for nodes to come online before returning",
},
},
Action: func(c *cli.Context) {
err := util.IpfsKillAll()
handleErr("ipfs kill err: ", err)
err = util.IpfsStart(c.Bool("wait"))
handleErr("ipfs start err: ", err)
},
}
var shellCmd = cli.Command{
Name: "shell",
Usage: "execs your shell with certain environment variables set",
Description: `Starts a new shell and sets some environment variables for you:
IPFS_PATH - set to testbed node 'n's IPFS_PATH
NODE[x] - set to the peer ID of node x
`,
Action: func(c *cli.Context) {
if !c.Args().Present() {
fmt.Println("please specify which node you want a shell for")
os.Exit(1)
}
n, err := strconv.Atoi(c.Args()[0])
handleErr("parse err: ", err)
err = util.IpfsShell(n)
handleErr("ipfs shell err: ", err)
},
}
var connectCmd = cli.Command{
Name: "connect",
Usage: "connect two nodes together",
Action: func(c *cli.Context) {
if len(c.Args()) < 2 {
fmt.Println("iptb connect [node] [node]")
os.Exit(1)
}
from, err := parseRange(c.Args()[0])
if err != nil {
fmt.Printf("failed to parse: %s\n", err)
return
}
to, err := parseRange(c.Args()[1])
if err != nil {
fmt.Printf("failed to parse: %s\n", err)
return
}
for _, f := range from {
for _, t := range to {
err = util.ConnectNodes(f, t)
if err != nil {
fmt.Printf("failed to connect: %s\n", err)
return
}
}
}
},
}
var getCmd = cli.Command{
Name: "get",
Usage: "get an attribute of the given node",
Action: func(c *cli.Context) {
if len(c.Args()) < 2 {
fmt.Println("iptb get [attr] [node]")
os.Exit(1)
}
attr := c.Args().First()
num, err := strconv.Atoi(c.Args()[1])
handleErr("error parsing node number: ", err)
val, err := util.GetAttr(attr, num)
handleErr("error getting attribute: ", err)
fmt.Println(val)
},
}
var dumpStacksCmd = cli.Command{
Name: "dump-stack",
Usage: "get a stack dump from the given daemon",
Action: func(c *cli.Context) {
if len(c.Args()) < 1 {
fmt.Println("iptb dump-stack [node]")
os.Exit(1)
}
num, err := strconv.Atoi(c.Args()[0])
handleErr("error parsing node number: ", err)
addr, err := util.GetNodesAPIAddr(num)
handleErr("failed to get api addr: ", err)
resp, err := http.Get("http://" + addr + "/debug/pprof/goroutine?debug=2")
handleErr("GET stack dump failed: ", err)
defer resp.Body.Close()
io.Copy(os.Stdout, resp.Body)
},
}

View File

@ -33,7 +33,10 @@ aggregate: clean-test-results $(T)
@echo "*** $@ ***"
lib/test-aggregate-results.sh
deps: $(SHARNESS) $(BINS) curl
global-deps:
make -C ../.. deps
deps: global-deps $(SHARNESS) $(BINS) curl
$(SHARNESS): FORCE
@echo "*** checking $@ ***"