Once upon a time I was need to configure a CI for a private github repo. Public CI providers such as Travis, CircleCI and other don't provide free plans for private repos. Besides tests I wanted to run are not publicly available. So I decided to provision a Jenkins server inside corporate VPN. How to trigger a pipeline on PR? Github provides a webhooks mechanism. Generally speaking it's a just HTTP request with some payload. And here we have a problem. How to pass a github webhook to the Jenkins which is not exposed to the Internet?
The dumbest solution would be just not use webhooks. Jenkins can be configured to poll a certain repository to check if there are some new PRs.
More elegant way is somehow to pass webhooks inside corporate VPN.
I'm not keen on polling and prefer "push" over it. I started to search if there are some services that solve my problem. As I expected I'm not the only one with such problem and some companies have implemented so-called webhook forwarders. I found at least three such services:
One thing I should mention that Jenkins itself cannot connect to a webhook forwarder. There should be one more piece in the route. All these services also provides clients that connect to the server and then replay webhooks inside corporate network. Consider the following diagram:
I chose smee.io because both server and client are free and open source unlike other two. I created a route in smee.io and provisioned their client in our Openshift instance. It looked that the problem was solved.
I decided to write my own smee.io client implementation with two key features:
It must be distributed as a single binary without any dependencies.
One running instance of the client must forward multiple source-destination pairs.
This is how I came up to idea to create
xakac. A small utility written on golang that replays
webhooks which were sent by smee.io server. Golang perfectly fits to this task. Each
source-destination pair works in a separate goroutine and source code is compiling into one small
executable file without dependencies.
You may ask what does xakac mean? It's a transliteration of russian word хакас (khakas). It's native people of the place where I came from. By the way you can find the code here:
It was a good exercise for me and my
xakac works fine except one thing. Sometimes connection
between client and server can suddenly be closed and in the logs I can see this error:
I need to figure out how to handle this situation and automatically reconnect a failed route.