github.com/hashicorp/go-plugin@v1.6.0/docs/guide-plugin-write-non-go.md (about) 1 # Writing Plugins Without Go 2 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 6 using other languages! 7 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. 11 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). 15 16 ## 1. Implement the Service 17 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: 21 22 ```proto 23 service KV { 24 rpc Get(GetRequest) returns (GetResponse); 25 rpc Put(PutRequest) returns (Empty); 26 } 27 ``` 28 29 We can implement that using Python as easily as: 30 31 ```python 32 class KVServicer(kv_pb2_grpc.KVServicer): 33 """Implementation of KV service.""" 34 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() 40 return result 41 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: 46 f.write(value) 47 48 return kv_pb2.Empty() 49 50 ``` 51 52 Great! With that, we have a fully functioning implementation of the service. 53 You can test this using standard gRPC testing mechanisms. 54 55 ## 2. Serve the Service 56 57 Next, we need to create a gRPC server and serve the service we just made. 58 59 In Python: 60 61 ```python 62 # Make the server 63 server = grpc.server(futures.ThreadPoolExecutor(max_workers=10)) 64 65 # Add our service 66 kv_pb2_grpc.add_KVServicer_to_server(KVServicer(), server) 67 68 # Listen on a port 69 server.add_insecure_port(':1234') 70 71 # Start 72 server.start() 73 ``` 74 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. 78 79 ## 3. Add the gRPC Health Checking Service 80 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. 84 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. 88 89 ``` 90 health = HealthServicer() 91 health.set("plugin", health_pb2.HealthCheckResponse.ServingStatus.Value('SERVING')) 92 health_pb2_grpc.add_HealthServicer_to_server(health, server) 93 ``` 94 95 ## 4. Output Handshake Information 96 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. 100 101 102 The structure is: 103 104 ``` 105 CORE-PROTOCOL-VERSION | APP-PROTOCOL-VERSION | NETWORK-TYPE | NETWORK-ADDR | PROTOCOL 106 ``` 107 108 Where: 109 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. 113 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. 117 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". 121 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. 126 127 For our example that is: 128 129 ``` 130 1|1|tcp|127.0.0.1:1234|grpc 131 ``` 132 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 136 information. 137 138 ## 5. Done! 139 140 And we're done! 141 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. 145 146 For our example, we used an environmental variable, and it looks like this: 147 148 ```sh 149 $ export KV_PLUGIN="python plugin.py" 150 ```