Skip to content

Commit

Permalink
Add --file flag for docker secret create command
Browse files Browse the repository at this point in the history
This fix tries to address the issue raised in 28581 and 28927
where it is not possible to create a secret from a file (only
through STDIN).

This fix add a flag `--file` to `docker secret create` so that
it is possible to create a secret from a file with:
```
docker secret create --file secret.in secret.name
```

or
```
echo TEST | docker secret create --file - secret.name
```

Related docs has been updated.

An integration test has been added to cover the changes.

This fix fixes 28581.
This fix is related to 28927.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
  • Loading branch information
yongtang committed Dec 13, 2016
1 parent cda0454 commit c6f0b7f
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
25 changes: 21 additions & 4 deletions cli/command/secret/create.go
Expand Up @@ -2,20 +2,22 @@ package secret

import (
"fmt"
"io"
"io/ioutil"
"os"

"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/cli"
"github.com/docker/docker/cli/command"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/system"
runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)

type createOptions struct {
name string
file string
labels opts.ListOpts
}

Expand All @@ -26,7 +28,7 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command {

cmd := &cobra.Command{
Use: "create [OPTIONS] SECRET",
Short: "Create a secret using stdin as content",
Short: "Create a secret from a file or STDIN as content",
Args: cli.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
createOpts.name = args[0]
Expand All @@ -35,6 +37,7 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
}
flags := cmd.Flags()
flags.VarP(&createOpts.labels, "label", "l", "Secret labels")
flags.StringVarP(&createOpts.file, "file", "f", "", "Read from a file or STDIN ('-')")

return cmd
}
Expand All @@ -43,9 +46,23 @@ func runSecretCreate(dockerCli *command.DockerCli, options createOptions) error
client := dockerCli.Client()
ctx := context.Background()

secretData, err := ioutil.ReadAll(os.Stdin)
if options.file == "" {
return fmt.Errorf("Please specify either a file name or STDIN ('-') with --file")
}

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()
}

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

spec := swarm.SecretSpec{
Expand Down
27 changes: 20 additions & 7 deletions docs/reference/commandline/secret_create.md
Expand Up @@ -16,23 +16,36 @@ keywords: ["secret, create"]
# secret create

```Markdown
Usage: docker secret create [OPTIONS] SECRET
Usage: docker secret create [OPTIONS] SECRET

Create a secret from a file or STDIN as content

Create a secret using stdin as content
Options:
--help Print usage
-l, --label list Secret labels (default [])
-f, --file string Read from a file or STDIN ('-')
--help Print usage
-l, --label list Secret labels (default [])
```

Creates a secret using standard input for the secret content. You must run this
Creates a secret using standard input or from a file for the secret content. You must run this
command on a manager node.

## Examples

### Create a secret

```bash
$ cat secret.json | docker secret create secret.json
$ cat secret.json | docker secret create -f - secret.json
mhv17xfe3gh6xc4rij5orpfds

$ docker secret ls
ID NAME CREATED UPDATED SIZE
mhv17xfe3gh6xc4rij5orpfds secret.json 2016-10-27 23:25:43.909181089 +0000 UTC 2016-10-27 23:25:43.909181089 +0000 UTC 1679
```

### Create a secret with a file

```bash
$ docker secret create --file secret.in secret.json
mhv17xfe3gh6xc4rij5orpfds

$ docker secret ls
Expand All @@ -43,7 +56,7 @@ mhv17xfe3gh6xc4rij5orpfds secret.json 2016-10-27 23:25:43.90918108
### Create a secret with labels

```bash
$ cat secret.json | docker secret create secret.json --label env=dev --label rev=20161102
$ cat secret.json | docker secret create secret.json -f - --label env=dev --label rev=20161102
jtn7g6aukl5ky7nr9gvwafoxh

$ docker secret inspect secret.json
Expand Down
34 changes: 34 additions & 0 deletions integration-cli/docker_cli_secret_create_test.go
Expand Up @@ -3,6 +3,10 @@
package main

import (
"io/ioutil"
"os"
"strings"

"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check"
Expand Down Expand Up @@ -104,3 +108,33 @@ func (s *DockerSwarmSuite) TestSecretCreateResolve(c *check.C) {
c.Assert(out, checker.Not(checker.Contains), id)
c.Assert(out, checker.Not(checker.Contains), fake)
}

func (s *DockerSwarmSuite) TestSecretCreateWithFile(c *check.C) {
d := s.AddDaemon(c, true, true)

testFile, err := ioutil.TempFile("", "secretCreateTest")
c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file"))
defer os.Remove(testFile.Name())

testData := "TESTINGDATA"
_, err = testFile.Write([]byte(testData))
c.Assert(err, checker.IsNil, check.Commentf("failed to write to temporary file"))

testName := "test_secret"
out, err := d.Cmd("secret", "create", "--file", testFile.Name(), testName)
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "", check.Commentf(out))

id := strings.TrimSpace(out)
secret := d.GetSecret(c, id)
c.Assert(secret.Spec.Name, checker.Equals, testName)

testName = "test_secret_2"
out, err = d.Cmd("secret", "create", testName, "-f", testFile.Name())
c.Assert(err, checker.IsNil)
c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "", check.Commentf(out))

id = strings.TrimSpace(out)
secret = d.GetSecret(c, id)
c.Assert(secret.Spec.Name, checker.Equals, testName)
}

0 comments on commit c6f0b7f

Please sign in to comment.