This tool serves as an entry point for the Hashicorp's Consul KV store. Not only because Consul lacks of a built in audit mechanism, but also because having configurations managed in GIT, using a gitflow or a normal development-to-master flow is much friendly and familiar to any development team to manage configurations.
Downloads in releases page.
The master branch is being refactored. No (big) breaking changes will happen but codebase is under significant changes. Mainly adding tests, makefile, and code refactor/cleanup.
Please use the releases/downloads page. Instructions for development will be added soon!
Gonsul will (optionally) clone your repository into the filesystem. After, it will recursively parse
all the files in
the directory. Whenever Gonsul moves one level deep into a folder, the folder name is added as a
Consul KV path part
and as soon as it finds a file (either .json
, .txt
or .ini
- or any other given in parameters)
it will take the
file name (without the extension) and append to the Consul KV path, making it a key and the file
content is added as the
value.
Example: Take this repository folder structure:
+-- prod
| |
| +-- website1
| | |-- config.json
| | |-- db-pass.txt
| |
| +-- app2
| |-- config.json
|
+-- dev
|
+-- website1
| |-- config.json
|
+-- app2
|-- config.json
All the files content would be inserted, respectively, into the following Consul KV paths:
prod/website1/config
prod/website1/db-pass
prod/app2/config
dev/website1/config
dev/app2/config
Note 1: Gonsul makes the assumption that only .txt
, .json
and .ini
files are to be treated
as keys and their
content as values for Consul. Any other files are disregarded. Also, .json
files are treated and
validated as valid
JSON, and inserted into Consul pretty formatted.
Note 2: You can instruct Gonsul to expand the JSON files, so it will parse the structure, appending the JSON path to the previous folder structure, creating single Consul KV entries for each value. Caveats: Any arrays found are inserted into Consul a bracketed comma separated value string. More details on this on the flags description.
Gonsul was built out of necessity and so it provides some features that makes our team more comfortable regarding security and consistency, so below are the most important features (TL;DR's in bold):
Below are all available command line flags for starting Gonsul. Flags may be specified on the
command line, using
environment variables (flag prefixed with "GONSUL", converted to upper case, and "-" changed to
"", e.g.
GONSUL_REPO_URL
), or using a configuration file (--config=
). The order of precedence for
specifying flags is:
--config=
--strategy=
--repo-url=
--repo-ssh-key=
--repo-ssh-user=
--repo-branch=
--repo-remote-name=
--repo-base-path=
--repo-root=
--consul-url=
--consul-acl=
--consul-base-path=
--log-level=
--expand-json=
--secrets-file=
--allow-deletes=
--poll-interval=
--input-ext=
--keep-ext=
Below is the full description for each individual command line flag.
--config
require:
noexample:
--config=gonsul.conf
This specifies a file with configuration settings for the options described below. File syntax:
strategy ONCE
or
strategy=DRYRUN
).--strategy
require:
yesexample:
--strategy=ONCE
This defines the mode that Gonsul should run at, having the following strategies:
DRYRUN
In this mode it will process the repository/folder and will output only the
different operations it
would run, such as: inserts, updates and deletesONCE
In this mode it will process the repository/folder and will proceed with all the
operations it finds
(updates, inserts and optionally deletes as well, see details below), after it finishes, Gonsul will
terminate
gracefully (exit 0). If something goes wrong, Gonsul will exit with one of the exit codes.POLL
In this mode, Gonsul will start polling the repository every X minutes and check for
differences
applying the same logic as the once
strategy. The process will work forever and it will only
stop on any error or
a SIGINT is received.HOOK
This is the last strategy type, and in this mode, Gonsul will lauch an HTTP server that
listens on a
specified port waiting for GET
request triggering and applying the same logic as the once
strategy. Again, this
process will live forever until it receives a SIGINT signal. Also, the HTTP server will only
process one request at a
time (using a lock between processes) to avoid concurrent writes on Consul, so whenever a request is
made and Gonsul is
already processing another, the new request will hold until the request before finishes.NOTES: On both POLL and HOOK strategies, the application will gracefully terminate upon
receiving a SIGINT
signal,
but it will obviously not under a SIGKILL
in which you can end up with inconsistent data inside
Consul KV cluster (in
case you have more than 64 operations in progress, and Gonsul issued only the first transaction for
example)
--repo-url
require:
noexample:
--repo-url=git@github.com:githubtraining/hellogitworld.git
This flag will tell Gonsul where it should clone/checkout the repository from. This should be a fully qualified GIT url (either ssh, http or https). Please provide the full URL, with any ports, credentials or whatever you would normally use.
Note: If you do not provide this flag, Gonsul will still look at the filesystem --repo-root
folder and try to
process/parse the directory. This can be useful in case you want to delegate the repository cloning
to a CI platform,
such as Bamboo for example, removing the GIT responsibility from Gonsul and having it just process
the files and sync
them with Consul as normal.
--repo-ssh-key
require:
noexample:
--repo-ssh-key=/home/example_user/.ssh/id_rsa
This is only required if the previous flag was given and it tells Gonsul where it can find the SSH key file to use in case we're connecting through SSH with a key.
--repo-ssh-user
require:
noexample:
--repo-ssh-user=git
This is only required if the previous flag was given and it tell Gonsul what user we should use when connecting to an SSH GIT repository.
--repo-branch
require:
nodefault:
masterexample:
--repo-branch=my_branch_name
This is the branch name that Gonsul should try to checkout.
--repo-remote-name
require:
nodefault:
originexample:
--repo-remote-name=upstream_name
This is the name of the remote configured on the repository. We need it to properly trigger some PULL and CHECKOUT commands on the repository.
--repo-base-path
require:
noexample:
--repo-base-path=configs/relative/path
This is the relative folder, inside our repository, that Gonsul should consider and parse as values to be synced with your Consul cluster. If no value is given, Gonsul assume that the root repository is to be considered as Consul parseable.
Note: Gonsul will only build the hierarchy path from this path onward. Given the example above,
Gonsul will not try
to look for a Consul KV path that starts with configs/relative/path
but instead, it will from any
deeper path from
this folder down.
Note2: If this flag is not set, the below value of --repo-root
will be used as the hierarchy
path within Consul,
which is normally not desired. Most of the times we should/must use this flag.
--repo-root
require:
yesexample:
--repo-root=/home/user/gonsul/repo_dir
This is the absolute path where Gonsul should clone the repository in your OS filesystem. This is a
required field, and
when provided without providing the previous flag --repo-url
, Gonsul will try to parse the given
absolute path without
using GIT. This could be useful if you want to use Gonsul as filesystem parser and Consul sync
without doing any GIT
operations.
Note: This value/path will be used as the the hierarchy path on Consul if no value is given on
above --repo-base-path
which in many cases is not intended. Most of the times, we should also use the flag above.
--consul-url
require:
yesexample:
--consul-url=https://consul-cluster.example.com:8080
This is the Consul's REST API endpoint that Gonsul will call to make the required inserts, updates and deletes on the Consul's KV store. Please provide the full URL, with scheme and port if appropriate.
Note: Do not add the KV path, just the the scheme and the authority part of the URL.
--consul-acl
require:
noexample:
--consul-acl=youracltokenhere
This is the Consul's access token that Gonsul will use when connecting to the cluster agent. This ACL must have read and write access to the same KV paths that are going to be replicated with the repository files.
--consul-base-path
require:
noexample:
--consul-base-path=my/kv/base/path
This is the prefix for all generated keys that Gonsul will look at.
Note: Remember that this base path must not be mirrored in the repository, as it will be automatically appended. This is useful when the Consul cluster as all the KV paths segregated (namespaced) by teams or projects.
--log-level
require:
nodefault:
ERRORexample:
--log-level=DEBUG
This defines the logging level that Gonsul should run, having the following levels:
DEBUG
In this mode it will verbosely output the information of below levels plus all the
debugging information such
as what tasks are being processed.INFO
In this mode it will output all the information below plus some useful information such
as processed keys.ERROR
In this mode, Gonsul will only output only error messages.--expand-json
require:
nodefault:
falseexample:
--expand-json=true
This will tell Gonsul how to treat JSON files. If true, Gonsul will traverse the JSON files and append the path to the previous folder/file hierarchy and create single entries in Consul KV for each value.
Note: Because Consul is a simple KV Store, where all values are strings, there are some caveats regarding the JSON file expanding. Some important ones are:
["val1","val2","otherval"]
true
and false
. This might
break some applications
when reading configuration, as they will be just strings after all.--expand-yaml
require:
nodefault:
falseexample:
--expand-yaml=true
This will tell Gonsul how to treat YAML files. If true, Gonsul will traverse the YAML files and append the path to the previous folder/file hierarchy and create single entries in Consul KV for each value.
Note: Because Consul is a simple KV Store, where all values are strings, there are some caveats regarding the YAML file expanding. Some important ones are:
["val1","val2","otherval"]
true
and false
. This might
break some applications
when reading configuration, as they will be just strings after all.--secrets-file
require:
noexample:
--secret-files=secrets.json
This is the location for a secrets file. You can either pass a relative path and Gonsul will look
for it into the
--repo-root
path or you can pass an absolute path. If this value is passed and the file is found
and checked as valid,
Gonsul will try to do an on-the-fly search and replace any placeholders for the corresponding
values. This is done using
mustache template system.
This file must be a valid JSON map, where the keys are the placeholders and the values the actual
secrets. An example
secrets.json
file could look like this:
{
"FOO_DB_USER": "foo_username_foo1982",
"FOO_DB_PASS": "foo_password_J5sXoEN",
"BAR_TOKEN": "bar_token_J5sXoEN",
"BAZ_KEY": "baz_key_J5sXoEN"
}
Note 1: All the replacement is done on-the-fly in memory, and apart from the original supplied
secrets.json
file,
no secrets are written to disk.
Note 2: The placeholders should follow the mustache triple curly braces
{{{FOO_DB_USER}}}
, that means
"unescaped HTML charcaters" - basically takes the value as is.
--allow-deletes
require:
nodefault:
falseexample:
--allow-deletes=true
This option sets Gonsul behaviour on how it should proceed in case some Consul deletes are to be made.
true
With this mode deletes are allowed and Gonsul will proceed with the delete operations,
removed files from the repo and/or files added directly on consul k/v will be deleted.skip
In this mode, Gonsul will skip the deletion check and operations and will just
sync/push files to consul k/v path (can lead to inconsistencies at the consul k/v path since removed
files from the repo and/or files added directly on consul k/v will stay in the consul path because
we are skipping deletions).false
this is the default mode and Gonsul will not proceed with the deletes, and depending
on the --strategy
it is running at, will respond with some different behaviors, such as:
ONCE
When running in once mode, Gonsul will terminate with error code 10 and output
to console all the Consul KV paths that are supposed to be deleted.
HOOK
Gonsul will repond to the HTTP request with error 503 and will also return the
following headers and values:
X-Gonsul-Error:10
X-Gonsul-Delete-Paths:path1/to/be/deleted,path2/to/be/deleted
POLL
Gonsul will log all the paths to be deleted as ERRORS and carry on, over and over.
In this mode you should monitor Gonsul logs to detect any found errors, and react appropriately.
The errors will follow the syntax:
[ERROR] [28-01-2018 17:38:25 1234] error-10 path1/to/be/deleted
[ERROR] [28-01-2018 17:38:25 5678] error-10 path2/to/be/deleted
--poll-interval
require:
nodefault:
60example:
--poll-interval=300
This is the number of seconds you want Gonsul to wait between checks on the repository when it is
running in
--strategy=POLL
mode.
--input-ext
require:
nodefault:
json,txt,iniexample:
--input-ext=json,txt,ini,yaml
This is the file extensions that Gonsul should consider as inputs to populate our Consul. Please set each extension without the dot, and separate each extension with a comma.
--keep-ext
require:
nodefault:
falseexample:
--keep-ext=true
Gonsul default behavior is to remove/trim the filextension from the filename when pushing files to consul k/v path, if this option is set to true gonsul will keep the file extension.
--timeout
require:
nodefault:
5example:
--timeout=20
The number of seconds for the client to wait for a response from Consul
Whenever an error occurs, and Gonsul exits with a code other than 0, we try to return a meaningful code, such as:
10 - This is the most important error code. It means Delete operations were found and Gonsul is running without delete permission. This error comes with the info about the Consul KV paths that would be deleted.
20 - There was a problem on the initialization parameters /flags
30 - This means there was an error connecting to Consul cluster. This can ben either ACL token, wrong endpoint, network, etc.
31 - There was a problem running a Consul transaction. It basically means on operation of the transaction is corrupted for some reason. Try a dryrun to analyze all the operations Gonsul is trying to run.
40 - This is a generic error when Gonsul fails to read an HTTP response.
50 - This error is thrown when Gonsul could not encode a json payload for a transaction. Check dryrun for what operations Gonsul is trying to run.
51 - This is when Gonsul could not decode a JSON payload. This can be either from a GET response from Consul, or more common when processing the filesystem and it found a corrupted JSON file - check your JSON files for errors.
60 - This occurs when Gonsul cannot clone the repository. Either because credentials are broken, or filesystem permissions.
70 - This error occurs when secret replacement fails.
80 - This is a generic HTTP error. Run Gonsul in debug mode to look for more information regarding the error.
For notes on how to contribute check CONTRIBUTING.