Published on June 11, 2021
Table of Contents
Overview
Superorbital spends a lot of time helping companies improve their internal computer engineering processes, and even when the basic problem is well understood, each engagement brings a lot of unique and interesting details that often require a unique solution. Even with the unique nature of each engagement we often see similar problems and pain points crop up across our customer base. Some of these problems are very large and something that might take a long term project to solve well, while others pain points are actually pretty simple to resolve with just a little bit of prioritization and focus.
Superorbital is proud to announce the release of wordchain, a simple, but flexible tool to address one of these easier pain points.
The Backstory
Early on in it’s development, Docker introduced randomized Linux container names using word pairs that consist of an adjective and the last name of a famous scientist or hacker. They even immortalized the well known fact that Steve Wozniak is not boring. As the industry started to make a concerted effort to migrate workloads off of pets and onto cattle random word-pair naming became an nice bridge between generating a completely random sequence of characters and generating something that was still somewhat memorable to human beings.
As time went on, Terraform introduced a module called random pet that can be used to apply a random name to each unique piece of infrastructure that a system needs to spin up and many other more general tools appeared, like Python’s codename.
But all of these tools tend to either only solve the problem for a single application or workflow, or are difficult to reuse everywhere in the pipeline. Installing Python to support a single CLI tool is less than ideal and environments like AWS may have hard limits on things like object names lengths, so a ten character random word pair might be much too long.
An Example Use-Case
AWS1 Elastic Load Balancer names must be unique within an account and can not be longer than 32 characters. When a human is generating the ELB name the length is unlikely to be a big issue, but it can quickly become a problem when the names are being auto-generated.
As an example, let’s imagine a CI/CD2 pipeline that runs integration tests on every PR and must create a load balancer for those tests.
To programmatically generate a name, one might combine a few available pieces of information with a random tag:
- Company: superorbital
- Application Name: login-service
- Environment: development
- AWS Region: us-east-1
- Random Tag: elegant-bartik
Even shortened up, these names can get long very quickly:
-
so-loginsvc-dev-usge1-elegant-bartik
(37 characters)
In this use-case it would be really useful to know ahead of time exactly how long each segment was going to be.
- Company: 2 characters
- Application Name: 8 character max
-
Environment: 3 characters (
dev
,tst
,int
,stg
,prd
) -
AWS Region: 5 characters max (
use1
,euc1
,apse1
,usge1
)
At this point the name (so-loginsvc-dev-usge1
) is 22 characters long, so this gives us exactly 10 characters to work with for randomization.
So, how can we easily generate a string, that meets our requirements of being a fixed length, random, and memorable, in most of the environments (scripts, containers, etc.) that we are likely to regularly use?
The Solution
After re-implementing this functionality in a few projects and never stumbling across a tool that that was truly as flexible as we wanted, we decided to build wordchain.
Using wordchain
it is easy to generate a random word sequence with a set length.
$ wordchain random -l 4
alto-howl
In our CI/CD pipeline use-case above, we would probably want the result to be deterministic, based on the branch name, so instead we might actually do something like this:
$ wordchain random -l 4 -s "my-pull-request-branch-name"
awry-grub
By passing in the branch name we can ensure that the result is deterministic and will remain the same for any job that is run on this branch.
Design Considerations
wordchain is designed with a few core things in mind. We wanted it to be very flexible. This primarily means that the output should be highly-configurable by the user.
wordchain
makes it very easy for the user to define:
- the number of words in the list.
- the length of words in the list.
- the delimiter that should be used between words.
- a string to be prepended or appended to the results.
- a custom list of words to pull from.
We also wanted it to be self-contained and therefore easy to use. This meant that we decide to build a tool:
- which could be installed with a single binary.
- which could be used as a simple REST-based3 micro-service.
- which could be used as a library for people writing Go applications.
- which provides an embedded word list, but allow it to be replaced.
And finally we wanted to ensure that it could provide deterministic results when desired. This is especially important in CI/CD pipelines, where you often want the results to remain unchanged on a given branch or pull request.
Usage Examples
CLI
- Use the built-in list to get a 5 letter adjective/noun chain
$ wordchain random
sudsy-cloak
- Use the built-in list to get a 4 letter adjective/noun chain
$ wordchain random -l 4
holy-wart
- Adjust the words types in the chain
$ wordchain random -t adjective,adjective,noun
fried-picky-month
- Get deterministic results from your list by providing a seed string
$ wordchain random -s "my-unique-git-branch-name"
mangy-berry
$ wordchain random -s "my-unique-git-branch-name"
mangy-berry
$ wordchain random -s "someone-elses-unique-git-branch-name"
minty-sleet
$ wordchain random -s "someone-elses-unique-git-branch-name"
minty-sleet
- Provide a custom list to get a 3 letter adjective/noun chain
$ wordchain random -j ./data/tests/words.json -l 3
tan-nap
- Get a 3 letter adjective/noun chain with a custom divider and pre-pended and post-pended word.
$ wordchain random -l 3 -d + -r hello -o goodbye
hello+odd+pad+goodbye
- Get a copy of the internal word list in the valid json format
$ wordchain export > internal-word-list.json
Microservice
$ wordchain listen --port 8080
2021/03/30 11:32:02 Serving word chains at http://[::]:8080
$ curl -X POST -d '{}' -H 'Content-Type: application/json' http://127.0.0.1:8080/v1/random
"{\"chain\":\"quack-bayou\"}"
$ curl -X POST -d '{"length": 3}' -H 'Content-Type: application/json' http://127.0.0.1:8080/v1/random
"{\"chain\":\"odd-toy\"}"
$ curl -X POST -d '{"divider": "_", "length": 3, "prepend": "hello", "postpend": "adios", "seed": "deterministic" }' -H 'Content-Type: application/json' http://127.0.0.1:8080/v1/random
"{\"chain\":\"hello_bad_ace_adios\"}"
Docker
$ docker run superorbital/wordchain:latest
2021/03/30 20:35:07 Serving word chains at http://[::]:8080
$ docker run superorbital/wordchain:latest random
alpha-drink
$ docker run superorbital/wordchain:latest random -l 3
cut-oak
Library
- In Go-based software project you can do something like this to use this as a library:
package main
import (
types "github.com/superorbital/wordchain/types"
words "github.com/superorbital/wordchain/words"
)
func main() {
prefs := types.Preferences{
WordFile: "",
Length: 5,
Divider: "-",
Prepend: "",
Postpend: "",
Seed: "",
Type: []string{"adjective", "noun"},
}
words.Random(prefs)
}
The library will expect a data file of words to exist. You can either create a valid JSON data file in your project at data/words.json
or you can copy wordchain/pkged.go
into your project to use the same word list that is embedded in the wordchain
binary by default.
Conclusion
wordchain
has helped us simplify various aspects of the projects that we have been working on, and hopefully it can also help you out. You can find the project on Github: github.com/superorbital/wordchain
Github stars, issues and pull requests are all encouraged!