|
| 1 | +# Why Chatops RPC? |
| 2 | + |
| 3 | +Chatops RPC is distilled from several years' experience working with Chatops |
| 4 | +at GitHub. The protocol is simple and will not cover every use case, but |
| 5 | +internal adoption has been excellent. |
| 6 | + |
| 7 | +### What came first |
| 8 | + |
| 9 | +#### Hubot |
| 10 | + |
| 11 | +Our first generation of chatops were written directly as Hubot scripts. These |
| 12 | +work fine for situations where there's an existing API that's well-supported. |
| 13 | +But if the API wasn't designed to do what the chat command wanted, a single |
| 14 | +command might end up making several REST API calls, with all the associated |
| 15 | +error handling, responses, etc. REST API endpoints created explicitly for chat |
| 16 | +commands tended to be challenging to test end-to-end, since lots of the |
| 17 | +logic would end up wrapped in hubot and outputting chat-adapter-specific things. |
| 18 | + |
| 19 | +#### Shell |
| 20 | + |
| 21 | +Next we wrote a bridge from a pile of shell scripts to hubot. This had great |
| 22 | +adoption, but it had its own problems. Security contexts were often mixed up |
| 23 | +with each other, so there were very poor boundaries between what access tokens |
| 24 | +a script needed and had available. Several different services made more |
| 25 | +sense being written as shell, ruby, python, go, and more, and this mishmash |
| 26 | +meant that in practice very little code was reused or tested. |
| 27 | + |
| 28 | +#### The pattern |
| 29 | + |
| 30 | +Over time, we settled on a new pattern: direct hubot bindings to API endpoints |
| 31 | +written just for hubot. This resulted in a few services with a few hundred |
| 32 | +lines of boilerplate node, wrapping API calls. |
| 33 | + |
| 34 | +This pattern was a winner, though. Servers were able to test their commands |
| 35 | +end-to-end, missing out only on the regular expressions that might trigger a |
| 36 | +command. Responses and changes to state could be tested in one place. |
| 37 | + |
| 38 | +Chatops RPC is a distillation and protocol around the last pattern of RPC |
| 39 | +endpoints with a one-to-one mapping to a chat command. |
| 40 | + |
| 41 | +### Authentication |
| 42 | + |
| 43 | +Chatops RPC servers need to trust the username that the chat bridge gives them. |
| 44 | +This means that a shared token gives servers the ability to misrepresent users |
| 45 | +with other servers. In this case, there's a lot of trust built in to the chat |
| 46 | +bridge, and we find this maps well to the asymmetric crypto authentication. |
| 47 | + |
| 48 | +### Keyword Arguments |
| 49 | + |
| 50 | +We pair this system with <https://github.com/github/hubot-chatops-rpc>, which |
| 51 | +provides generic argument support for long arguments, like `--argument foo`. |
| 52 | +While regexes create much more natural commands, rarely used options tend to |
| 53 | +create ugly regexes that are hard to test. If a command can potentially take 10 |
| 54 | +arguments, it's almost certain the regex will have unhandled edge cases. Generic |
| 55 | +arguments provide an easy way to take rarely-used options. These are not part |
| 56 | +of the Chatops RPC protocol but it's highly recommended to use a client that |
| 57 | +supports them. |
| 58 | + |
| 59 | +Keyword arguments are also important for searching chat history. In the past, we |
| 60 | +had several commands that had strange regex forms for different operations. It's |
| 61 | +hard to find examples to use these unusual forms. For example, `.deploy!` has |
| 62 | +become `.deploy --force`, which is much clearer for new employees and easier to |
| 63 | +find examples of. |
| 64 | + |
| 65 | +### Testing |
| 66 | + |
| 67 | +Highly testable patterns were a core consideration of Chatops RPC. GitHub had |
| 68 | +grown quite dependent on Chatops as a core part of its workflow, but a very |
| 69 | +large number of them were not tested. We've had several instances of important |
| 70 | +but rarely-used chat operations failing during availability incidents. Chatops |
| 71 | +RPC brings the entire flow to the server, and this results in highly testable |
| 72 | +operations that will work when they need to. |
| 73 | + |
| 74 | +### Prefixes |
| 75 | + |
| 76 | +Prefixes provide a way for more than one of the same endpoint to coexist. Over |
| 77 | +the years, we've had several systems with staging environments or other |
| 78 | +contexts. Ad-hoc solutions, unique to each, were created, forcing developers to |
| 79 | +learn new ways to manage the context of multiple chat-connected systems. |
| 80 | + |
| 81 | +Prefixes provide a way to have two systems, such as `.deploy` and |
| 82 | +`.deploy-staging` for a staging deployments system. Prefixes also provide a way |
| 83 | +to interface with endpoints that are associated with a resource they manage. For |
| 84 | +example, if your site has multiple kubernetes clusters, perhaps a server to |
| 85 | +manage each would be stood up, one per cluster, each including the cluster |
| 86 | +name in the prefix. This allows you to write "manage kubernetes cluster" once |
| 87 | +but have `.kubectl@cluster1 list pods` and `.kubectl@cluster2 list pods`. |
| 88 | + |
| 89 | +Internally, we use Hubot middleware to alias some very commonly used commands |
| 90 | +to shorter versions that do not use the same prefix. |
0 commit comments