Skip to content
This repository was archived by the owner on Nov 14, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ The configuration for Brubeck is loaded through a JSON file, passed on the comma
./brubeck --config=my.config.json

If no configuration file is passed to the daemon, it will load `config.default.json`, which
contains useful defaults for local development/testing.
contains useful defaults for local development/testing. The configuration file also supports
environment variable substitution when the BRUBECK_CONFIG_SUBSTITUTE_ENV environment variable
is set. The syntax for environment variable substitution is similar to bash: ${MY_VAR} is
replaced, verbatim, by the value of MY_VAR in the envionment. All environment variables
referenced in this way must be present at runtime, or else Brubeck will fail to start.

The JSON file can contain the following sections:

Expand Down
91 changes: 90 additions & 1 deletion src/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,95 @@ static char *get_config_name(const char *full_path)
return config_name;
}

static json_t *parse_config(const char *path, json_error_t *error)
{
json_t *parsed;
ssize_t len;
char *buf;
FILE *fp;
const char *p;

/* only perform env var substitutions if configured to do so through the enviornment */
if (getenv("BRUBECK_CONFIG_SUBSTITUTE_ENV") == NULL) {
return json_load_file(path, 0, error);
}

fp = fopen(path, "r");
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf = malloc(len + 1);
if (!buf) {
die("malloc failed while parsing config file, %s (len %ld)", path, len);
}

/* read in the entire config. */
memset(buf, 0, len + 1);
const ssize_t r = fread(buf, len, 1, fp);
const int err = ferror(fp);
if (err) {
die("failed to read config file %s, read %ld bytes of %ld total, ferror: %d (%s)",
path, r, len, err, strerror(err));
}

/* substitue environment variables matching the following syntax: ${MY_ENV_VAR} */
for (p = buf; buf != '\0'; ) {
const char *s = strstr(p, "${");
if (s == NULL) {
break;
}
const size_t prefix_len = s - buf;

const char *e = strstr(s, "}");
if (e == NULL) {
die("malformed environment substition syntax: "
"no matching \"}\" after \"${\" in config file %s", path);
}

/* found replacement between `s` and `e`. extract the key. */
const size_t klen = e - (s + 2);
if (klen == 0) {
die("malformed environment substition syntax: "
"no key found between brackets in config file %s", path);
}
char *k = strndup(s + 2, klen);

const char *v = getenv(k);
if (v == NULL) {
die("environment substition: no environment variable found for "
"key \"%s\" in config %s", k, path);
}

const size_t vlen = strlen(v);
size_t newsize = prefix_len + vlen + strlen(e + 1) + 1;
char *newbuf = malloc(newsize);
if (!buf) {
die("realloc failed while parsing config file, %s (newsize %lu)",
path, newsize);
}

/* copy in the old prefix, the new substitution, and the remaining suffix */
memcpy(newbuf, buf, prefix_len);
memcpy(newbuf + prefix_len, v, vlen);
memcpy(newbuf + prefix_len + vlen, e + 1, strlen(e + 1) + 1);
free(buf);

/* continue from the next byte after the previous prefix, and new value. */
buf = newbuf;
p = newbuf + prefix_len + vlen + 1;

log_splunk("replaced config %s with %s from environment", k, v);
free(k);
}

/* load as json, now that environment replacements are complete */
parsed = json_loads(buf, 0, error);

fclose(fp);
free(buf);
return parsed;
}

static void load_config(struct brubeck_server *server, const char *path)
{
json_error_t error;
Expand All @@ -198,7 +287,7 @@ static void load_config(struct brubeck_server *server, const char *path)
server->name = "brubeck";
server->config_name = get_config_name(path);
server->dump_path = NULL;
server->config = json_load_file(path, 0, &error);
server->config = parse_config(path, &error);
if (!server->config) {
die("failed to load config file, %s (%s:%d:%d)",
error.text, error.source, error.line, error.column);
Expand Down