Skip to content
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

Plugin Architecture #1

Closed
mitchellh opened this issue Apr 27, 2013 · 4 comments
Closed

Plugin Architecture #1

mitchellh opened this issue Apr 27, 2013 · 4 comments
Assignees
Milestone

Comments

@mitchellh
Copy link
Contributor

We need a plugin architecture in place. Because Golang doesn't support dynamic linking of any kind, we'll have to use IPC for this. To keep things as simple as possible, let's go with the net/rpc package to get this done.

Ideas:

  • Given a binary, such as packer-build, the plugin lib must execute the underlying executable using os/exec or whatever. It must then initiate and abstract the RPC stuff.
  • To most of Packer, plugins must appear just as normal implementers of interfaces such as Command or Builder. Keep it simple!
  • Multiple packer instances must be able to run at one time, so static ports for listening on RPC is not possible.

Other notes:

  • I had an idea to use stdin/stdout for the communication mechanism for net/rpc. If this gets done, can the plugin call back into Packer? There are cases where this is necessary, so it is important that is possible.
@mitchellh mitchellh mentioned this issue Apr 27, 2013
@mitchellh
Copy link
Contributor Author

So it looks like net/rpc is just one-way RPC. I googled and found some crazy ideas about muxing/demuxing multiple net.Conn onto a single one, but that sounds incredibly complicated and... yeah.

Instead, I think we should just open two connections (one from core to the plugin, and one from plugin to the core). If either of these is dead, the whole plugin connection is severed (panic?).

Given that, we can't use stdin/stdout. We have to use TCP sockets. Another option would be to use named pipes. This would be super rad but is poorly supported on Windows. I think the safest thing to do would be to just use TCP sockets.

@mitchellh
Copy link
Contributor Author

So here is an idea for how to use TCP ports.

  • Have a range of usable ports, configurable. The "server" attempts to bind to these ports in order until it successfully binds at some point.
  • Packer core gets the range from the global config file (Global configuration file #9) and attempts to bind when it starts. Attached to an Environment? Maybe.
  • Plugins get the range from stdin (maybe two args, min/max). They attempt to bind and output the port they bound to on STDOUT. The plugin runner (core) reads this connects over that port.
  • Plugins get the port of the core from stdin as well.
  • Plugins should probably have some sort of "magic cookie" that is the first argument. If this isn't the first argument, show a human-friendly error message about the plugin being a Packer plugin, and not meant to be invoked directly. This can just be some well known cookie we document well.

@mitchellh
Copy link
Contributor Author

I've started implementing the RPC mechanism for Command in 575489f. The pieces that make it work:

  • RPCServerCommand is a struct that wraps a Command and exposes it as a net/rpc friendly interface. It translates that interface down into actual Command method calls, and back out as proper return values.
  • RPCClientCommand is a valid implementation of Command that has an rpc.Client and makes the proper remote RPC calls to talk to the command and returns the proper values.

This is all tested and works so far! (See command_test.go).

These are the "low-level" interfaces/structs for the remote command stuff. I imagine there will be a construtor-like method on top like packer.NewPluginCommand that takes the binary name of the command plugin and orchestrates the entire setup of this whole thing, and returns a Command. :)

@ghost ghost assigned mitchellh May 5, 2013
@mitchellh
Copy link
Contributor Author

DONE, on a high level. There is still a lot of work to do in the space of error handling...

So the way this works is pretty neat. There are, as of this comment, three main packages:

  • packer contains the core interfaces, template parsing APIs, etc.
  • packer/rpc contains implementations of the core interfaces that are actually executed over an RPC connection. It also has exported functions to start a Golang RPC server for a given interface.
  • packer/plugin has the ability to "setup" a plugin by serving a specific interface. And it also contains a "Client" for executing certain interfaces over an RPC connection to a subprocess.

This separation makes it SUPER nice because:

  • packer doesn't need to care about RPC.
  • packer/rpc doesn't need to care about subprocessing or any craziness, it just focuses on making the core Packer interfaces RPC-able.
  • packer/plugin doesn't need to care about how to RPC interfaces, it just worries about connecting to and serving the RPC interfaces from a subprocess.

This makes a nice separation that makes working with this stuff quite nice.

mitchellh pushed a commit that referenced this issue Jul 25, 2013
mitchellh pushed a commit that referenced this issue Nov 5, 2013
mitchellh pushed a commit that referenced this issue Apr 28, 2014
mitchellh pushed a commit that referenced this issue Apr 28, 2014
rasa pushed a commit that referenced this issue Feb 16, 2015
Updating from official repo
mitchellh pushed a commit that referenced this issue Jun 15, 2015
marklap referenced this issue in marklap/packer Aug 7, 2015
kikitux added a commit that referenced this issue Oct 14, 2015
cbednarski pushed a commit that referenced this issue Jul 31, 2016
mwhooker pushed a commit that referenced this issue Feb 8, 2018
azr pushed a commit that referenced this issue Dec 20, 2018
SwampDragons pushed a commit that referenced this issue Feb 25, 2019
SwampDragons pushed a commit that referenced this issue Mar 4, 2019
chhaj5236 pushed a commit that referenced this issue Apr 13, 2019
SwampDragons pushed a commit that referenced this issue Jun 26, 2019
SwampDragons pushed a commit that referenced this issue Sep 17, 2019
scienty pushed a commit to scienty/packer that referenced this issue Sep 19, 2019
SwampDragons pushed a commit that referenced this issue Oct 11, 2019
SwampDragons pushed a commit that referenced this issue Oct 21, 2019
…#1)

* Adding config to specify allowed inbound IP addresses

* Also allowing CIDR blocks in addition to IP addresses
SwampDragons pushed a commit that referenced this issue Oct 21, 2019
…#1)

* Adding config to specify allowed inbound IP addresses

* Also allowing CIDR blocks in addition to IP addresses
SwampDragons pushed a commit that referenced this issue Mar 2, 2020
Synchronize fork from upstream repository
@ghost ghost locked and limited conversation to collaborators Apr 11, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant