From 30d63edc9effd7c488ee33fb58bc8dd730879a7f Mon Sep 17 00:00:00 2001 From: Richard Date: Wed, 6 Sep 2023 20:30:36 +0300 Subject: [PATCH 1/9] docs: add how to manage config files recipe --- content/Recipes/files-w-configu.mdx | 153 +++++++++++++++++++++++++ content/Recipes/hc-vault-w-configu.mdx | 2 +- content/sidebar.json | 4 + 3 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 content/Recipes/files-w-configu.mdx diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx new file mode 100644 index 0000000..5adc08b --- /dev/null +++ b/content/Recipes/files-w-configu.mdx @@ -0,0 +1,153 @@ +--- +id: files-w-configu +slug: files-w-configu +title: Managing configuration files using Configu Orchestrator (open-source) +--- + +Today's dev teams are tasked with managing Config Ops on the _platform_ as well, +Configu lets you only worry about your application [schemas](/config-schema), with Configu providing the rest of what's needed, including managing the diffrent storage platforms +and validating your new config values. Check out the tutorial below that shows how to use [Configu Orchestrator (open-source)](https://github.com/configu/configu) to manage +[JSON files](https://json.org) and [INI files](https://docs.fileformat.com/system/ini). + +![image](./img/file-diagram.png) + +To complete the tutorial, you'll need: + +- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) that contains an array or an [INI file](https://docs.fileformat.com/system/ini/) +- [Configu's CLI](/cli-setup) +- [hackathon-starter application](https://github.com/sahat/hackathon-starter) + +As most applications already have configuration files, In this example, we will use the `.env.example` file from the hackathon-starter repo: + +`.env.example` + +```bash +BASE_URL=http://localhost:8080 +MONGODB_URI=mongodb://localhost:27017/test +SITE_CONTACT_EMAIL=youremail@yourdomain.com + +... + +``` + +## Step 1 - Create schema declaration + +Instead of maintaining a `.env` file for each environment or duplicating the keys, +create a `.cfgu` schema declaration for this service, so that each change will only have to be made once (only the key in the schema) and then the values will be initialized by the same interface. +We will use the `init` command to generate it and for this example, we can also use the `--import` flag to auto-generate it from the existing `.env` file: + +```bash +configu init --import .env.example --defaults --types --name app +``` + + + `--types` will automatically generate the types for you, based on the supported types. If you use + this flag, always check and verify that the generated types are accurate + + +`app.cfgu.json` + +```json +{ + "BASE_URL": { + "type": "URL", + "default": "http://localhost:8080" + }, + "MONGODB_URI": { + "type": "String", + "default": "mongodb://localhost:27017/test" + }, + "SITE_CONTACT_EMAIL": { + "type": "Email", + "default": "youremail@yourdomain.com" + }, + + ... +} +``` + + + Although saving configurations in the source control is considered to be bad practice, the Cfgu + format is designed to be part of the code as it doesn't include any sensitive values. Doing that + increases developers' velocity and helps them avoid leaving the terminal/IDE. + + +## Step 2 - Use defaults for local development + + + For the full instructions please follow the `hackathon-starter` [getting started + guide](https://github.com/sahat/hackathon-starter/blob/master/README.md#getting-started) + + +Running a local environment was never easier, run Configu seamlessly with your app. + +```bash +configu eval --schema "./app.cfgu.json" --defaults | configu export --run "node app.js" +``` + +## Step 3 - Manage configs in JSON/INI files using Configu Orchestrator + +Using a single set of commands we can control any store from local files to secret managers. +In the following example, we will manage our configs over our JSON/INI files. + +### Using JSON/INI files + +Configu's CLI needs to be directed to your desired file by providing a file path via the [.configu file](../cli-config). + +example: + + + +```json +{ + "stores": { + "my-store": { + "type": "json-file", + "configuration": { + "path": "path/to/file.json" + } + } + } +} +``` + +```json +{ + "stores": { + "my-store": { + "type": "ini-file", + "configuration": { + "path": "path/to/file.ini" + } + } + } +} +``` + + + +### Upsert values + +```bash +configu upsert --store "my-store" --set "prod" --schema "./app.cfgu.json" \ + -c "BASE_URL=http://app.yourdomain.com" \ + -c "SITE_CONTACT_EMAIL=info@yourdomain.com" +``` + +We can also easily add configs to additional environments like `test` + +```bash +configu upsert --store "my-store" --set "test" --schema "./app.cfgu.json" \ + -c "BASE_URL=http://app.test.yourdomain.com" -c "SITE_CONTACT_EMAIL=test@yourdomain.com" +``` + +### Export values + +Similar to the way we previously used the Cfgu defaults we can evaluate and export from any store we need. + +```bash +configu eval --store "my-store" --set "prod" --schema "./app.cfgu.json" \ + | configu export +``` + +You're done! This was a simple operation, but that's the best way to show someone the power and the simplicity of Configu Orchestrator and how you can use it to manage your configuration automatically and safely using all your current stores. diff --git a/content/Recipes/hc-vault-w-configu.mdx b/content/Recipes/hc-vault-w-configu.mdx index 4e990ae..bd1d380 100644 --- a/content/Recipes/hc-vault-w-configu.mdx +++ b/content/Recipes/hc-vault-w-configu.mdx @@ -114,7 +114,7 @@ If not please configure your environment with the required variables (See variab ```bash configu upsert --store "hashicorp-vault" --schema "./my-app.cfgu.json" --set "prod" \ - --config "DB_USER=user" --config "DB_PASSWORD=123" --config "DB_HOST=localhots" \ + --config "DB_USER=user" --config "DB_PASSWORD=123" --config "DB_HOST=localhost" \ --config "DB_PORT=5433" --config "DB_NAME=database" ``` diff --git a/content/sidebar.json b/content/sidebar.json index 61ed6c8..50176a5 100644 --- a/content/sidebar.json +++ b/content/sidebar.json @@ -192,6 +192,10 @@ { "title": "Managing HashiCorp Vault using Configu", "slug": "hc-vault-w-configu" + }, + { + "title": "Managing configuration files using Configu", + "slug": "files-w-configu" } ] } From ff8eec901c5732c33ac7f5190514e6934307ae1f Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 7 Sep 2023 07:53:34 +0300 Subject: [PATCH 2/9] docs: fix recipe commands --- content/Recipes/files-w-configu.mdx | 10 ++++++++-- content/Recipes/hc-vault-w-configu.mdx | 6 +++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index 5adc08b..92b13d1 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -13,10 +13,16 @@ and validating your new config values. Check out the tutorial below that shows h To complete the tutorial, you'll need: -- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) that contains an array or an [INI file](https://docs.fileformat.com/system/ini/) +- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) or an [INI file](https://docs.fileformat.com/system/ini/) - [Configu's CLI](/cli-setup) - [hackathon-starter application](https://github.com/sahat/hackathon-starter) + +- Make sure that the files are already created when using the Configu CLI. +- When using a JSON file, make sure it is a root-level array. + + + As most applications already have configuration files, In this example, we will use the `.env.example` file from the hackathon-starter repo: `.env.example` @@ -82,7 +88,7 @@ configu init --import .env.example --defaults --types --name app Running a local environment was never easier, run Configu seamlessly with your app. ```bash -configu eval --schema "./app.cfgu.json" --defaults | configu export --run "node app.js" +configu eval --schema "./app.cfgu.json" | configu export --run "node app.js" ``` ## Step 3 - Manage configs in JSON/INI files using Configu Orchestrator diff --git a/content/Recipes/hc-vault-w-configu.mdx b/content/Recipes/hc-vault-w-configu.mdx index bd1d380..20258f8 100644 --- a/content/Recipes/hc-vault-w-configu.mdx +++ b/content/Recipes/hc-vault-w-configu.mdx @@ -86,18 +86,18 @@ Running a local environment was never easier, choose your preferred way to injec - Run Configu seamlessly with your app ```bash - configu eval --schema "./my-app.cfgu.json" --defaults | configu export --run "py my-app.py" + configu eval --schema "./my-app.cfgu.json" | configu export --run "py my-app.py" ``` - Inject the variables into your shell ```bash - configu eval --schema "./my-app.cfgu.json" --defaults | configu export --source + configu eval --schema "./my-app.cfgu.json" | configu export --source ``` - Download and use `.env` file or any other format you want ```bash - configu eval --schema "./my-app.cfgu.json" --defaults | configu export --format "Dotenv" > .env.development + configu eval --schema "./my-app.cfgu.json" | configu export --format "Dotenv" > .env.development ``` ## Step 3 - Manage configs in HashiCorp Vault using Configu Orchestrator From 73733e564c05bd22612cc20bbbbc33b09f68ebd1 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 7 Sep 2023 08:04:22 +0300 Subject: [PATCH 3/9] docs: adjust file recipe --- content/Recipes/files-w-configu.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index 92b13d1..f94fc46 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -153,7 +153,7 @@ Similar to the way we previously used the Cfgu defaults we can evaluate and expo ```bash configu eval --store "my-store" --set "prod" --schema "./app.cfgu.json" \ - | configu export + | configu export --run "node app.js" ``` You're done! This was a simple operation, but that's the best way to show someone the power and the simplicity of Configu Orchestrator and how you can use it to manage your configuration automatically and safely using all your current stores. From 0a9fbdb09223c0218cec696382acf2eff235ba33 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 7 Sep 2023 11:30:24 +0300 Subject: [PATCH 4/9] docs: add img to files recipe --- content/Recipes/files-w-configu.mdx | 2 +- content/Recipes/img/files-diagram.png | Bin 0 -> 41436 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 content/Recipes/img/files-diagram.png diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index f94fc46..da5743e 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -9,7 +9,7 @@ Configu lets you only worry about your application [schemas](/config-schema), wi and validating your new config values. Check out the tutorial below that shows how to use [Configu Orchestrator (open-source)](https://github.com/configu/configu) to manage [JSON files](https://json.org) and [INI files](https://docs.fileformat.com/system/ini). -![image](./img/file-diagram.png) +![image](./img/files-diagram.png) To complete the tutorial, you'll need: diff --git a/content/Recipes/img/files-diagram.png b/content/Recipes/img/files-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..4927182f5a691da00d33f5ea8546d80a2da7a934 GIT binary patch literal 41436 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 Date: Thu, 7 Sep 2023 13:31:06 +0300 Subject: [PATCH 5/9] docs: change ini file link --- content/Recipes/files-w-configu.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index da5743e..a91a77b 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -7,13 +7,13 @@ title: Managing configuration files using Configu Orchestrator (open-source) Today's dev teams are tasked with managing Config Ops on the _platform_ as well, Configu lets you only worry about your application [schemas](/config-schema), with Configu providing the rest of what's needed, including managing the diffrent storage platforms and validating your new config values. Check out the tutorial below that shows how to use [Configu Orchestrator (open-source)](https://github.com/configu/configu) to manage -[JSON files](https://json.org) and [INI files](https://docs.fileformat.com/system/ini). +[JSON files](https://json.org) and [INI files](https://en.wikipedia.org/wiki/INI_file). ![image](./img/files-diagram.png) To complete the tutorial, you'll need: -- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) or an [INI file](https://docs.fileformat.com/system/ini/) +- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) or an [INI file](https://en.wikipedia.org/wiki/INI_file) - [Configu's CLI](/cli-setup) - [hackathon-starter application](https://github.com/sahat/hackathon-starter) From 4ce9239da43a80101d7552d290e97dce5581c5c0 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 7 Sep 2023 15:10:39 +0300 Subject: [PATCH 6/9] docs: add cli interfaces to ini file store --- content/Concepts/config-store.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/Concepts/config-store.mdx b/content/Concepts/config-store.mdx index 5d2a095..96ef80d 100644 --- a/content/Concepts/config-store.mdx +++ b/content/Concepts/config-store.mdx @@ -50,7 +50,7 @@ You can choose the appropriate `ConfigStore` based on your specific use case, an category="file" name="Ini File" type="ini-file" - interfaces={['Node.js']} + interfaces={['CLI', 'Node.js']} docs="https://configu.com/docs/" configs="https://configu.com/docs/" /> From a0c46c270138269c17bcb24b25b5cd7e0a5380f7 Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 7 Sep 2023 15:13:33 +0300 Subject: [PATCH 7/9] docs: change file recipe .configu --- content/Recipes/files-w-configu.mdx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index a91a77b..f6cf7cc 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -107,7 +107,7 @@ example: ```json { "stores": { - "my-store": { + "file-store": { "type": "json-file", "configuration": { "path": "path/to/file.json" @@ -120,7 +120,7 @@ example: ```json { "stores": { - "my-store": { + "file-store": { "type": "ini-file", "configuration": { "path": "path/to/file.ini" @@ -135,7 +135,7 @@ example: ### Upsert values ```bash -configu upsert --store "my-store" --set "prod" --schema "./app.cfgu.json" \ +configu upsert --store "file-store" --set "prod" --schema "./app.cfgu.json" \ -c "BASE_URL=http://app.yourdomain.com" \ -c "SITE_CONTACT_EMAIL=info@yourdomain.com" ``` @@ -143,7 +143,7 @@ configu upsert --store "my-store" --set "prod" --schema "./app.cfgu.json" \ We can also easily add configs to additional environments like `test` ```bash -configu upsert --store "my-store" --set "test" --schema "./app.cfgu.json" \ +configu upsert --store "file-store" --set "test" --schema "./app.cfgu.json" \ -c "BASE_URL=http://app.test.yourdomain.com" -c "SITE_CONTACT_EMAIL=test@yourdomain.com" ``` @@ -152,7 +152,7 @@ configu upsert --store "my-store" --set "test" --schema "./app.cfgu.json" \ Similar to the way we previously used the Cfgu defaults we can evaluate and export from any store we need. ```bash -configu eval --store "my-store" --set "prod" --schema "./app.cfgu.json" \ +configu eval --store "file-store" --set "prod" --schema "./app.cfgu.json" \ | configu export --run "node app.js" ``` From e5ae89b20f473ce7b2124172d44e893eecd64ed0 Mon Sep 17 00:00:00 2001 From: Richard Date: Sun, 10 Sep 2023 12:19:35 +0300 Subject: [PATCH 8/9] docs: improve files recipe --- content/Recipes/files-w-configu.mdx | 46 ++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index f6cf7cc..4679be7 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -19,7 +19,10 @@ To complete the tutorial, you'll need: - Make sure that the files are already created when using the Configu CLI. -- When using a JSON file, make sure it is a root-level array. +- When using a JSON file, make sure it is a root-level array as such: +```json +[] +``` @@ -147,6 +150,47 @@ configu upsert --store "file-store" --set "test" --schema "./app.cfgu.json" \ -c "BASE_URL=http://app.test.yourdomain.com" -c "SITE_CONTACT_EMAIL=test@yourdomain.com" ``` +Upsert result: + + + +```json +[ + { + "key": "BASE_URL", + "set": "test", + "value": "http://app.test.yourdomain.com" + }, + { + "key": "SITE_CONTACT_EMAIL", + "set": "test", + "value": "test@yourdomain.com" + }, + { + "key": "BASE_URL", + "set": "prod", + "value": "http://app.yourdomain.co.il" + }, + { + "key": "SITE_CONTACT_EMAIL", + "set": "prod", + "value": "info@yourdomain.com" + } +] +``` + +```ini +[test] +BASE_URL=http://app.test.yourdomain.com +SITE_CONTACT_EMAIL=test@yourdomain.com + +[prod] +BASE_URL=http://app.yourdomain.com +SITE_CONTACT_EMAIL=info@yourdomain.com +``` + + + ### Export values Similar to the way we previously used the Cfgu defaults we can evaluate and export from any store we need. From d90146bd0b97befe74bbce3019803d8f84b2e81a Mon Sep 17 00:00:00 2001 From: Richard Akman Date: Tue, 19 Sep 2023 11:05:37 +0300 Subject: [PATCH 9/9] docs: fix json file link --- content/Recipes/files-w-configu.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/Recipes/files-w-configu.mdx b/content/Recipes/files-w-configu.mdx index 4679be7..e29f20e 100644 --- a/content/Recipes/files-w-configu.mdx +++ b/content/Recipes/files-w-configu.mdx @@ -13,7 +13,7 @@ and validating your new config values. Check out the tutorial below that shows h To complete the tutorial, you'll need: -- A [JSON file](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) or an [INI file](https://en.wikipedia.org/wiki/INI_file) +- A [JSON file](https://json.org) or an [INI file](https://en.wikipedia.org/wiki/INI_file) - [Configu's CLI](/cli-setup) - [hackathon-starter application](https://github.com/sahat/hackathon-starter)