docs/config/checklist-adding-config-fields.md
This is a checklist of all the places you need to update when adding a new field to config. There may be a few other special cases not included but this covers the majority of configs.
We suggest you copy the raw markdown into a gist or local file and check them
off as you go (you can mark them as done by replace [ ] with [x] so github
renders them as checked). Then please include the completed lists you worked
through in your PR description.
Examples of special cases this doesn't cover are:
-dev mode
or differences between CE and Enterprise.There are four specific cases covered with increasing complexity:
agent/config/config.go.agent/config/runtime.go.agent/config/builder.go to
translate.agent/config/testdata/full-config.*, which should cause the test to fail.
Then update the expected value in TestLoad_FullConfig in
agent/config/runtime_test.go to make the test pass again.go test -run TestRuntimeConfig_Sanitize ./agent/config -update to update
the expected value for TestRuntimeConfig_Sanitize. Look at git diff to
make sure the value changed as you expect.agent/config/builder.go.TestLoad_IntegrationWithFlags in
agent/config/runtime_test.go.DefaultSource in agent/config/defaults.go.TestLoad_IntegrationWithFlags in
agent/config/runtime_test.go.DefaultConfig() in agent/consul/config.go.ReloadConfig in agent/agent.go if it needs to affect the local
client state or another client agent component.ReloadConfig in agent/consul/client.go if it needs to affect
state for client agent's RPC client.agent/agent_test.go similar to others with prefix
TestAgent_reloadConfig*.website/content/docs/agent/config/config-files.mdx.Done! You can now use your new field in a client agent by accessing
s.agent.Config.<FieldName>.
If you need a CLI flag, access to the variable in a Server context, or touched the Service Definition, make sure you continue on to follow the appropriate checklists below.
If the config field also needs a CLI flag, then follow these steps.
agent/config/flags.go.agent/config/flag_test.go.TestLoad_IntegrationWithFlags in agent/config/runtime_test.go to ensure setting the
flag works.website/source/docs/agent/config/config-files.mdx and website/source/docs/agent/config/cli-flags.mdx.Consul servers have a separate Config struct for reasons. Note that Consul
server agents are actually also client agents, so in some cases config that is
only destined for servers doesn't need to follow this checklist provided it's
only needed during the bootstrapping of the server (which is done in code shared
by both server and client components in agent.go). For example WAN Gossip
configs are only valid on server agents but since WAN Gossip is setup in
agent.go they don't need to follow this checklist. The simplest (and mostly
accurate) rule is:
If you need to access the config field from code in
agent/consul(e.g. RPC endpoints), then you need to follow this. If it's only inagent(e.g. HTTP endpoints or agent startup) you don't.
A final word of warning - you should never need to pass config into the FSM
(agent/consul/fsm) or state store (agent/consul/state). Doing so is very
dangerous and can violate consistency guarantees and corrupt databases. If
you think you need this then please discuss the design with the Consul team
before writing code!
Consul's server components for historical reasons don't use the RuntimeConfig
struct they have their own struct called Config in agent/consul/config.go.
agent/consul/config.goRuntimeConfig in newConsulConfig method in agent/agent.goagent_test.go if there is some non-trivial
behavior in the code you added in the previous step. We tend not to test
simple assignments from one to the other since these are typically caught by
higher-level tests of the actual functionality that matters but some examples
can be found prefixed with TestAgent_consulConfig*ReloadConfig in agent/consul/server.go this
needs to be adequately synchronized with any readers of the state being
updated.
- [ ] Add a new test or a new assertion to TestServer_ReloadConfigYou can now access that field from s.srv.config.<FieldName> inside an RPC
handler.
The Service Definition syntax
appears both in Consul config files but also in the /v1/agent/service/register
API.
For wonderful historical reasons, our config files have always used snake_case
attribute names in both JSON and HCL (even before we supported HCL!!) while our
API uses CamelCase.
Because we want documentation examples to work in both config files and API bodies to avoid needless confusion, we have to accept both snake case and camel case field names for the service definition.
Finally, adding a field to the service definition implies adding the field to several internal structs and to all API outputs that display services from the catalog. That explains the multiple layers needed below.
This list assumes a new field in the base service definition struct. Adding new
fields to health checks is similar but mostly needs HealthCheck structs and
methods updating instead. Adding fields to embedded structs like ProxyConfig
is largely the same pattern but may need different test methods etc. updating.
agent/structs package
ServiceDefinition (service_definition.go)NodeService (structs.go)ServiceNode (structs.go)ServiceDefinition.ToNodeService to translate the fieldNodeService.ToServiceNode to translate the fieldServiceNode.ToNodeService to translate the fieldTestStructs_ServiceNode_ConversionsServiceNode.PartialCloneTestStructs_ServiceNode_PartialClone (structs_test.go)NodeService.Validate to ensure the field value is
reasonableTestStructs_NodeService_Validate* in
structs_test.goNodeService.IsSameTestStructs_NodeService_IsSameServiceNode.IsSameServiceTestStructs_ServiceNode_IsSameServiceaux inline struct in
ServiceDefinition.UnmarshalJSON (service_defintion.go).
UnmarshalJSON
method - you may need to add one if there are no other case
transformations being done, copy and existing example.agent package
testAgent_RegisterService and/or add a new test to ensure
your fields register correctly via API (agent_endpoint_test.go)testAgent_RegisterService_TranslateKeys to include
examples with it set in snake_case and ensure it is parsed
correctly. Run this via TestAgent_RegisterService_TranslateKeys
(agent_endpoint_test.go).api package
AgentService (agent.go)agent_test.go
make test or ensure the consul binary on
your $PATH is a build with your new field - usually make dev
ensures this unless you're path is funky or you have a consul binary
even further up the shell's $PATH).website/source/docs/agent/services.html.mdNote that although the new field will show up in the API output of
/agent/services , /catalog/services and /health/services, those tests
right now don't exercise anything that's super useful unless custom logic is
required since they don't even encode the response object as JSON and just
assert on the structs you already modified. If custom presentation logic is
needed, tests for these endpoints might be warranted too. It's usual to use
omit-empty for new fields that will typically not be used by existing
registrations although we don't currently test for that systematically.