Skip to content

Commit

Permalink
Merge pull request #144 from jbenet/bootstrap-cmd
Browse files Browse the repository at this point in the history
bootstrap cmd
  • Loading branch information
jbenet committed Oct 6, 2014
2 parents 874d612 + abefd93 commit 501030f
Show file tree
Hide file tree
Showing 3 changed files with 281 additions and 10 deletions.
254 changes: 254 additions & 0 deletions cmd/ipfs/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
package main

import (
"errors"
"strings"

"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/gonuts/flag"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/commander"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"

config "github.com/jbenet/go-ipfs/config"
peer "github.com/jbenet/go-ipfs/peer"
u "github.com/jbenet/go-ipfs/util"
)

var cmdIpfsBootstrap = &commander.Command{
UsageLine: "bootstrap",
Short: "Show a list of bootstrapped addresses.",
Long: `ipfs bootstrap - show, or manipulate bootstrap node addresses
Running 'ipfs bootstrap' with no arguments will run 'ipfs bootstrap list'.
Commands:
list Show the boostrap list.
add <address> Add a node's address to the bootstrap list.
remove <address> Remove an address from the bootstrap list.
` + bootstrapSecurityWarning,
Run: bootstrapListCmd,
Subcommands: []*commander.Command{
cmdIpfsBootstrapRemove,
cmdIpfsBootstrapAdd,
cmdIpfsBootstrapList,
},
Flag: *flag.NewFlagSet("ipfs-bootstrap", flag.ExitOnError),
}

var cmdIpfsBootstrapRemove = &commander.Command{
UsageLine: "remove <address | peerid>",
Short: "Remove addresses from the bootstrap list.",
Long: `ipfs bootstrap remove - remove addresses from the bootstrap list
` + bootstrapSecurityWarning,
Run: bootstrapRemoveCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-remove", flag.ExitOnError),
}

var cmdIpfsBootstrapAdd = &commander.Command{
UsageLine: "add <address | peerid>",
Short: "Add addresses to the bootstrap list.",
Long: `ipfs bootstrap add - add addresses to the bootstrap list
` + bootstrapSecurityWarning,
Run: bootstrapAddCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-add", flag.ExitOnError),
}

var cmdIpfsBootstrapList = &commander.Command{
UsageLine: "list",
Short: "Show addresses in the bootstrap list.",
Run: bootstrapListCmd,
Flag: *flag.NewFlagSet("ipfs-bootstrap-list", flag.ExitOnError),
}

func bootstrapRemoveCmd(c *commander.Command, inp []string) error {

if len(inp) == 0 {
return errors.New("remove: no address or peerid specified")
}

toRemove, err := bootstrapInputToPeers(inp)
if err != nil {
return err
}

cfg, err := getConfig(c)
if err != nil {
return err
}

keep := []*config.BootstrapPeer{}
remove := []*config.BootstrapPeer{}

// function to filer what to keep
shouldKeep := func(bp *config.BootstrapPeer) bool {
for _, skipBP := range toRemove {

// IDs must match to skip.
if bp.PeerID != skipBP.PeerID {
continue
}

// if Addresses match, or skipBP has no addr (wildcard)
if skipBP.Address == bp.Address || skipBP.Address == "" {
return false
}
}
return true
}

// filter all the existing peers
for _, currBP := range cfg.Bootstrap {
if shouldKeep(currBP) {
keep = append(keep, currBP)
} else {
remove = append(remove, currBP)
}
}

// if didn't remove anyone, bail.
if len(keep) == len(cfg.Bootstrap) {
return errors.New("remove: peer given did not match any in list")
}

// write new config
cfg.Bootstrap = keep
if err := writeConfig(c, cfg); err != nil {
return err
}

for _, bp := range remove {
u.POut("removed %s\n", bp)
}
return nil
}

func bootstrapAddCmd(c *commander.Command, inp []string) error {

if len(inp) == 0 {
return errors.New("add: no address specified")
}

toAdd, err := bootstrapInputToPeers(inp)
if err != nil {
return err
}

cfg, err := getConfig(c)
if err != nil {
return err
}

// function to check whether a peer is already in the list.
combine := func(lists ...[]*config.BootstrapPeer) []*config.BootstrapPeer {

set := map[string]struct{}{}
final := []*config.BootstrapPeer{}

for _, list := range lists {
for _, peer := range list {
// if already in the set, continue
_, found := set[peer.String()]
if found {
continue
}

set[peer.String()] = struct{}{}
final = append(final, peer)
}
}
return final
}

// combine both lists, removing dups.
cfg.Bootstrap = combine(cfg.Bootstrap, toAdd)
if err := writeConfig(c, cfg); err != nil {
return err
}

for _, bp := range toAdd {
u.POut("added %s\n", bp)
}
return nil
}

func bootstrapListCmd(c *commander.Command, inp []string) error {

cfg, err := getConfig(c)
if err != nil {
return err
}

for _, bp := range cfg.Bootstrap {
u.POut("%s\n", bp)
}

return nil
}

func writeConfig(c *commander.Command, cfg *config.Config) error {

confdir, err := getConfigDir(c)
if err != nil {
return err
}

filename, err := config.Filename(confdir)
if err != nil {
return err
}

return config.WriteConfigFile(filename, cfg)
}

func bootstrapInputToPeers(input []string) ([]*config.BootstrapPeer, error) {
split := func(addr string) (string, string) {
idx := strings.LastIndex(addr, "/")
if idx == -1 {
return "", addr
}
return addr[:idx], addr[idx+1:]
}

peers := []*config.BootstrapPeer{}
for _, addr := range input {
addrS, peeridS := split(addr)

// make sure addrS parses as a multiaddr.
if len(addrS) > 0 {
maddr, err := ma.NewMultiaddr(addrS)
if err != nil {
return nil, err
}

addrS, err = maddr.String()
if err != nil {
return nil, err
}
}

// make sure idS parses as a peer.ID
peerid, err := mh.FromB58String(peeridS)
if err != nil {
return nil, err
}

// construct config entry
peers = append(peers, &config.BootstrapPeer{
Address: addrS,
PeerID: peer.ID(peerid).Pretty(),
})
}
return peers, nil
}

const bootstrapSecurityWarning = `
SECURITY WARNING:
The bootstrap command manipulates the "bootstrap list", which contains
the addresses of bootstrap nodes. These are the *trusted peers* from
which to learn about other peers in the network. Only edit this list
if you understand the risks of adding or removing nodes from this list.
`
33 changes: 23 additions & 10 deletions cmd/ipfs/ipfs.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package main

import (
"errors"
"fmt"
"os"
"runtime/pprof"
Expand Down Expand Up @@ -51,6 +50,7 @@ Use "ipfs help <command>" for more information about a command.
cmdIpfsMount,
cmdIpfsInit,
cmdIpfsServe,
cmdIpfsBootstrap,
},
Flag: *flag.NewFlagSet("ipfs", flag.ExitOnError),
}
Expand Down Expand Up @@ -105,17 +105,30 @@ func localNode(confdir string, online bool) (*core.IpfsNode, error) {
// Gets the config "-c" flag from the command, or returns
// the default configuration root directory
func getConfigDir(c *commander.Command) (string, error) {
conf := c.Flag.Lookup("c").Value.Get()
if conf == nil {
return config.PathRoot()

// use the root cmd (that's where config is specified)
for ; c.Parent != nil; c = c.Parent {
}

// flag should be defined on root.
param := c.Flag.Lookup("c").Value.Get().(string)
if param != "" {
return u.TildeExpansion(param)
}
confStr, ok := conf.(string)
if !ok {
return "", errors.New("failed to retrieve config flag value.")

return config.PathRoot()
}

func getConfig(c *commander.Command) (*config.Config, error) {
confdir, err := getConfigDir(c)
if err != nil {
return nil, err
}
if len(confStr) == 0 {
return config.PathRoot()

filename, err := config.Filename(confdir)
if err != nil {
return nil, err
}

return u.TildeExpansion(confStr)
return config.Load(filename)
}
4 changes: 4 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ type BootstrapPeer struct {
PeerID string // until multiaddr supports ipfs, use another field.
}

func (bp *BootstrapPeer) String() string {
return bp.Address + "/" + bp.PeerID
}

// Config is used to load IPFS config files.
type Config struct {
Identity Identity // local node's peer identity
Expand Down

0 comments on commit 501030f

Please sign in to comment.