Introduce `secret` management command and ECS implementation

Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
This commit is contained in:
Nicolas De Loof 2020-08-20 15:55:55 +02:00
parent 35242f89d3
commit 32adf3e4e6
No known key found for this signature in database
GPG Key ID: 9858809D6F8F6E7E
5 changed files with 210 additions and 2 deletions

View File

@ -42,8 +42,8 @@ func Command() *cobra.Command {
} }
// define flags for backward compatibility with com.docker.cli // define flags for backward compatibility with com.docker.cli
flags := cmd.Flags() flags := cmd.Flags()
flags.StringP("username", "u", "", "Username") flags.StringP("username", "u", "", "username")
flags.StringP("password", "p", "", "Password") flags.StringP("password", "p", "", "password")
flags.BoolP("password-stdin", "", false, "Take the password from stdin") flags.BoolP("password-stdin", "", false, "Take the password from stdin")
mobyflags.AddMobyFlagsForRetrocompatibility(flags) mobyflags.AddMobyFlagsForRetrocompatibility(flags)

165
cli/cmd/secrets.go Normal file
View File

@ -0,0 +1,165 @@
/*
Copyright 2020 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"fmt"
"io"
"os"
"strings"
"text/tabwriter"
"github.com/spf13/cobra"
"github.com/docker/api/client"
"github.com/docker/api/secrets"
)
type createSecretOptions struct {
Label string
Username string
Password string
Description string
}
// SecretCommand manage secrets
func SecretCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "secret",
Short: "Manages secrets",
}
cmd.AddCommand(
createSecret(),
inspectSecret(),
listSecrets(),
deleteSecret(),
)
return cmd
}
func createSecret() *cobra.Command {
opts := createSecretOptions{}
cmd := &cobra.Command{
Use: "create NAME",
Short: "Creates a secret.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := client.New(cmd.Context())
if err != nil {
return err
}
name := args[0]
secret := secrets.NewSecret(name, opts.Username, opts.Password, opts.Description)
id, err := c.SecretsService().CreateSecret(cmd.Context(), secret)
if err != nil {
return err
}
fmt.Println(id)
return nil
},
}
cmd.Flags().StringVarP(&opts.Username, "username", "u", "", "username")
cmd.Flags().StringVarP(&opts.Password, "password", "p", "", "password")
cmd.Flags().StringVarP(&opts.Description, "description", "d", "", "Secret description")
return cmd
}
func inspectSecret() *cobra.Command {
cmd := &cobra.Command{
Use: "inspect ID",
Short: "Displays secret details",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := client.New(cmd.Context())
if err != nil {
return err
}
secret, err := c.SecretsService().InspectSecret(cmd.Context(), args[0])
if err != nil {
return err
}
out, err := secret.ToJSON()
if err != nil {
return err
}
fmt.Println(out)
return nil
},
}
return cmd
}
func listSecrets() *cobra.Command {
cmd := &cobra.Command{
Use: "list",
Aliases: []string{"ls"},
Short: "List secrets stored for the existing account.",
RunE: func(cmd *cobra.Command, args []string) error {
c, err := client.New(cmd.Context())
if err != nil {
return err
}
list, err := c.SecretsService().ListSecrets(cmd.Context())
if err != nil {
return err
}
printList(os.Stdout, list)
return nil
},
}
return cmd
}
type deleteSecretOptions struct {
recover bool
}
func deleteSecret() *cobra.Command {
opts := deleteSecretOptions{}
cmd := &cobra.Command{
Use: "delete NAME",
Aliases: []string{"rm", "remove"},
Short: "Removes a secret.",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
c, err := client.New(cmd.Context())
if err != nil {
return err
}
return c.SecretsService().DeleteSecret(cmd.Context(), args[0], opts.recover)
},
}
cmd.Flags().BoolVar(&opts.recover, "recover", false, "Enable recovery.")
return cmd
}
func printList(out io.Writer, secrets []secrets.Secret) {
printSection(out, func(w io.Writer) {
for _, secret := range secrets {
fmt.Fprintf(w, "%s\t%s\t%s\n", secret.ID, secret.Name, secret.Description) // nolint:errcheck
}
}, "ID", "NAME", "DESCRIPTION")
}
func printSection(out io.Writer, printer func(io.Writer), headers ...string) {
w := tabwriter.NewWriter(out, 20, 1, 3, ' ', 0)
fmt.Fprintln(w, strings.Join(headers, "\t")) // nolint:errcheck
printer(w)
w.Flush() // nolint:errcheck
}

39
cli/cmd/secrets_test.go Normal file
View File

@ -0,0 +1,39 @@
/*
Copyright 2020 Docker, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd
import (
"bytes"
"testing"
"gotest.tools/v3/golden"
"github.com/docker/api/secrets"
)
func TestPrintList(t *testing.T) {
secrets := []secrets.Secret{
{
ID: "123",
Name: "secret123",
Description: "secret 1,2,3",
},
}
out := &bytes.Buffer{}
printList(out, secrets)
golden.Assert(t, out.String(), "secrets-out.golden")
}

2
cli/cmd/testdata/secrets-out.golden vendored Normal file
View File

@ -0,0 +1,2 @@
ID NAME DESCRIPTION
123 secret123 secret 1,2,3

View File

@ -64,6 +64,7 @@ var (
"context": {}, "context": {},
"login": {}, "login": {},
"logout": {}, "logout": {},
"secret": {},
"serve": {}, "serve": {},
"version": {}, "version": {},
} }
@ -126,6 +127,7 @@ func main() {
logout.Command(), logout.Command(),
cmd.VersionCommand(version), cmd.VersionCommand(version),
cmd.StopCommand(), cmd.StopCommand(),
cmd.SecretCommand(),
) )
helpFunc := root.HelpFunc() helpFunc := root.HelpFunc()