Skip to content

Commit

Permalink
Merge pull request #366 from twistlock/plugable_secrets_backend
Browse files Browse the repository at this point in the history
Plugable secrets backend
  • Loading branch information
thaJeztah committed Sep 18, 2017
2 parents 37ac97c + 0ee9e05 commit 3edf97e
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 36 deletions.
26 changes: 21 additions & 5 deletions cli/command/formatter/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@ import (
)

const (
defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
defaultSecretTableFormat = "table {{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}"
secretIDHeader = "ID"
secretCreatedHeader = "CREATED"
secretUpdatedHeader = "UPDATED"
secretInspectPrettyTemplate Format = `ID: {{.ID}}
Name: {{.Name}}
secretInspectPrettyTemplate Format = `ID: {{.ID}}
Name: {{.Name}}
{{- if .Labels }}
Labels:
{{- range $k, $v := .Labels }}
- {{ $k }}{{if $v }}={{ $v }}{{ end }}
{{- end }}{{ end }}
Created at: {{.CreatedAt}}
Updated at: {{.UpdatedAt}}`
Driver: {{.Driver}}
Created at: {{.CreatedAt}}
Updated at: {{.UpdatedAt}}`
)

// NewSecretFormat returns a Format for rendering using a secret Context
Expand Down Expand Up @@ -61,6 +62,7 @@ func newSecretContext() *secretContext {
sCtx.header = map[string]string{
"ID": secretIDHeader,
"Name": nameHeader,
"Driver": driverHeader,
"CreatedAt": secretCreatedHeader,
"UpdatedAt": secretUpdatedHeader,
"Labels": labelsHeader,
Expand Down Expand Up @@ -89,6 +91,13 @@ func (c *secretContext) CreatedAt() string {
return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.CreatedAt)) + " ago"
}

func (c *secretContext) Driver() string {
if c.s.Spec.Driver == nil {
return ""
}
return c.s.Spec.Driver.Name
}

func (c *secretContext) UpdatedAt() string {
return units.HumanDuration(time.Now().UTC().Sub(c.s.Meta.UpdatedAt)) + " ago"
}
Expand Down Expand Up @@ -153,6 +162,13 @@ func (ctx *secretInspectContext) Labels() map[string]string {
return ctx.Secret.Spec.Labels
}

func (ctx *secretInspectContext) Driver() string {
if ctx.Secret.Spec.Driver == nil {
return ""
}
return ctx.Secret.Spec.Driver.Name
}

func (ctx *secretInspectContext) CreatedAt() string {
return command.PrettyPrint(ctx.Secret.CreatedAt)
}
Expand Down
6 changes: 3 additions & 3 deletions cli/command/formatter/secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ func TestSecretContextFormatWrite(t *testing.T) {
},
// Table format
{Context{Format: NewSecretFormat("table", false)},
`ID NAME CREATED UPDATED
1 passwords Less than a second ago Less than a second ago
2 id_rsa Less than a second ago Less than a second ago
`ID NAME DRIVER CREATED UPDATED
1 passwords Less than a second ago Less than a second ago
2 id_rsa Less than a second ago Less than a second ago
`},
{Context{Format: NewSecretFormat("table {{.Name}}", true)},
`NAME
Expand Down
49 changes: 36 additions & 13 deletions cli/command/secret/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (

type createOptions struct {
name string
driver string
file string
labels opts.ListOpts
}
Expand All @@ -27,17 +28,21 @@ func newSecretCreateCommand(dockerCli command.Cli) *cobra.Command {
}

cmd := &cobra.Command{
Use: "create [OPTIONS] SECRET file|-",
Use: "create [OPTIONS] SECRET [file|-]",
Short: "Create a secret from a file or STDIN as content",
Args: cli.ExactArgs(2),
Args: cli.RequiresRangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
options.name = args[0]
options.file = args[1]
if len(args) == 2 {
options.file = args[1]
}
return runSecretCreate(dockerCli, options)
},
}
flags := cmd.Flags()
flags.VarP(&options.labels, "label", "l", "Secret labels")
flags.StringVarP(&options.driver, "driver", "d", "", "Secret driver")
flags.SetAnnotation("driver", "version", []string{"1.31"})

return cmd
}
Expand All @@ -46,28 +51,26 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error {
client := dockerCli.Client()
ctx := context.Background()

var in io.Reader = dockerCli.In()
if options.file != "-" {
file, err := system.OpenSequential(options.file)
if err != nil {
return err
}
in = file
defer file.Close()
if options.driver != "" && options.file != "" {
return errors.Errorf("When using secret driver secret data must be empty")
}

secretData, err := ioutil.ReadAll(in)
secretData, err := readSecretData(dockerCli.In(), options.file)
if err != nil {
return errors.Errorf("Error reading content from %q: %v", options.file, err)
}

spec := swarm.SecretSpec{
Annotations: swarm.Annotations{
Name: options.name,
Labels: opts.ConvertKVStringsToMap(options.labels.GetAll()),
},
Data: secretData,
}
if options.driver != "" {
spec.Driver = &swarm.Driver{
Name: options.driver,
}
}

r, err := client.SecretCreate(ctx, spec)
if err != nil {
Expand All @@ -77,3 +80,23 @@ func runSecretCreate(dockerCli command.Cli, options createOptions) error {
fmt.Fprintln(dockerCli.Out(), r.ID)
return nil
}

func readSecretData(in io.ReadCloser, file string) ([]byte, error) {
// Read secret value from external driver
if file == "" {
return nil, nil
}
if file != "-" {
var err error
in, err = system.OpenSequential(file)
if err != nil {
return nil, err
}
defer in.Close()
}
data, err := ioutil.ReadAll(in)
if err != nil {
return nil, err
}
return data, nil
}
38 changes: 33 additions & 5 deletions cli/command/secret/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,11 @@ func TestSecretCreateErrors(t *testing.T) {
secretCreateFunc func(swarm.SecretSpec) (types.SecretCreateResponse, error)
expectedError string
}{
{
args: []string{"too_few"},
expectedError: "requires exactly 2 arguments",
},
{args: []string{"too", "many", "arguments"},
expectedError: "requires exactly 2 arguments",
expectedError: "requires at least 1 and at most 2 arguments",
},
{args: []string{"create", "--driver", "driver", "-"},
expectedError: "secret data must be empty",
},
{
args: []string{"name", filepath.Join("testdata", secretDataFile)},
Expand Down Expand Up @@ -75,6 +74,35 @@ func TestSecretCreateWithName(t *testing.T) {
assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String()))
}

func TestSecretCreateWithDriver(t *testing.T) {
expectedDriver := &swarm.Driver{
Name: "secret-driver",
}
name := "foo"

cli := test.NewFakeCli(&fakeClient{
secretCreateFunc: func(spec swarm.SecretSpec) (types.SecretCreateResponse, error) {
if spec.Name != name {
return types.SecretCreateResponse{}, errors.Errorf("expected name %q, got %q", name, spec.Name)
}

if !reflect.DeepEqual(spec.Driver.Name, expectedDriver.Name) {
return types.SecretCreateResponse{}, errors.Errorf("expected driver %v, got %v", expectedDriver, spec.Labels)
}

return types.SecretCreateResponse{
ID: "ID-" + spec.Name,
}, nil
},
})

cmd := newSecretCreateCommand(cli)
cmd.SetArgs([]string{name})
cmd.Flags().Set("driver", expectedDriver.Name)
assert.NoError(t, cmd.Execute())
assert.Equal(t, "ID-"+name, strings.TrimSpace(cli.OutBuffer().String()))
}

func TestSecretCreateWithLabels(t *testing.T) {
expectedLabels := map[string]string{
"lbl1": "Label-foo",
Expand Down
1 change: 1 addition & 0 deletions cli/command/secret/inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ func TestSecretInspectPretty(t *testing.T) {
}),
SecretID("secretID"),
SecretName("secretName"),
SecretDriver("driver"),
SecretCreatedAt(time.Time{}),
SecretUpdatedAt(time.Time{}),
), []byte{}, nil
Expand Down
1 change: 1 addition & 0 deletions cli/command/secret/ls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func TestSecretList(t *testing.T) {
SecretVersion(swarm.Version{Index: 11}),
SecretCreatedAt(time.Now().Add(-2*time.Hour)),
SecretUpdatedAt(time.Now().Add(-1*time.Hour)),
SecretDriver("driver"),
),
}, nil
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
ID: secretID
Name: secretName
ID: secretID
Name: secretName
Labels:
- lbl1=value1
Created at: 0001-01-01 00:00:00 +0000 utc
Updated at: 0001-01-01 00:00:00 +0000 utc
Driver: driver
Created at: 0001-01-01 00:00:00 +0000 utc
Updated at: 0001-01-01 00:00:00 +0000 utc
6 changes: 3 additions & 3 deletions cli/command/secret/testdata/secret-list-with-filter.golden
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ID NAME CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
ID NAME DRIVER CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
6 changes: 3 additions & 3 deletions cli/command/secret/testdata/secret-list.golden
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
ID NAME CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar 2 hours ago About an hour ago
ID NAME DRIVER CREATED UPDATED
ID-foo foo 2 hours ago About an hour ago
ID-bar bar driver 2 hours ago About an hour ago
9 changes: 9 additions & 0 deletions internal/test/builders/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ func SecretName(name string) func(secret *swarm.Secret) {
}
}

// SecretDriver sets the secret's driver name
func SecretDriver(driver string) func(secret *swarm.Secret) {
return func(secret *swarm.Secret) {
secret.Spec.Driver = &swarm.Driver{
Name: driver,
}
}
}

// SecretID sets the secret's ID
func SecretID(ID string) func(secret *swarm.Secret) {
return func(secret *swarm.Secret) {
Expand Down

0 comments on commit 3edf97e

Please sign in to comment.