Skip to content

Commit

Permalink
Implement plain parameters.
Browse files Browse the repository at this point in the history
Fixes #4
  • Loading branch information
Eugene Dementiev authored and ekini committed Dec 10, 2018
1 parent 961c593 commit b20587f
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 22 deletions.
40 changes: 38 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 18 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ All parameters must be in JSON format, i.e.:
}
```

If a few parameters are specified, all JSON entities will be read and merged into one, overriding existing keys, i.e.
If several parameters are specified, all JSON entities will be read and merged into one, overriding existing keys, i.e.

Parameter one:
```
Expand All @@ -39,6 +39,10 @@ The result will be merged as this:
}
```

One can also specify `--plain-name` and `--plain-path` command line options to read _plain_ parameters that are not in JSON format.
`ssm-parent` takes the value as is, and constructs a key name from the `basename parameter`,
i.e. a SSM Parameter `/project/environment/myParameter` with value `supervalue` will be exported as `myParameter=supervalue`.

### How to use


Expand All @@ -48,7 +52,10 @@ That should be pretty self-explanatory.
SSM-Parent is a docker entrypoint.
It gets specified parameters (possibly secret) from AWS SSM Parameter Store,
then exports them to the underlying process.
then exports them to the underlying process. Or creates a .env file to be consumed by an application.
It reads parameters in the following order: path->name->plain-path->plain-name.
So that every rightmost parameter overrides the previous one.
Usage:
ssm-parent [command]
Expand All @@ -60,12 +67,15 @@ Available Commands:
run Runs the specified command
Flags:
-e, --expand Expand arguments and values using shell-style syntax
-h, --help help for ssm-parent
-n, --name stringArray Name of the SSM parameter to retrieve. Can be specified multiple times.
-p, --path stringArray Path to a SSM parameter. Can be specified multiple times.
-r, --recursive Walk through the provided SSM paths recursively.
-s, --strict Strict mode. Fail if found less parameters than number of names.
-e, --expand Expand arguments and values using shell-style syntax
-h, --help help for ssm-parent
-n, --name stringArray Name of the SSM parameter to retrieve. Expects JSON in the value. Can be specified multiple times.
-p, --path stringArray Path to a SSM parameter. Expects JSON in the value. Can be specified multiple times.
--plain-name stringArray Name of the SSM parameter to retrieve. Expects actual parameter in the value. Can be specified multiple times.
--plain-path stringArray Path to a SSM parameter. Expects actual parameter in the value. Can be specified multiple times.
-r, --recursive Walk through the provided SSM paths recursively.
-s, --strict Strict mode. Fail if found less parameters than number of names.
--version version for ssm-parent
Use "ssm-parent [command] --help" for more information about a command.
```
Expand Down
2 changes: 1 addition & 1 deletion cmd/dotenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var dotenvCmd = &cobra.Command{
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
megamap := make(map[string]string)
parameters, err := ssm.GetParameters(names, paths, expand, strict, recursive)
parameters, err := ssm.GetParameters(names, paths, plainNames, plainPaths, expand, strict, recursive)
if err != nil {
log.WithError(err).Fatal("Can't get parameters")
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var printCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) {

megamap := make(map[string]string)
parameters, err := ssm.GetParameters(names, paths, expand, strict, recursive)
parameters, err := ssm.GetParameters(names, paths, plainNames, plainPaths, expand, strict, recursive)
if err != nil {
log.WithError(err).Fatal("Can't get parameters")
}
Expand Down
23 changes: 15 additions & 8 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (
)

var (
paths []string
names []string
recursive bool
strict bool
expand bool
paths []string
names []string
plainPaths []string
plainNames []string
recursive bool
strict bool
expand bool
)

// rootCmd represents the base command when called without any subcommands
Expand All @@ -22,7 +24,10 @@ var rootCmd = &cobra.Command{
Long: `SSM-Parent is a docker entrypoint.
It gets specified parameters (possibly secret) from AWS SSM Parameter Store,
then exports them to the underlying process.
then exports them to the underlying process. Or creates a .env file to be consumed by an application.
It reads parameters in the following order: path->name->plain-path->plain-name.
So that every rightmost parameter overrides the previous one.
`,
}

Expand All @@ -35,8 +40,10 @@ func Execute(version string) {
}

func init() {
rootCmd.PersistentFlags().StringArrayVarP(&paths, "path", "p", []string{}, "Path to a SSM parameter. Can be specified multiple times.")
rootCmd.PersistentFlags().StringArrayVarP(&names, "name", "n", []string{}, "Name of the SSM parameter to retrieve. Can be specified multiple times.")
rootCmd.PersistentFlags().StringArrayVarP(&paths, "path", "p", []string{}, "Path to a SSM parameter. Expects JSON in the value. Can be specified multiple times.")
rootCmd.PersistentFlags().StringArrayVarP(&names, "name", "n", []string{}, "Name of the SSM parameter to retrieve. Expects JSON in the value. Can be specified multiple times.")
rootCmd.PersistentFlags().StringArrayVarP(&plainPaths, "plain-path", "", []string{}, "Path to a SSM parameter. Expects actual parameter in the value. Can be specified multiple times.")
rootCmd.PersistentFlags().StringArrayVarP(&plainNames, "plain-name", "", []string{}, "Name of the SSM parameter to retrieve. Expects actual parameter in the value. Can be specified multiple times.")
rootCmd.PersistentFlags().BoolVarP(&recursive, "recursive", "r", false, "Walk through the provided SSM paths recursively.")
rootCmd.PersistentFlags().BoolVarP(&strict, "strict", "s", false, "Strict mode. Fail if found less parameters than number of names.")
rootCmd.PersistentFlags().BoolVarP(&expand, "expand", "e", false, "Expand arguments and values using shell-style syntax")
Expand Down
2 changes: 1 addition & 1 deletion cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ var runCmd = &cobra.Command{
var cmdArgs []string

megamap := make(map[string]string)
parameters, err := ssm.GetParameters(names, paths, expand, strict, recursive)
parameters, err := ssm.GetParameters(names, paths, plainNames, plainPaths, expand, strict, recursive)
if err != nil {
log.WithError(err).Fatal("Can't get parameters")
}
Expand Down
88 changes: 87 additions & 1 deletion ssm/parameters.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ssm
import (
"encoding/json"
"fmt"
goPath "path"

"github.com/apex/log"
"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -57,6 +58,30 @@ func getJsonSSMParametersByPaths(paths []string, strict, recursive bool) (parame
return
}

func getPlainSSMParametersByPaths(paths []string, strict, recursive bool) (parameters []map[string]string, err error) {
err = makeSession()
if err != nil {
log.WithError(err).Fatal("Can't create session") // fail early here
}
s := ssm.New(localSession)
for _, path := range paths {
response, innerErr := s.GetParametersByPath(&ssm.GetParametersByPathInput{
Path: aws.String(path),
WithDecryption: aws.Bool(true),
Recursive: aws.Bool(recursive),
})
if innerErr != nil {
err = multierror.Append(err, fmt.Errorf("Can't get parameters from path '%s': %s", path, innerErr))
}
for _, parameter := range response.Parameters {
values := make(map[string]string)
values[goPath.Base(aws.StringValue(parameter.Name))] = aws.StringValue(parameter.Value)
parameters = append(parameters, values)
}
}
return
}

func getJsonSSMParameters(names []string, strict bool) (parameters []map[string]string, err error) {
err = makeSession()
if err != nil {
Expand Down Expand Up @@ -93,13 +118,51 @@ func getJsonSSMParameters(names []string, strict bool) (parameters []map[string]
return
}

func GetParameters(names, paths []string, expand, strict, recursive bool) (parameters []map[string]string, err error) {
func getPlainSSMParameters(names []string, strict bool) (parameters []map[string]string, err error) {
err = makeSession()
if err != nil {
log.WithError(err).Fatal("Can't create session") // fail early here
}
s := ssm.New(localSession)
response, err := s.GetParameters(&ssm.GetParametersInput{
Names: aws.StringSlice(names),
WithDecryption: aws.Bool(true),
})
if err != nil {
return nil, err
}
if len(response.Parameters) < len(names) {
if strict {
err = multierror.Append(err, fmt.Errorf("Found %d parameters from %d names", len(response.Parameters), len(names)))
} else {
var found []string
for _, f := range response.Parameters {
found = append(found, *f.Name)
}
diff := stringSliceDifference(names, found)
log.WithFields(log.Fields{"missing_names": diff}).Warn("Some parameters have not been found")
}
}
for _, parameter := range response.Parameters {
values := make(map[string]string)
values[goPath.Base(aws.StringValue(parameter.Name))] = aws.StringValue(parameter.Value)
parameters = append(parameters, values)
}
return
}

func GetParameters(names, paths, plainNames, plainPaths []string, expand, strict, recursive bool) (parameters []map[string]string, err error) {
localNames := names
localPaths := paths
localPlainNames := plainNames
localPlainPaths := plainPaths
if expand {
localNames = ExpandArgs(names)
localPaths = ExpandArgs(paths)
localPlainNames = ExpandArgs(plainNames)
localPlainPaths = ExpandArgs(plainPaths)
}

if len(localPaths) > 0 {
parametersFromPaths, err := getJsonSSMParametersByPaths(localPaths, strict, recursive)
if err != nil {
Expand All @@ -122,5 +185,28 @@ func GetParameters(names, paths []string, expand, strict, recursive bool) (param
parameters = append(parameters, parameter)
}
}
if len(localPlainPaths) > 0 {
parametersFromPlainPaths, err := getPlainSSMParametersByPaths(localPlainPaths, strict, recursive)
if err != nil {
log.WithError(err).WithFields(
log.Fields{"plain_paths": localPaths},
).Fatal("Can't get plain parameters by paths")
}
for _, parameter := range parametersFromPlainPaths {
parameters = append(parameters, parameter)
}
}

if len(localPlainNames) > 0 {
parametersFromPlainNames, err := getPlainSSMParameters(localPlainNames, strict)
if err != nil {
log.WithError(err).WithFields(
log.Fields{"plain_names": localNames},
).Fatal("Can't get plain parameters by names")
}
for _, parameter := range parametersFromPlainNames {
parameters = append(parameters, parameter)
}
}
return
}

0 comments on commit b20587f

Please sign in to comment.