Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add keys option #4

Merged
merged 4 commits into from
Sep 1, 2020
Merged
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: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ json2env execute commands with environment variables made from JSON.
## Synopsis

```go
$ echo '{"key":"value"}' | json2env /path/to/command [...]
$ echo '{"key":"value"}' | json2env --keys "key" /path/to/command [...]
```

```go
$ echo '{"examplekey1":"value1", "examplekey2":"value2"}' | json2env env | grep examplekey
$ echo '{"examplekey1":"value1", "examplekey2":"value2", "examplekey3":"value3"}' | json2env --keys "examplekey1,examplekey2" env | grep examplekey
examplekey1=value1
examplekey2=value2
```
Expand All @@ -35,6 +35,8 @@ I wanted to pass secret information as an environment variable to the ECS contai

Since this feature is implemented in ECS on EC2, this feature will probably be implemented in Fargate in the future, so I wanted something to convert JSON to environment variables that can be used in the meantime.

And I made it mandatory to specify the name of the environment variable to use so that I can safely remove this tool when I no longer use it.

## Installation

```console
Expand Down
27 changes: 23 additions & 4 deletions json2env.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io"
"log"
"os/exec"
"strings"

"github.com/pkg/errors"
)
Expand All @@ -26,6 +27,7 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer, inS
}
fs.SetOutput(errStream)
ver := fs.Bool("version", false, "display version")
keys := fs.String("keys", "", "conmma separated environment variable names that you want to export")

if err := fs.Parse(argv); err != nil {
return err
Expand All @@ -37,6 +39,11 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer, inS
if *ver {
return printVersion(outStream)
}

if *keys == "" {
return errors.New("keys option is required")
}

var envJSON map[string]string
err := json.NewDecoder(inStream).Decode(&envJSON)
if err != nil {
Expand All @@ -47,22 +54,34 @@ func Run(ctx context.Context, argv []string, outStream, errStream io.Writer, inS
return errors.Wrap(err, "failed to decode input")
}
}
newEnv := makeNewEnv(env, envJSON)

newEnv, err := makeNewEnv(env, envJSON, strings.Split(*keys, ","))
if err != nil {
return errors.Wrapf(err, "failed to create new env")
}
if err := runCommand(command, newEnv, outStream, errStream); err != nil {
return errors.Wrapf(err, "failed to run command %+s", command)
}

return nil
}

func makeNewEnv(origEnv []string, json map[string]string) []string {
func makeNewEnv(origEnv []string, json map[string]string, envNames []string) ([]string, error) {
newEnv := []string{}
for key, value := range json {
newJSON := make(map[string]string)
for _, name := range envNames {
value, ok := json[name]
if !ok {
return newEnv, errors.New(fmt.Sprintf("%s is not exists in json", name))
}
newJSON[name] = value
}
for key, value := range newJSON {
newEnv = append(newEnv, fmt.Sprintf("%s=%s", key, value))
}
// if same key exists origEnv and newEnv, json parameter overwrite the origEnv
newEnv = append(origEnv, newEnv...)
return newEnv
return newEnv, nil
}

func printVersion(out io.Writer) error {
Expand Down
46 changes: 38 additions & 8 deletions json2env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,39 @@ import (
)

func TestNormal(t *testing.T) {
stdin := bytes.NewBufferString("{}")
err := Run(context.Background(), []string{"ls"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
stdin := bytes.NewBufferString("{\"test\": \"test\"}")
err := Run(context.Background(), []string{"-keys", "test", "ls"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
if err != nil {
t.Fatalf("failed test %#v", err)
}
}

func TestErrorIfNotJson(t *testing.T) {
stdin := bytes.NewBufferString("{deadbeaf")
err := Run(context.Background(), []string{"ls"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
err := Run(context.Background(), []string{"-keys", "test", "ls"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
if err == nil {
t.Fatalf("error not occurred, failed test %#v", err)
t.Fatalf("error not occurred, failed test")
}
}

func TestErrorIfSpecifyNotExistsKeysJson(t *testing.T) {
stdin := bytes.NewBufferString("{\"test\": \"test\"}")
err := Run(context.Background(), []string{"-keys", "notExists", "ls"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
if err == nil {
t.Fatalf("error not occurred, failed test")
}
}
func TestErrorIfCommandNotExists(t *testing.T) {
stdin := bytes.NewBufferString("{deadbeaf")
err := Run(context.Background(), []string{}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
stdin := bytes.NewBufferString("{\"test\": \"test\"}")
err := Run(context.Background(), []string{"-keys", "test"}, &bytes.Buffer{}, &bytes.Buffer{}, stdin, []string{})
if err == nil {
t.Fatalf("error not occurred, failed test %#v", err)
}
}
func TestEnv(t *testing.T) {
stdin := bytes.NewBufferString("{\"a\": \"after\"}")
var outStream bytes.Buffer
err := Run(context.Background(), []string{"env"}, &outStream, &bytes.Buffer{}, stdin, []string{"a=before"})
err := Run(context.Background(), []string{"-keys", "a", "env"}, &outStream, &bytes.Buffer{}, stdin, []string{"a=before"})
if err != nil {
t.Fatalf("failed run %#v", err)
}
Expand All @@ -45,11 +52,34 @@ func TestEnv(t *testing.T) {
}

func TestGetEnv(t *testing.T) {
env := makeNewEnv([]string{"a=b", "b=b"}, map[string]string{"b": "c", "d": "e"})
env, err := makeNewEnv([]string{"a=b", "b=b"}, map[string]string{"b": "c", "d": "e"}, []string{"b", "d"})
if err != nil {
t.Fatalf("failed err:%#v", err)
}
sort.Strings(env)
expect := []string{"a=b", "b=b", "b=c", "d=e"}
sort.Strings(expect)
if !reflect.DeepEqual(env, expect) {
t.Fatalf("failed getEnv test expect: %#v, got: %#v", expect, env)
}
}

func TestGetSomeEnv(t *testing.T) {
env, err := makeNewEnv([]string{"a=b", "b=b"}, map[string]string{"b": "c", "d": "e"}, []string{"b"})
if err != nil {
t.Fatalf("failed err:%#v", err)
}
sort.Strings(env)
expect := []string{"a=b", "b=b", "b=c"}
sort.Strings(expect)
if !reflect.DeepEqual(env, expect) {
t.Fatalf("failed getEnv test expect: %#v, got: %#v", expect, env)
}
}

func TestNotExistedKey(t *testing.T) {
_, err := makeNewEnv([]string{"a=b", "b=b"}, map[string]string{"b": "c", "d": "e"}, []string{"x"})
if err == nil {
t.Fatal("failed err")
}
}