-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit be533f7
Showing
10 changed files
with
385 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# some examples | ||
|
||
E2F_name_someini=testfile.ini | ||
E2F_data_someini=key=value | ||
|
||
E2F_name_somejson=testfile.json | ||
E2F_data_somejson={"key": "value"} | ||
|
||
E2F_name_sometoml=testfile.toml | ||
E2F_data_sometoml=key=value | ||
|
||
E2F_name_someyaml=testfile.yaml | ||
E2F_data_someyaml=key: value | ||
|
||
E2F_name_somefullpath=/Users/barnabykeene/Desktop/env2file/fromfullpath.yaml | ||
E2F_data_somefullpath=key: value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: goreleaser | ||
|
||
on: | ||
pull_request: | ||
push: | ||
|
||
jobs: | ||
goreleaser: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v1 | ||
- name: Set up Go | ||
uses: actions/setup-go@v1 | ||
- name: Docker Login | ||
uses: azure/docker-login@v1 | ||
with: | ||
username: ${{ secrets.DOCKER_USERNAME }} | ||
password: ${{ secrets.DOCKER_PASSWORD }} | ||
- name: Run GoReleaser | ||
uses: goreleaser/goreleaser-action@v1 | ||
with: | ||
version: latest | ||
args: release | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dist/ | ||
test/* | ||
!test/.gitkeep |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
project_name: env2file | ||
builds: | ||
- env: | ||
- CGO_ENABLED=0 | ||
goos: | ||
- linux | ||
- windows | ||
- darwin | ||
goarch: | ||
- amd64 | ||
- arm | ||
- arm64 | ||
checksum: | ||
name_template: "checksums.txt" | ||
snapshot: | ||
name_template: "{{ .Tag }}-next" | ||
changelog: | ||
sort: asc | ||
filters: | ||
exclude: | ||
- "^docs:" | ||
- "^test:" | ||
dockers: | ||
- image_templates: | ||
- southclaws/env2file:latest | ||
dockerfile: Dockerfile | ||
nfpms: | ||
- vendor: Southclaws | ||
homepage: https://github.com/Southclaws/env2file | ||
maintainer: Southclaws <hello@southcla.ws> | ||
description: A tiny utility for turning environment variable values into files. | ||
license: GPLv3 | ||
formats: | ||
- deb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
FROM scratch | ||
ADD /env2file /bin/env2file | ||
ENTRYPOINT ["env2file"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2017 Barnaby "Southclaws" Keene | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# env2file | ||
|
||
A tiny utility for turning environment variable values into files. | ||
|
||
```sh | ||
go get github.com/Southclaws/env2file | ||
``` | ||
|
||
```sh | ||
docker pull southclaws/env2file | ||
``` | ||
|
||
## Why | ||
|
||
Sometimes you need to deploy a containerised application and it requires a file for configuration. That means you have | ||
to think about where that file goes, how to automate its creation and maybe even version control so you can record | ||
configuration change history. | ||
|
||
This simplifies that by allowing you to store small-ish configuration files as environment variables in your container | ||
management system. | ||
|
||
It's kind of like ConfigMaps in Kubernetes. | ||
|
||
## How | ||
|
||
This is mainly designed for deployments that use Docker Compose. The intended usage is: | ||
|
||
1. Add env2file to your compose config | ||
2. Mount a volume/directory to both env2file and the app that wants a file | ||
3. Set some environment variables on the env2file container | ||
4. Everything boots up, env2file creates the files, they are visible to the app, app is happy! | ||
|
||
env2file will search for environment variables that match the following format: | ||
|
||
```env | ||
EF_(name|data)_(\w+) | ||
``` | ||
|
||
Where the first group is either `name` or `data` and the second group is some unique name. | ||
|
||
Each "target" requires two variables: one for the filename and one for the contents. So if you wanted to create a file | ||
named `config.json` with some JSON in it, you'd declare two variables: | ||
|
||
```env | ||
EF_name_cfg=config.json | ||
EF_data_cfg={"some":"json"} | ||
``` | ||
|
||
The unique key (`cfg` in the above example) permits for as many targets as you want: | ||
|
||
```env | ||
EF_name_cfg=config.json | ||
EF_data_cfg={"some":"json"} | ||
EF_name_auth=auth.yaml | ||
EF_data_auth=some: yaml | ||
EF_name_other=other_stuff | ||
EF_data_other=my secret pizza recipe | ||
``` | ||
|
||
```yaml | ||
version: "3.5" | ||
services: | ||
someapp: | ||
image: some/app | ||
volumes: | ||
- /shared/config:/etc/someapp/config | ||
env2file: | ||
image: southclaws/env2file | ||
environment: | ||
E2F_name_config: /config/someapp-config.json | ||
E2F_data_config: | | ||
{ | ||
"host": "127.0.0.1", | ||
"port": 4444 | ||
} | ||
E2F_name_clientid: /config/client_identifier | ||
E2F_data_clientid: 37d060be-fb2e-11e9-99d0-645aede9143b | ||
volumes: | ||
- /shared/config:/config | ||
``` | ||
In the above example, `some/app` will see a file named `someapp-config.json` inside the `/etc/someapp/config` directory | ||
with the contents: | ||
|
||
```json | ||
{ | ||
"host": "127.0.0.1", | ||
"port": 4444 | ||
} | ||
``` | ||
|
||
And a file named `client_identifier` inside the same directory that contains simply | ||
`37d060be-fb2e-11e9-99d0-645aede9143b`. | ||
|
||
--- | ||
|
||
You can demo/play locally with the following docker run line: | ||
|
||
```sh | ||
docker run -v$(pwd)/files:/files -e EF_name_target=/files/target.json -e EF_data_target='{"a":"b"}' southclaws/env2file | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
) | ||
|
||
const prefix = "EF_" | ||
|
||
// target represents a filename (full path) and its contents. | ||
type target struct { | ||
name string | ||
data string | ||
} | ||
|
||
// writes the contents of a target to its desired file. | ||
func (t target) write() error { | ||
f, err := os.Create(t.name) | ||
if err != nil { | ||
return err | ||
} | ||
if _, err := f.WriteString(t.data); err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
// aggregateFromEnv collects a set of targets from the given env vars | ||
// it only accepts pairs, so if a `name` is missing a `data` then it's ignored | ||
func aggregateFromEnv(envs []string) ([]target, []error) { | ||
targ := make(map[string]struct{}) | ||
name := make(map[string]string) | ||
data := make(map[string]string) | ||
errs := []error{} | ||
for _, e := range envs { | ||
key, value := splitEnvironmentVariable(e) | ||
if !strings.HasPrefix(key, prefix) { | ||
continue | ||
} | ||
t, n, err := decodeKey(key) | ||
if err != nil { | ||
errs = append(errs, err) | ||
continue | ||
} | ||
targ[n] = struct{}{} | ||
switch t { | ||
case "name": | ||
name[n] = value | ||
case "data": | ||
data[n] = value | ||
} | ||
} | ||
targets, joinErrors := join(targ, name, data) | ||
return targets, append(errs, joinErrors...) | ||
} | ||
|
||
// joins the aggregated sets of separate variables into a list of targets | ||
func join(t map[string]struct{}, n, d map[string]string) ([]target, []error) { | ||
all := []target{} | ||
errs := []error{} | ||
for key := range t { | ||
var t target | ||
var ok bool | ||
if t.name, ok = n[key]; !ok { | ||
errs = append(errs, fmt.Errorf("missing target config for %s", key)) | ||
continue | ||
} | ||
if t.data, ok = d[key]; !ok { | ||
errs = append(errs, fmt.Errorf("missing target config for %s", key)) | ||
continue | ||
} | ||
all = append(all, t) | ||
} | ||
return all, errs | ||
} | ||
|
||
func splitEnvironmentVariable(keyvalue string) (key, value string) { | ||
v := strings.SplitN(keyvalue, "=", 2) | ||
return v[0], v[1] | ||
} | ||
|
||
// splits a key in the E2F format into a target type and a target name | ||
// errors if the pattern is wrong such as having too few _ separators | ||
func decodeKey(key string) (targetType string, name string, err error) { | ||
v := strings.SplitN(key, "_", 3) | ||
if len(v) != 3 { | ||
return "", "", fmt.Errorf("%s has invalid pattern", key) | ||
} | ||
return v[1], v[2], nil | ||
} | ||
|
||
func main() { | ||
targets, errors := aggregateFromEnv(os.Environ()) | ||
for _, e := range errors { | ||
fmt.Println("Error:", e) | ||
} | ||
for _, t := range targets { | ||
if err := t.write(); err != nil { | ||
fmt.Println(err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func Test_aggregateFromEnv(t *testing.T) { | ||
tests := []struct { | ||
variables []string | ||
wantTargs []target | ||
wantError []error | ||
}{ | ||
{ | ||
[]string{`EF_name_file=file.json`, `EF_data_file={"a":0}`}, | ||
[]target{{name: "file.json", data: `{"a":0}`}}, | ||
[]error{}, | ||
}, | ||
{ | ||
[]string{`EF_name_file=fi_le.json`, `EF_data_file={"a":0}`}, | ||
[]target{{name: "fi_le.json", data: `{"a":0}`}}, | ||
[]error{}, | ||
}, | ||
{ | ||
[]string{`EF_name_fi_le=fi_le.json`, `EF_data_fi_le={"a":0}`}, | ||
[]target{{name: "fi_le.json", data: `{"a":0}`}}, | ||
[]error{}, | ||
}, | ||
} | ||
for ii, tt := range tests { | ||
t.Run(fmt.Sprint(ii), func(t *testing.T) { | ||
gotTargs, gotError := aggregateFromEnv(tt.variables) | ||
equal(t, tt.wantTargs, gotTargs) | ||
equal(t, tt.wantError, gotError) | ||
}) | ||
} | ||
} | ||
|
||
func Test_decodeKey(t *testing.T) { | ||
tests := []struct { | ||
key string | ||
wantType string | ||
wantName string | ||
wantError error | ||
}{ | ||
{"EF_name_target", "name", "target", nil}, | ||
{"EF_data_target", "data", "target", nil}, | ||
{"EF_name_target_underscore", "name", "target_underscore", nil}, | ||
{"EF_name_", "name", "", nil}, | ||
{"EF_name", "", "", fmt.Errorf("EF_name has invalid pattern")}, | ||
{"EF_", "", "", fmt.Errorf("EF_ has invalid pattern")}, | ||
{"EF", "", "", fmt.Errorf("EF has invalid pattern")}, | ||
} | ||
for ii, tt := range tests { | ||
t.Run(fmt.Sprint(ii), func(t *testing.T) { | ||
gotType, gotName, gotError := decodeKey(tt.key) | ||
equal(t, tt.wantError, gotError) | ||
if gotError == nil { | ||
equal(t, tt.wantType, gotType) | ||
equal(t, tt.wantName, gotName) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
// helpers | ||
|
||
func equal(t *testing.T, expected, actual interface{}) { | ||
if !reflect.DeepEqual(expected, actual) { | ||
t.Errorf("%v != %v", expected, actual) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
module github.com/Southclaws/env2file | ||
|
||
go 1.0 |