In this post I want to create my own kubectl exec command in GO. Kubernetes
provides a nice SDK called
client-go. It allows you to write
your own controllers, watch for changes, do REST calls against the API-Server
and much more. However, until
client-go/#45 is resolved,
it is not possible to use the Websocket endpoints of the API-Server out of the
box. This is especially annoying if you want to write a Websocket client, which
can connect to arbitrary secured API-Servers. The
Authenticating page shows
what the API-Server currently supports, and writing a client on your own, which
supports all these authentication mechanisms, does definitely not scale.
Luckily client-go gives you all the low-level tools to reuse all negotiation
code for your Websocket connection. Client-go allows, to create your own
http.RoundTripper, which you can
then wrap with rest.HTTPWrappersForConfig(config, myRoundTripper). The
wrapping RoundTrippers will make sure to do preflight requests, and add all
necessary security headers to your request. Further, via
rest.TLSConfigFor(config), a tls.Config can be requested and set on our
custom request. It is also worth noting, that with RoundTrippers it is not
possible to get the underlying connection after the invokation. To solve this,
we can do our work on the Websocket via a callback inside the RoundTripper.
Now let’s start with wrapping a gorilla/websocket connection with our custom
RoundTripper:
All this does, is taking the connection details and the header from the
provided request, tries to establish a Websocket connection, and forwards the
result, to a callback RoundTripCallback. At this stage, we can
expect that the API-Server security negotiations are already done, and that we
just care about the additional security headers.
Next, a callback, which prints out the response of our command, executed in the
pod, is needed:
It reads the response from the API-Server and prints the result to stdout, once
the connection is closed. Now that the receiving part is done, we can think about
constructing the actual exec request:
This will create a GET request, with all the necessary query parameters
attached, to execute an arbitrary command inside a Pod.
Finally the wrapped RoundTripper can be constructed:
In this function, all the wiring based on a provided rest.Config happens.
First the TLS configuration is constructed and passed to the Websocket dialer.
Then the Websocket RoundTripper is constructed and wrapped by the Kubernetes
RoundTrippers. Now only the main method is missing:
If I now run ls in the virt-api Pod on my KubeVirt development environment,