init.go 5.01 KB
Newer Older
1
package main
Matt Bell's avatar
Matt Bell committed
2 3

import (
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
4
	"errors"
Brian Tiger Chow's avatar
Brian Tiger Chow committed
5
	"fmt"
6
	"io"
7 8
	"os"
	"path"
Matt Bell's avatar
Matt Bell committed
9

10 11 12 13 14 15 16
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
	assets "github.com/ipfs/go-ipfs/assets"
	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	namesys "github.com/ipfs/go-ipfs/namesys"
	config "github.com/ipfs/go-ipfs/repo/config"
	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
Matt Bell's avatar
Matt Bell committed
17 18
)

19
const nBitsForKeypairDefault = 2048
20

Matt Bell's avatar
Matt Bell committed
21
var initCmd = &cmds.Command{
22 23 24 25
	Helptext: cmds.HelpText{
		Tagline:          "Initializes IPFS config file",
		ShortDescription: "Initializes IPFS configuration files and generates a new keypair.",
	},
26

Matt Bell's avatar
Matt Bell committed
27
	Options: []cmds.Option{
28
		cmds.IntOption("bits", "b", fmt.Sprintf("Number of bits to use in the generated RSA private key (defaults to %d)", nBitsForKeypairDefault)),
29
		cmds.BoolOption("force", "f", "Overwrite existing config (if it exists)"),
30 31 32 33 34

		// TODO need to decide whether to expose the override as a file or a
		// directory. That is: should we allow the user to also specify the
		// name of the file?
		// TODO cmds.StringOption("event-logs", "l", "Location for machine-readable event logs"),
Matt Bell's avatar
Matt Bell committed
35
	},
36
	PreRun: func(req cmds.Request) error {
37 38 39 40
		daemonLocked, err := fsrepo.LockedByOtherProcess(req.Context().ConfigRoot)
		if err != nil {
			return err
		}
41 42 43 44 45 46 47 48 49

		log.Info("checking if daemon is running...")
		if daemonLocked {
			e := "ipfs daemon is running. please stop it to run this command"
			return cmds.ClientError(e)
		}

		return nil
	},
50
	Run: func(req cmds.Request, res cmds.Response) {
51 52 53 54
		if req.Context().Online {
			res.SetError(errors.New("init must be run offline only!"), cmds.ErrNormal)
			return
		}
55

56
		force, _, err := req.Option("f").Bool() // if !found, it's okay force == false
57
		if err != nil {
58 59
			res.SetError(err, cmds.ErrNormal)
			return
60 61
		}

62
		nBitsForKeypair, bitsOptFound, err := req.Option("b").Int()
63
		if err != nil {
64 65
			res.SetError(err, cmds.ErrNormal)
			return
66
		}
Henry's avatar
Henry committed
67

68
		if !bitsOptFound {
69
			nBitsForKeypair = nBitsForKeypairDefault
70 71
		}

72 73 74 75
		if err := doInit(os.Stdout, req.Context().ConfigRoot, force, nBitsForKeypair); err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}
76 77
	},
}
Matt Bell's avatar
Matt Bell committed
78

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
var errRepoExists = errors.New(`ipfs configuration file already exists!
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80 81 82 83
Reinitializing would overwrite your keys.
(use -f to force overwrite)
`)

84
func initWithDefaults(out io.Writer, repoRoot string) error {
85
	return doInit(out, repoRoot, false, nBitsForKeypairDefault)
86 87
}

88
func doInit(out io.Writer, repoRoot string, force bool, nBitsForKeypair int) error {
Henry's avatar
Henry committed
89
	if _, err := fmt.Fprintf(out, "initializing ipfs node at %s\n", repoRoot); err != nil {
90 91
		return err
	}
92

93 94 95 96
	if err := checkWriteable(repoRoot); err != nil {
		return err
	}

97
	if fsrepo.IsInitialized(repoRoot) && !force {
98
		return errRepoExists
99
	}
Henry's avatar
Henry committed
100

101
	conf, err := config.Init(out, nBitsForKeypair)
102
	if err != nil {
103
		return err
104
	}
Henry's avatar
Henry committed
105

106
	if fsrepo.IsInitialized(repoRoot) {
107
		if err := fsrepo.Remove(repoRoot); err != nil {
108
			return err
109
		}
110
	}
Henry's avatar
Henry committed
111

112
	if err := fsrepo.Init(repoRoot, conf); err != nil {
113
		return err
114
	}
115

116 117
	if err := addDefaultAssets(out, repoRoot); err != nil {
		return err
Jeromy's avatar
Jeromy committed
118
	}
119 120

	return initializeIpnsKeyspace(repoRoot)
121 122
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
func checkWriteable(dir string) error {
	_, err := os.Stat(dir)
	if err == nil {
		// dir exists, make sure we can write to it
		testfile := path.Join(dir, "test")
		fi, err := os.Create(testfile)
		if err != nil {
			if os.IsPermission(err) {
				return fmt.Errorf("%s is not writeable by the current user", dir)
			}
			return fmt.Errorf("unexpected error while checking writeablility of repo root: %s", err)
		}
		fi.Close()
		return os.Remove(testfile)
	}

	if os.IsNotExist(err) {
		// dir doesnt exist, check that we can create it
		return os.Mkdir(dir, 0775)
	}

	if os.IsPermission(err) {
		return fmt.Errorf("cannot write to %s, incorrect permissions", err)
	}

	return err
}

151
func addDefaultAssets(out io.Writer, repoRoot string) error {
152
	ctx, cancel := context.WithCancel(context.Background())
153
	defer cancel()
Henry's avatar
Henry committed
154

155 156
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
157 158
		return err
	}
Henry's avatar
Henry committed
159

160
	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
161
	if err != nil {
162
		return err
163 164 165
	}
	defer nd.Close()

166 167 168 169 170 171
	gwAkey, err := assets.SeedGatewayAssets(nd)
	if err != nil {
		return fmt.Errorf("init: seeding init docs failed: %s", err)
	}
	log.Debugf("init: seeded gateway assets %s", gwAkey)

Henry's avatar
Henry committed
172
	dkey, err := assets.SeedInitDocs(nd)
173
	if err != nil {
Henry's avatar
Henry committed
174
		return fmt.Errorf("init: seeding init docs failed: %s", err)
175 176
	}

Henry's avatar
Henry committed
177 178 179 180 181 182
	if _, err = fmt.Fprintf(out, "to get started, enter:\n"); err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "\n\tipfs cat /ipfs/%s/readme\n\n", dkey)
	return err
Matt Bell's avatar
Matt Bell committed
183
}
Brian Tiger Chow's avatar
Brian Tiger Chow committed
184

Jeromy's avatar
Jeromy committed
185 186 187 188
func initializeIpnsKeyspace(repoRoot string) error {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

189 190
	r, err := fsrepo.Open(repoRoot)
	if err != nil { // NB: repo is owned by the node
Jeromy's avatar
Jeromy committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204
		return err
	}

	nd, err := core.NewIPFSNode(ctx, core.Offline(r))
	if err != nil {
		return err
	}
	defer nd.Close()

	err = nd.SetupOfflineRouting()
	if err != nil {
		return err
	}

205
	return namesys.InitializeKeyspace(ctx, nd.DAG, nd.Namesys, nd.Pinning, nd.PrivateKey)
Jeromy's avatar
Jeromy committed
206
}