1 # Writing Plugins Without Go
3 This guide explains how to write a go-plugin compatible plugin using
4 a programming language other than Go. go-plugin supports plugins using
5 [gRPC](http://www.grpc.io). This makes it relatively simple to write plugins
8 Minimal knowledge about gRPC is assumed. We recommend reading the
9 [gRPC Go Tutorial](http://www.grpc.io/docs/tutorials/basic/go.html). This
10 alone is enough gRPC knowledge to continue.
12 This guide will implement the kv example in Python.
13 Full source code for the examples present in this guide
14 [is available in the examples/grpc folder](https://github.com/hashicorp/go-plugin/tree/master/examples/grpc).
16 ## 1. Implement the Service
18 The first step is to implement the gRPC server for the protocol buffers
19 service that your plugin defines. This is a standard gRPC server.
20 For the KV service, the service looks like this:
24 rpc Get(GetRequest) returns (GetResponse);
25 rpc Put(PutRequest) returns (Empty);
29 We can implement that using Python as easily as:
32 class KVServicer(kv_pb2_grpc.KVServicer):
33 """Implementation of KV service."""
35 def Get(self, request, context):
36 filename = "kv_"+request.key
37 with open(filename, 'r') as f:
38 result = kv_pb2.GetResponse()
39 result.value = f.read()
42 def Put(self, request, context):
43 filename = "kv_"+request.key
44 value = "{0}\n\nWritten from plugin-python".format(request.value)
45 with open(filename, 'w') as f:
52 Great! With that, we have a fully functioning implementation of the service.
53 You can test this using standard gRPC testing mechanisms.
55 ## 2. Serve the Service
57 Next, we need to create a gRPC server and serve the service we just made.
63 server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
66 kv_pb2_grpc.add_KVServicer_to_server(KVServicer(), server)
69 server.add_insecure_port(':1234')
75 You can listen on any TCP address or Unix domain socket. go-plugin does
76 assume that connections are reliable (local), so you should not serve
77 your plugin across the network.
79 ## 3. Add the gRPC Health Checking Service
81 go-plugin requires the
82 [gRPC Health Checking Service](https://github.com/grpc/grpc/blob/master/doc/health-checking.md)
83 to be registered on your server. You must register the status of "plugin" to be SERVING.
85 The health checking service is used by go-plugin to determine if everything
86 is healthy with the connection. If you don't implement this service, your
87 process may be abruptly restarted and your plugins are likely to be unreliable.
90 health = HealthServicer()
91 health.set("plugin", health_pb2.HealthCheckResponse.ServingStatus.Value('SERVING'))
92 health_pb2_grpc.add_HealthServicer_to_server(health, server)
95 ## 4. Output Handshake Information
97 The final step is to output the handshake information to stdout. go-plugin
98 reads a single line from stdout to determine how to connect to your plugin,
99 what protocol it is using, etc.
105 CORE-PROTOCOL-VERSION | APP-PROTOCOL-VERSION | NETWORK-TYPE | NETWORK-ADDR | PROTOCOL
110 * `CORE-PROTOCOL-VERSION` is the protocol version for go-plugin itself.
111 The current value is `1`. Please use this value. Any other value will
112 cause your plugin to not load.
114 * `APP-PROTOCOL-VERSION` is the protocol version for the application data.
115 This is determined by the application. You must reference the documentation
116 for your application to determine the desired value.
118 * `NETWORK-TYPE` and `NETWORK-ADDR` are the networking information for
119 connecting to this plugin. The type must be "unix" or "tcp". The address
120 is a path to the Unix socket for "unix" and an IP address for "tcp".
122 * `PROTOCOL` is the named protocol that the connection will use. If this
123 is omitted (older versions), this is "netrpc" for Go net/rpc. This can
124 also be "grpc". This is the protocol that the plugin wants to speak to
125 the host process with.
127 For our example that is:
130 1|1|tcp|127.0.0.1:1234|grpc
133 The only element you'll have to be careful about is the second one (the
134 `APP-PROTOCOL-VERISON`). This will depend on the application you're
135 building a plugin for. Please reference their documentation for more
142 Configure the host application (the application you're writing a plugin
143 for) to execute your Python application. Configuring plugins is specific
144 to the host application.
146 For our example, we used an environmental variable, and it looks like this:
149 $ export KV_PLUGIN="python plugin.py"