Notes from my presentation on Go plugins in 1.8
A Go plugin is essentially a shared object. We recognize these from our close neighbors: the C
and C++
programming languages.
Go plugin's are NOT part of the original program. They are standalone binaries that adhere to an ABI (Application Binary Interface) that another Go program can choose to attempt to run.
A Go program can choose to implement a Go plugin (remember this is a shared object or .so
file) at runtime. This is huge because we no longer have to recompile anything to drastically change the
behavior of a Go program.
golang:1.8
Docker Containermake
Which is essentially a wrapper for
docker run \
-i \
-t \
-v $GOPATH/src/github.com/kris-nova/go-plugin-demo:/go/src/github.com/kris-nova/go-plugin-demo \
-w /go/src/github.com/kris-nova/go-plugin-demo \
--rm
From the docker container we can go ahead and natively compile the main program, as well as all the plugins.
make build
By default we will be running plugin1
. Run the program with
make run
export PLUGIN_NUMBER=2
make run
Let's look at the Go source code here. The standard library has a Cgo
implementation!
#cgo linux LDFLAGS: -ldl
#include <dlfcn.h>
#include <limits.h>
#include <stdlib.h>
#include <stdint.h>
This includes the dlfcn.h
file, and uses the traditional Linux linking functions. As in this prototype:
#include <stdlib.h>
#include <stdio.h>
#include <dlfcn.h>
int main(int argc, char **argv) {
void *handle;
void (*run)();
char *error;
handle = dlopen ("../plugins/plugin1.so", RTLD_LAZY);
if (!handle) {
fputs (dlerror(), stderr);
printf("\n");
exit(1);
}
// Here we tell the handle to look for the known golang symbol.
run = dlsym(handle, "plugin/unnamed-4dc81edc69e27be0c67b8f6c72a541e65358fd88.init");
if ((error = dlerror()) != NULL) {
fputs(error, stderr);
printf("\n");
exit(1);
}
// Here we actually run the function (with no arguments) that we referenced earlier.
(*run)();
dlclose(handle);
}
This gives us a hint into how Go plugins work, and explains why they are only supported in Linux right now. They use POSIX dynamic loading more information.
Right now there is only support for handling the linux version in the C implementation. The good news is that there is already resources for building shared objects for Windows and other archtypes.
See the original plugin library proposal here.. We are now thinking about implementing a bring your own Go plugin model to kops
!
*.so
model... and use the filename as the plugin unique ID.