-
Notifications
You must be signed in to change notification settings - Fork 39
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
interface'ifying things #61
Conversation
main.go
Outdated
killCmd, | ||
restartCmd, | ||
setCmd, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
where is set going?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hopefully nowhere. A lot of code is being stripped to just limit the total amount of code that needs to be rewritten to get things working. Both setCmd
and getCmd
will be coming back in, as well as the flags I stripped from init
in some way.
With the latest updates though the IPFS local plugin actually works. Some code massaging needs to take place as a few things are a bit ruff around the edges.
- Proper plugin loading
- Better command output handling
@travisperson could you take a look at incorporating these changes too while youre at it? 08f0993 It separates the init process into two steps (optionally) then makes the normal init process explicitly do both. This will make certain setups easier to play with in the future. |
@whyrusleeping ah nice. Ya should be easy to incorporate. |
testbed/spec.go
Outdated
} | ||
|
||
plugs, err := ioutil.ReadDir(dir) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style nit: don't put spaces between creating and checking an error
testbed/spec.go
Outdated
|
||
PluginName := *(PluginNameSym.(*string)) | ||
|
||
plugins[PluginName] = iptbplugin{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably want to check if a plugin by this name exists already
We should make sure its possible to build iptb by default with support for some 'default plugins'. I want to not have to worry about where my ipfs plugin is located |
Building in some plugins is a great idea, I updated the current "plugins" to get built into the binary and allow for them to be overridden. Also exposed them as a plugin package for easy hacking / building your own 🔨 |
plugins/ipfs/util.go
Outdated
return []string{attrId, attrPath, attrBwIn, attrBwOut} | ||
} | ||
|
||
func GetAttrDesc(attr string) (string, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate code?
testbed/interfaces/node.go
Outdated
type GetAttrDescFunc func(attr string) (string, error) | ||
|
||
// TestbedNode specifies the interface to a process controlled by iptb | ||
type TestbedNode interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface is getting pretty big, I wonder if we should break it up, and make some of the methods optional (by specialization, or similar)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return types and parameters are a little off, but a rough idea:
https://gist.github.com/frrist/01405d6b36aae85108fad80c2c40d3fb
plugins/ipfs/docker/dockeripfs.go
Outdated
) | ||
|
||
func init() { | ||
NewNode = func(dir string, extras map[string]interface{}) (testbedi.TestbedNode, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't have to assign these like this, it should work the same if you just define it as:
func NewNode(dir string, extras map[string]interface{}) (testbedi.TestbedNode, error) {
...
...
}
main.go
Outdated
"fmt" | ||
"io" | ||
"net/http" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: whitespace
main.go
Outdated
Action: func(c *cli.Context) error { | ||
if c.Int("count") == 0 { | ||
fmt.Printf("please specify number of nodes: '%s init -n 10'\n", os.Args[0]) | ||
os.Exit(1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets return errors for these and have the exit here
testbed/testbed.go
Outdated
return nil | ||
} | ||
|
||
err = os.RemoveAll(dir) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can just return os.RemoveALl(dir)
here
testbed/testbed.go
Outdated
|
||
for i := 0; i < count; i++ { | ||
dir := path.Join(base, fmt.Sprint(i)) | ||
err := os.MkdirAll(dir, 0775) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: combine with if
testbed/testbed.go
Outdated
return nil, err | ||
} | ||
|
||
var spec *NodeSpec |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I don't think this is necessary
main.go
Outdated
Usage: "stream events from a given node", | ||
Action: func(c *cli.Context) error { | ||
if len(c.Args()) != 1 { | ||
return fmt.Errorf("'iptb logs' accepts at exactly 1 argument") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iptb logs events
main.go
Outdated
@@ -598,3 +822,34 @@ var logsCmd = cli.Command{ | |||
return nil | |||
}, | |||
} | |||
|
|||
var eventsCmd = cli.Command{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this!
plugins/ipfs/docker/dockeripfs.go
Outdated
return nil, fmt.Errorf("error getting env: %s", err) | ||
} | ||
|
||
cmd := exec.Command(l.repobuilder, "init") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can use exec.CommandContext
here
testbed/testbed.go
Outdated
defer wait.Done() | ||
_, err := nd.Init(context.TODO()) | ||
if err != nil { | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should try and avoid panics, could use an error channel here. We could also just do this in a loop without a go-routine.
main.go
Outdated
if err != nil { | ||
return err | ||
} | ||
|
||
out, err := nd.RunCmd(c.Args()[1:]...) | ||
out, err := nd.RunCmd(context.TODO(), c.Args()[1:]...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can pass a context with a timeout here
plugins/ipfs/docker/dockeripfs.go
Outdated
return fmt.Errorf("node is already running") | ||
} | ||
|
||
cmd := exec.Command("docker", "run", "-d", "-v", l.dir+":/data/ipfs", l.image) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting future work here would be to use the docker api package: https://docs.docker.com/develop/sdk/#sdk-and-api-quickstart
Before merging, let's make sure that the tests all pass, and that if we use this in the go-ipfs sharness tests, they all still pass |
289baf9
to
fd43b32
Compare
commands/attr.go
Outdated
|
||
tb := testbed.NewTestbed(path.Join(flagRoot, "benches", flagTestbed)) | ||
|
||
if flagSave { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we first attempt to set the attribute on the node before persisting it to the nodespec file?
commands/fast.go
Outdated
} | ||
|
||
runCmd := func(node testbedi.Core) (testbedi.TBOutput, error) { | ||
return node.Init(context.TODO(), ([]string{})...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can remove ([]string{})...
}, | ||
}, | ||
Before: func(c *cli.Context) error { | ||
if present := isTerminatorPresent(c); present { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's leave a comment describing what terminator
means
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a comment on isTerminatorPresent
as this is used on any command which takes a node range.
results[i] = Result{ | ||
Node: n, | ||
Output: out, | ||
Error: errors.Wrapf(err, "node[%d]", n), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this this be incorrect if list
is a range like [4-8]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep!
d487790
to
b55e21f
Compare
e82eb61
to
451df6b
Compare
451df6b
to
dcd10d7
Compare
To make sure everything was working correctly I did a quick update to go-ipfs sharness tests as well using the new cli. You can see those changes here https://github.com/ipfs/go-ipfs/compare/master...travisperson:update-iptb?expand=1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly random suggestions and interface comments. Overall, this looks like a reasonable design.
README.md
Outdated
dump-stack get a stack dump from the given daemon | ||
help, h show a list of subcommands, or help for a specific subcommand | ||
fast create default bench and initialize | ||
bench create, remove, list bench setups |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"manage test (?) bench setups". I assume these aren't benchmarks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya, not benchmarks, just different setups. I'll try to make that clear. There is some discussion around the introduction of bench
in issue #62. Basically this stemmed from having both a init
and a create
command, and trying to make it less ambiguous as to which to run.
The thought was to place the concept of "create" under a category, and a suggestion was made to call them benches
, like having a toolbench where you would work on something.
In the current implementation init
no longer makes the node specification. Instead it's a direct map to the Init
method on the node interface. This allows iptb to have it's own configuration (defining number of nodes, types, etc), and still exposing the direct call to the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bench
is really unfortunate name, I think pretty much anything would be better, given its strong association with benchmarks
README.md
Outdated
connect connect two nodes together | ||
dump-stack get a stack dump from the given daemon | ||
help, h show a list of subcommands, or help for a specific subcommand | ||
fast create default bench and initialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"auto"? Or maybe just a iptb init --create[=default] --start
flags? "fast" makes me think you want IPTB to run fast, or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now there is iptb bench create [other flags] --init
. The fast
command was added (name mostly a placeholder, though auto
might be a good choice) to bring back the functionality of iptb init
, as currently it maps directly to the node interface method Init
. It would be nice to keep that exposed as a directly way to invoke that method without overloading it too much. This could also be fixed by changing out the Core#Init
method name something else, and keeping init
as the quick and easy way to get started with iptb.
Basically iptb fast
is almost a direct mapping to iptb bench create --init
, it just doesn't accept the idea of additional configuration through --attr
flags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for sth else than fast
, I do like the idea of using default
somehow
commands/connect.go
Outdated
for _, f := range from { | ||
for _, t := range to { | ||
ctx, cancel := context.WithTimeout(context.Background(), timeout) | ||
defer cancel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the timeout be applied to the entire command?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I'd also consider doing this in parallel anyways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but this can happen in a follow on PR
commands/connect.go
Outdated
Category: "CORE", | ||
Name: "connect", | ||
Usage: "connect nodes together", | ||
ArgsUsage: "<nodes> <nodes>", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also expect this command to take 1 arg (connecting all the nodes) and 0 args (connecting all nodes). Is there already another command for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, nothing like that yet. Sounds like a good addition though 👍
TotalOut int | ||
} | ||
|
||
func GetBW(l testbedi.Libp2p) (*BW, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well take a context for all of these functions up-front (unless I'm missing something about how they're supposed to be used).
testbed/testbed.go
Outdated
return NodesFromSpecs(specs) | ||
} | ||
|
||
func InitNodes(nodes []testbedi.Core, args ...string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just pass in the context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dead code actually, deleting...
testbed/spec.go
Outdated
} | ||
|
||
// SetAttr sets an attribute on the NodeSpec | ||
func (ns *NodeSpec) SetAttr(attr string, val interface{}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Attribute
interface takes/returns a string value. I assume these should match.
plugins/ipfs/docker/dockeripfs.go
Outdated
|
||
/// Core Interface | ||
|
||
func (l *Dockeripfs) Init(ctx context.Context, agrs ...string) (testbedi.Output, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/agrs/args.
plugins/ipfs/util.go
Outdated
return nil | ||
} | ||
|
||
func SwarmAddr(lt ListenType, addr string, port int) string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should really just use normal multiaddrs. This'll be a pain to maintain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya, actually that is a good idea. I just changed it so that the plugin itself can take an apiaddr
/ swarmaddr
, and the user can just throw in what ever they want.
They now just have defaults, and we can later be a little smarter and parse into and rewrite from the config to change individual values.
local
apiaddr
=> /ip4/127.0.0.1/tcp/0
swarmaddr
=> /ip4/127.0.0.1/tcp/0
local
apiaddr
=> /ip4/0.0.0.0/tcp/5001
swarmaddr
=> /ip4/0.0.0.0/tcp/4001
Note: we can also add profiles and such
Libp2p | ||
// Allows a node to run any initialization it may require | ||
// Ex: Installing additional dependencies / setting up configuration | ||
Init(ctx context.Context, args ...string) (Output, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume that "args" are additional command line arguments, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing major, mostly small things that could make things a bit nicer.
One thing I noticed, while the interfaces are nicely documented a lot of the rest of the code doesn't have comments on methods, which makes it a bit harder to read & understand, than necessary.
Overall this is a big improvement 💯
README.md
Outdated
@@ -1,22 +1,19 @@ | |||
# IPTB | |||
|
|||
`iptb` is a program used to create and manage a cluster of sandboxed IPFS nodes locally on your computer. Spin up 1000s of nodes! It exposes various options, such as different bootstrapping patterns. `iptb` makes testing IPFS networks easy! | |||
`iptb` is a program used to create and manage a cluster of sandboxed IPFS nodes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the idea was to allow for other things than IPFS as well, so maybe make this description a bit more generic?
README.md
Outdated
connect connect two nodes together | ||
dump-stack get a stack dump from the given daemon | ||
help, h show a list of subcommands, or help for a specific subcommand | ||
fast create default bench and initialize |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for sth else than fast
, I do like the idea of using default
somehow
README.md
Outdated
dump-stack get a stack dump from the given daemon | ||
help, h show a list of subcommands, or help for a specific subcommand | ||
fast create default bench and initialize | ||
bench create, remove, list bench setups |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bench
is really unfortunate name, I think pretty much anything would be better, given its strong association with benchmarks
README.md
Outdated
``` | ||
|
||
### Install | ||
|
||
`iptb` uses [gx](https://github.com/whyrusleeping/gx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we make it such that it also works without gx, pretty please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can do that as long as we drop the ipfs
plugins from being built into the binary by default due to its heavy use of gx. Currently the go-libp2p
package needs to be versioned.
commands/connect.go
Outdated
var ConnectCmd = cli.Command{ | ||
Category: "CORE", | ||
Name: "connect", | ||
Usage: "connect nodes together", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great to have a little more text here, with some examples. I was really unclear on how this works, especially with ranges, until I saw a demo from @whyrusleeping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I propose we address this in a follow on PR since similar changes will likely be required.
plugins/ipfs/local/localipfs.go
Outdated
} | ||
|
||
func (l *Localipfs) Shell(ctx context.Context, nodes []testbedi.Core) error { | ||
shell := os.Getenv("SHELL") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice if these env variables are global constants, such that other plugins could reuse them
testbed/interfaces/node.go
Outdated
type Attribute interface { | ||
Core | ||
// GetAttr returns the value of attr | ||
GetAttr(attr string) (string, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is inconsistent, with both go best practices and the metric interface, and should be just Attr
and SetAttr
.
testbed/interfaces/node.go
Outdated
// Ex: Installing additional dependencies / setting up configuration | ||
Init(ctx context.Context, args ...string) (Output, error) | ||
// Starts the node | ||
Start(ctx context.Context, wait bool, args ...string) (Output, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing explanation of what wait
does
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it needs to be removed actually. At the moment it doesn't serve much of a purpose. We can add it back if we find that it's actually needed for something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I guess start has a purpose still. It can be to wait for the node to be reachable (api online). Stop is the one that doesn't really fit at the moment. It was added per a mention in #10, but I can't seem to think why it would be needed.
testbed/interfaces/node.go
Outdated
Shell(ctx context.Context, ns []Core) error | ||
|
||
// Writes a log line to stdout | ||
Infof(format string, args ...interface{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why does a plugin need to implement this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was thinking that this one could probably be left off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya, I think we talked about this previously, it can be dropped. Original thought was to make it easier to use the interface in other applications (embedded iptb), and provide logging.
// Examples localipfs, dockeripfs, etc. | ||
Type() string | ||
|
||
String() string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is String
supposed to do/where is it useful?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String is a builtin go interface. It defines how this object gets printed if someone passes it to a Printf
type function
018fefc
to
ae7b7d1
Compare
' | ||
|
||
test_expect_success "iptb stop works" ' | ||
../bin/iptb stop | ||
../bin/iptb stop && sleep 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could have iptb sit around and wait for the processes to be really dead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
at least make an issue for it, fine to fix later
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very large PR, i'm not going to be able to review in-depth, but i trust you two to do the right thing. Let's get this merged, and try to integrate things upwards, fixing any issues discovered along the way.
@Stebalien @dignifiedquire @whyrusleeping Is there any other feedback that should block this PR? There is additional work I want to do to the plugins. I can remove that code from this PR, or simply follow up. |
60c8209
to
34b6f51
Compare
34b6f51
to
5e19097
Compare
What's in the PR?