Skip to content

Commit 5a589ad

Browse files
committed
Configuration standard
1 parent c40d035 commit 5a589ad

1 file changed

Lines changed: 210 additions & 0 deletions

File tree

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# HyperFleet Configuration Standard
2+
3+
## Overview
4+
5+
This document defines the standard approach for configuration loading, merging, and override rules across all HyperFleet applications. This ensures consistent, predictable configuration behavior across all repositories.
6+
7+
## Configuration behavior
8+
9+
When configuring applications there are multiple options for data sources:
10+
- Using files
11+
- Single or multiple files allowed
12+
- Single or multiple formats (YAML, JSON)
13+
- Good for complex object hierarchies (arrays, complex objects)
14+
- Using command-line arguments
15+
- Good for interactive execution (e.g. during development, `--help`)
16+
- Using environment variables
17+
- More secure for parameters like credentials
18+
- Easy to operate in environments like Kubernetes
19+
- Remote configuration
20+
- Centralized configuration
21+
22+
For HyperFleet applications we want to offer flexibility and predictability for developers and providers who will operate the solution.
23+
- HyperFleet applications will use data sources with this override precedence
24+
1. **Command-line flags** (highest priority)
25+
2. **Environment variables**
26+
3. **Configuration files**
27+
4. Defaults
28+
- All the configuration options must be documented explicitly in a `docs/config.md` document in the repository
29+
- Current "merged" configuration should be displayed at boot time, or exposed to be queried (e.g. using an `/config` endpoint)
30+
31+
All options can be set using all data sources, with some exceptions:
32+
- The location for a config file is defined by a command-line parameter `--config` or environment variable only.
33+
- Some libraries used by the applications (e.g broker or OTEL) will require their specific files and/or environment variables
34+
- It doesn't make sense to offer multiple ways to configure these
35+
- Any other exception should be documented in `docs/config.md`
36+
37+
## Config properties syntax
38+
39+
Since each data source has different syntax rules, we need to stablish a convention for config properties:
40+
- Properties are case insensitive
41+
- Two properties `propertyA` and `propertya` should mean the same
42+
- Properties should form a hierarchy of single word paths
43+
- E.g to represent the property `app.name`
44+
- As a command-line parameter it will be `--app-name`
45+
- As an environment variable it will be `HYPERFLEET_APP_NAME`
46+
- In YAML files it can be a nested property
47+
```
48+
app:
49+
name: myapp
50+
```
51+
52+
53+
Snake case property names should be avoided, as they can create ambiguity.
54+
55+
56+
## Standard Configuration File Paths
57+
58+
Config files for HyperFleet applications must be in YAML format
59+
60+
The config file location is flexible and can be determined by:
61+
1. Path specified via `--config` flag (if provided)
62+
2. Path specified via `HYPERFLEET_CONFIG` environment variable
63+
3. Default values
64+
- production: `/etc/hyperfleet/config.yaml`
65+
- development: `./configs/config.yaml`
66+
67+
The first file found is used. If no config file is found, the application continues with flags and environment variables only.
68+
69+
Some applications may work with multiple configuration files, for example the adapter framework can use two config files:
70+
- General application configuration, typically non functional parameters (technical configuration)
71+
- Business specific configuration (e.g. the AdapterConfig configuration)
72+
- Specifying the file to load should use a configuration key such as `adapter.config` (`--adapter-config`, `HYPERFLEET_ADAPTER_CONFIG`)
73+
- Values for these business configuration will only be loaded from files, there is no need to override from command line nor environment variables
74+
75+
## Environment Variable Convention
76+
77+
Rules:
78+
- All letters must be uppercase
79+
- All environment variables for HyperFleet applications should be prefixed with `HYPERFLEET_`.
80+
- This makes it easier to identify them and avoids collision with other properties.
81+
- The exception would be for those environment variables that are used by 3rd party libraries directly (e.g. OpenTelemetry lib)
82+
- Nested properties are separated by the `_` character.
83+
- e.g. `HYPERFLEET_<PATH>_<TO>_<PROPERTY>`
84+
85+
### Examples
86+
```bash
87+
# General format
88+
HYPERFLEET_APP_NAME="my-api"
89+
HYPERFLEET_SERVER_PORT=9000
90+
HYPERFLEET_DATABASE_HOST="db.example.com"
91+
```
92+
93+
## Command-Line Flag Convention
94+
95+
Rules
96+
1. **Lowercase**: All letters must be lowercase
97+
2. **Kebab-case**: Use hyphens (`-`) to separate words
98+
3. **Hierarchical**: Use section prefix for nested fields (e.g., `--app-name`, `--server-port`)
99+
4. **Short flags**: Common flags should have single-letter shortcuts
100+
101+
```
102+
--<section>-<field>
103+
```
104+
105+
106+
### Standard Flags
107+
108+
#### Global Flags (all applications)
109+
```
110+
--config <path> # Config file path
111+
--name, -n <string> # component name (REQUIRED)
112+
--version, -v <string> # component version
113+
```
114+
115+
#### Server Flags
116+
```
117+
--server-host <string> # Server bind host
118+
--server-port, -p <int> # Server bind port
119+
--server-timeout, -t <int> # Server timeout in seconds
120+
```
121+
122+
#### Database Flags
123+
```
124+
--db-host <string> # Database host
125+
--db-port <int> # Database port
126+
--db-username, -u <string> # Database username
127+
--db-password <string> # Database password (avoid using; prefer env vars)
128+
--db-name, -d <string> # Database name
129+
```
130+
131+
#### Logging Flags
132+
```
133+
--log-level, -l <level> # Logging level
134+
--log-format, -f <format> # Logging format (json|text)
135+
```
136+
137+
## Configuration Validation
138+
139+
The service should not be considered to be ready until configuration is merged and validation is performed.
140+
141+
An error in the configuration should stop the service.
142+
143+
This document does not define how validation is performed for services.
144+
145+
### Validation Error Handling
146+
When validation fails:
147+
1. Display **full field path** (e.g., `Config.Server.Port` not just `Port`)
148+
2. Show **validation rule** that failed (e.g., `required`, `min`, `max`)
149+
3. Provide **actual value** that failed validation
150+
4. Include **helpful hints** for how to fix (flags, env vars, config file)
151+
5. **Exit with code 1** to prevent startup with invalid configuration
152+
153+
Example error output:
154+
```
155+
Configuration validation failed:
156+
- Field 'Config.App.Name' failed validation: required
157+
Please provide application name via:
158+
• Flag: --app-name or -n
159+
• Environment variable: HYPERFLEET_MYAPP_APP_NAME
160+
• Config file: app.name
161+
- Field 'Config.Server.Port' failed validation: max
162+
Value 70000 exceeds maximum allowed value of 65535
163+
```
164+
165+
### Unknown Field Handling
166+
167+
Any unexpected property in a config file should trigger an error either when loading the file or validating the configuration. Silently accepting unexpected properties can lead to undesired behaviour, which is usually the case with misspelled config properties.
168+
169+
If using `viper` for unmarshaling an struct, there is the `viper.unmarshalExact()` function that will provoke an error for unexpected values.
170+
171+
172+
## Applications with multiple commands
173+
174+
Some applications define multiple commands (e.g. hyperfleet-api has serve and migrate commands). Configuration options should be different for each command, so it is not required to provide all configs for commands that only need a subset or completely different set of configuration options.
175+
176+
Configuration property names should be the same for commands that share concerns. E.g. for hyperfleet-api, all the config settings for database connection should have the same names.
177+
178+
## Configuration Reloading
179+
180+
### Standard Behavior
181+
**HyperFleet applications do NOT support runtime configuration reloading.**
182+
183+
Rationale:
184+
- **Simplicity**: Restart-based config changes are easier to reason about and test
185+
- **Consistency**: Ensures entire config is validated together at startup
186+
- **Safety**: Prevents partial config updates that could leave app in invalid state
187+
188+
### Configuration Changes
189+
To apply configuration changes:
190+
1. Update the configuration file or environment variables
191+
2. Restart the application/service
192+
3. New configuration is loaded and validated at startup
193+
194+
## Implementation example
195+
196+
An example to implement the configuration with support of cobra, viper and the [validation library](https://github.com/go-playground/validator) can be found at https://github.com/rh-amarin/viper-cobra-validation-poc. It showcases:
197+
198+
- Using flags for command parameters
199+
- Configuring a file for loading configuration
200+
- Setting prefix for environment variables
201+
- Declarative validation of structs
202+
203+
204+
## Displaying configuration
205+
206+
To make it easier to know the state in which the application runs, the merged configuration should be easily obtained.
207+
- Logging the configuration at start time
208+
- Offering a method to query it, e.g. through a `/config` endpoint that displays the values in JSON format
209+
210+
When displaying the configuration values, any sensitive data like credentials should be redacted and displayed as `*`, indicating that the value is set but can not be consulted

0 commit comments

Comments
 (0)