What’s new in Spruce?

It’s been a while since we last blogged about spruce, and since then, a lot of things have changed. Here’s a quick summary of the spruce operators, and new features as of Spruce 1.4.2:


Want a playground to easily experiment with spruce operators, or debug/track down/report a bug? Check out http://play.spruce.cf.


The (( param )) operator can be used to require that an end-user override a particular value in a later manifest. For example, (( param "What should the admin user's password be set to?" )) will produce the error: properties.users.admin.password: What should the admin user's password be set to?



(( vault "my/secret/path:key" )) will contact the Vault server you’re currently targeted to via the VAULT_ADDR environment variable, and attempt to retrieve the value stored in my/secret/path:key. This allows you to store credentials in Vault, safely outside your manifest and templates. If you wish to commit a complete manifest without sensitive data to your repo, set the REDACT environment variable to any value. spruce will place REDACTED as the value retrieved, rather than the actual value. Just make sure to deploy the non-redacted one to bosh, or your password might suddenly become "REDACTED" (security through confuscation?).


Environment Variables

spruce can pull in the values of environment variables, and inject them into your manifest, alleviating the need to generate a new document by hand, with that variable, and merging it on top. For example (( grab $DIRECTOR_UUID )) or (( concat "cf-" $ENVIRONMENT_NAME ))



spruce json <file> or echo "my: yml" | spruce json will take a YAML document, and convert it for JSON. This is super useful for piping BOSH manifests or templates through jq for parsing.

Improved Error Display

Errors now utilize colors to improve readability where possible. Additionally whereas arrays would only show indexes for errors, spruce will now try to resolve out array object names (e.g. jobs.0.networks: You need to specify a network. will now show jobs.myjob_z1.networks: You need to specify a network.). The final error display improvement is that any unsatisfied (( param )) errors are shown in preference over other errors, to suppress issues caused by un-met parameters being grabbed, concatenated, injected, etc.


The logical-Or operator can be used to allow failover from one reference to another, or to a default value, without causing an error. For example, your database client might want to grab the port of the database server, or if that was not set, provide a default value: (( grab properties.db.port || "5524" ))



The (( inject this.data )) operator is used similarly to YAML’s anchoring/reference mechanism, except that it works across documents. It takes all of the data located under this.data, and injects it at the parent of the key that invoked the operator. This is pretty handy in BOSH manifests for defining how a type of job/instance group should be at a global scale, and making sure each zoned instance of it gets the same data where necessary, overriding what makes sense.



(( keys my.map )) is used to obtain an array listing all of the keys of a map, in case you need to do something with them.


Cartesian Products

Need to mash-up a list of ports with a list of server IPs? (( cartesian-product my.servers ":" my.ports )) will do the trick.



(( concat thing1 thing2 )) does just what it sounds like it would. It concatenates two values together. They can be references to scalars in the YAML document, environment variables, or quoted strings.



(( grab my.value )) is a straightforward operator to take the value of another property, and stick it here. Need to set the port of a server in one part of the manifest, and send it to clients of that server in a different part of the manifest? This is your operator.


Static IPs

Auto-generating static IPs for non-cloud-config BOSH deployments is made a lot easier with this operator. It behaves similarly to spiff’s static_ips operator: (( static_ips(0, 1, 2, ..., n) ))


Spread the word

twitter icon facebook icon linkedin icon