This page summarises my recent contributions to Coder of a feature called Workspace Presets, which simplifies the experience of provisioning new cloud development environments for end user developers.
Pull Requests
My contributions to Coder’s workspace presets are mostly encapsulated by the following pull requests. Smaller subsequent pull requests corrected some small oversights in these contributions, but the bulk of my work is visible here:
Product Value
Workspace Presets are valuable because they reduce the end-user complexity of provisioning cloud development environments. This allows software engineers to create their cloud development workspaces in fewer clicks, without wasting time on optimizing resource allocation or minutiae related to workspace configuration.
Workspace Presets also unlock another feature, called Workspace Prebuilds. Workspace Prebuilds maintain a small number of workspaces in reserve, which can then be assigned to end user developers as needed. When an engineer needs a workspace, they only have to wait for an existing workspace to be assigned to them, instead of for all their resources to be provisioned.
Architecture
In order to deliver Workspace Presets, I modified the following interlocking components.
Terraform Provider
Coder allows its administrators to define workspace templates as Terraform modules and host the resulting workspaces on their preferred infrastructure. To accommodate runtime variations in workspaces, coder_parameters are a special kind of terraform data source, which defines the form that an end user developer needs to complete when they create a workspace.
Workspace presets offer reasonable defaults for these parameters. As such, workspace presets are defined using a
coder_workspace_preset
data source in Terraform. To implement this, I defined such a new data source in the coder terraform
provider. There was little more to do in the Terraform provider than to implement the new schema and some basic validation.
Provisioner Daemon
Once an administrator has defined a template for their workspaces, they need to upload this template to Coder for use. Coder provisioner daemons receive uploaded templates from the Coder control plane and import them. These provisioners are responsible for executing Terraform at various important points in a template or workspace’s lifecycle.
Having added a new data source to the Coder Terraform provider, I taught the provisioners to recognise these preset data
sources in a given terraform plan file and send the preset information to the control plane. As input, the provisioner reads
Terraform’s output and interprets it as a directed acyclic graph. By walking this graph, we inspect each node and identify
workspace preset data sources. These are collected and sent to a modified version of Coder’s CompleteJob
dRPC API endpoint.
PostgreSQL Database
The PostgreSQL database acts as the main repository for workspace presets. It sits at the core of the workspace preset lifecycle.
Once a provisioner communicates new workspace presets for a template to the control plane, the control plane’s dRPC endpoint controller needs to persist those presets to the repository, so that they can be useful when end users create workspaces later.
Then, in order to read those presets when users create workspaces, the HTTPS/JSON API must be able to read the relevant presets and their parameters from the repository.
To facilitate the above, I wrote migrations to create new tables for workspace presets and queries to interact with the data at all phases of the workspace preset lifecycle. I also wrote authorization policies to ensure secure access to workspace presets. This was simplified by Coder’s use of sqlc, as well as a mature test suite that tested migrations bidirectionally and ensured that all SQL queries were protected by authorization. The way that Coder wraps it’s main repository in an authz interface is superior to my approach in past projects. It has its trade offs, but it will be my favored approach in future.
HTTPS/JSON API
Once a template has been pushed to a Coder deployment and its presets persisted to the database, they need to be visible to the frontend (web or CLI) that allows the user to create a workspace. To accomplish this, a new endpoint was added to the Coder API which read presets from the database and published them to clients who needed them. This endpoint was relatively simple. The most complex feature was that it transforms the payload from its database representation to an API friendly format.
React Frontend
Users commonly use a React based web frontend to interact with Coder. This frontend contains a page that allows the user to create a new workspace. This page reads parameters (and now presets) from the API and renders them as a form for the user to complete.
I added calls to the HTTPS/JSON API client to fetch presets for a template, and a new input to select a preset. Based on the selected preset, I implemented logic to dynamically fill and disable the inputs related to specific parameters.
This was a good opportunity to learn about formik, Tanstack query and a few other frontend technologies that I had not encountered before.
Conclusion
By contributing workspace presets to Coder, I have created the opportunity for our users to simplify how they interact with their development environments and built the scaffolding around which other features can be built to save engineers time when they create workspaces.
The opportunity to deliver valuable, non trivial features to an open source project as part of my day to day work is a rewarding and fun experience.
Credit to the Staff Engineer, Product Manager and other colleagues that have helped refine, plan and review my contributions.