cloudfoundry / cloudfoundry/stratos
Refactor runtime property configuration
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 267
- Forks
- 137
- Avg merge
- 5h 14m
- Merged PRs (30d)
- 77
Description
Detailed Description
We'd like to add support for specifying runtime configuration properties via CloudFoundry user-provided services.
For example, an operator would specify prior to deployment:
cf create-user-provided-service stratos-properties -p '{"CF_CLIENT": "stratos","CF_CLIENT_SECRET": "xxxx"}'
And then in the manifest.yml:
applications:
- name: console
...
services:
- stratos-properties
We've found this pattern works better than other obvious alternatives with CloudFoundry because:
- Putting secrets (such as the client secret) in the
manifest.ymlas an environment variable is challenging with respect to public source repositories. - Setting environment variables on an already running app doesn't work well as many zero-downtime deploy plugins create a new app on each deployment.
Context
Currently runtime properties are spread between:
./config.propertiesfile- Environment variables (sometimes set via
manifest.yml) /etc/secretsdirectory
Some settings appear to only work if specified in the ./config.properties file, others appear to allow overriding by environment variables.
Possible Implementation
Last year we made a small Go library to handle looking up environment variables from a list of sources, e.g. first look for environment variables, falling back to data provided by a user provided services, falling back to defaults.
We (cloud.gov.au team) worked with 18F to integrate this with their console.
I've made an experimental change to integrate the same library with the Stratos codebase which is linked as a PR below.
The change is actually quite small - the main part (in main.go) is this method, which initialises an env.VarSet:
// getEnvironmentLookup return a search path for configuration settings
func getEnvironmentLookup() *env.VarSet {
// Make environment lookup
envLookup := env.NewVarSet()
// Environment variables directly set trump all others
envLookup.AppendSource(os.LookupEnv)
// If running in CloudFoundry, fallback to a user provided service (if set)
cfApp, err := cfenv.Current()
if err == nil {
envLookup.AppendSource(env.NewLookupFromUPS(cfApp, "stratos-properties"))
}
// Fallback to a "config.properties" files in our directory
envLookup.AppendSource(config.NewConfigFileLookup("./config.properties"))
// Fallback to individual files in the "/etc/secrets" directory
envLookup.AppendSource(config.NewSecretsDirLookup("/etc/secrets"))
return envLookup
}
which is passed around to each component that needs to lookup anything from any of the config sources (that is, it is a replacement for the the config.GetValue() calls).
The branch above compiles and pushes, I haven't tested any deeper than that yet, but we can look at if this is a direction worth pursuing.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with main.go and the components that currently use config.GetValue(), then read the env.VarSet integration and the existing config.properties and /etc/secrets lookup paths. Done means the runtime configuration sources have a defined precedence, including Cloud Foundry user-provided services, and the affected components use the shared lookup consistently.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend, cloud
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100