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

Implement Secrets #9125

Merged
merged 1 commit into from
Feb 9, 2021
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
37 changes: 37 additions & 0 deletions cmd/podman/common/completion.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,28 @@ func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellComp
return suggestions, cobra.ShellCompDirectiveNoFileComp
}

func getSecrets(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) {
suggestions := []string{}

engine, err := setupContainerEngine(cmd)
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}
secrets, err := engine.SecretList(registry.GetContext())
if err != nil {
cobra.CompErrorln(err.Error())
return nil, cobra.ShellCompDirectiveNoFileComp
}

for _, s := range secrets {
if strings.HasPrefix(s.Spec.Name, toComplete) {
suggestions = append(suggestions, s.Spec.Name)
}
}
return suggestions, cobra.ShellCompDirectiveNoFileComp
}

func getRegistries() ([]string, cobra.ShellCompDirective) {
regs, err := registries.GetRegistries()
if err != nil {
Expand Down Expand Up @@ -412,6 +434,21 @@ func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) (
return getVolumes(cmd, toComplete)
}

// AutocompleteSecrets - Autocomplete secrets.
func AutocompleteSecrets(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if !validCurrentCmdLine(cmd, args, toComplete) {
return nil, cobra.ShellCompDirectiveNoFileComp
}
return getSecrets(cmd, toComplete)
}

func AutocompleteSecretCreate(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 1 {
return nil, cobra.ShellCompDirectiveDefault
}
return nil, cobra.ShellCompDirectiveNoFileComp
}

// AutocompleteImages - Autocomplete images.
func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if !validCurrentCmdLine(cmd, args, toComplete) {
Expand Down
8 changes: 8 additions & 0 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,14 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) {
)
_ = cmd.RegisterFlagCompletionFunc(sdnotifyFlagName, AutocompleteSDNotify)

secretFlagName := "secret"
createFlags.StringArrayVar(
&cf.Secrets,
secretFlagName, []string{},
"Add secret to container",
)
_ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)

securityOptFlagName := "security-opt"
createFlags.StringArrayVar(
&cf.SecurityOpt,
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/common/create_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ type ContainerCLIOpts struct {
Replace bool
Rm bool
RootFS bool
Secrets []string
SecurityOpt []string
SdNotifyMode string
ShmSize string
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/common/specgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
s.StopTimeout = &c.StopTimeout
s.Timezone = c.Timezone
s.Umask = c.Umask
s.Secrets = c.Secrets

return nil
}
Expand Down
1 change: 1 addition & 0 deletions cmd/podman/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
_ "github.com/containers/podman/v2/cmd/podman/play"
_ "github.com/containers/podman/v2/cmd/podman/pods"
"github.com/containers/podman/v2/cmd/podman/registry"
_ "github.com/containers/podman/v2/cmd/podman/secrets"
_ "github.com/containers/podman/v2/cmd/podman/system"
_ "github.com/containers/podman/v2/cmd/podman/system/connection"
_ "github.com/containers/podman/v2/cmd/podman/volumes"
Expand Down
80 changes: 80 additions & 0 deletions cmd/podman/secrets/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package secrets

import (
"context"
"errors"
"fmt"
"io"
"os"

"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/spf13/cobra"
)

var (
createCmd = &cobra.Command{
Use: "create [options] SECRET FILE|-",
Short: "Create a new secret",
Long: "Create a secret. Input can be a path to a file or \"-\" (read from stdin). Default driver is file (unencrypted).",
RunE: create,
Args: cobra.ExactArgs(2),
ashley-cui marked this conversation as resolved.
Show resolved Hide resolved
Example: `podman secret create mysecret /path/to/secret
printf "secretdata" | podman secret create mysecret -`,
ashley-cui marked this conversation as resolved.
Show resolved Hide resolved
ValidArgsFunction: common.AutocompleteSecretCreate,
}
)

var (
createOpts = entities.SecretCreateOptions{}
)

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: createCmd,
Parent: secretCmd,
})

flags := createCmd.Flags()

driverFlagName := "driver"
flags.StringVar(&createOpts.Driver, driverFlagName, "file", "Specify secret driver")
_ = createCmd.RegisterFlagCompletionFunc(driverFlagName, completion.AutocompleteNone)
}

func create(cmd *cobra.Command, args []string) error {
name := args[0]

var err error
path := args[1]

var reader io.Reader
if path == "-" || path == "/dev/stdin" {
stat, err := os.Stdin.Stat()
if err != nil {
return err
}
if (stat.Mode() & os.ModeNamedPipe) == 0 {
return errors.New("if `-` is used, data must be passed into stdin")

}
reader = os.Stdin
} else {
file, err := os.Open(path)
if err != nil {
return err
}
ashley-cui marked this conversation as resolved.
Show resolved Hide resolved
defer file.Close()
reader = file
}

report, err := registry.ContainerEngine().SecretCreate(context.Background(), name, reader, createOpts)
if err != nil {
return err
}
fmt.Println(report.ID)
return nil
}
82 changes: 82 additions & 0 deletions cmd/podman/secrets/inspect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package secrets

import (
"context"
"encoding/json"
"fmt"
"html/template"
"os"
"text/tabwriter"

"github.com/containers/common/pkg/report"
"github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

var (
inspectCmd = &cobra.Command{
Use: "inspect [options] SECRET [SECRET...]",
Short: "Inspect a secret",
Long: "Display detail information on one or more secrets",
RunE: inspect,
Example: "podman secret inspect MYSECRET",
Args: cobra.MinimumNArgs(1),
ValidArgsFunction: common.AutocompleteSecrets,
}
)

var format string

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: inspectCmd,
Parent: secretCmd,
})
flags := inspectCmd.Flags()
formatFlagName := "format"
flags.StringVar(&format, formatFlagName, "", "Format volume output using Go template")
_ = inspectCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
}

func inspect(cmd *cobra.Command, args []string) error {
inspected, errs, _ := registry.ContainerEngine().SecretInspect(context.Background(), args)

// always print valid list
if len(inspected) == 0 {
inspected = []*entities.SecretInfoReport{}
}

if cmd.Flags().Changed("format") {
row := report.NormalizeFormat(format)
formatted := parse.EnforceRange(row)

tmpl, err := template.New("inspect secret").Parse(formatted)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 12, 2, 2, ' ', 0)
defer w.Flush()
tmpl.Execute(w, inspected)
} else {
buf, err := json.MarshalIndent(inspected, "", " ")
if err != nil {
return err
}
fmt.Println(string(buf))
}

if len(errs) > 0 {
if len(errs) > 1 {
for _, err := range errs[1:] {
fmt.Fprintf(os.Stderr, "error inspecting secret: %v\n", err)
}
}
return errors.Errorf("error inspecting secret: %v", errs[0])
}
return nil
}
99 changes: 99 additions & 0 deletions cmd/podman/secrets/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package secrets

import (
"context"
"html/template"
"os"
"text/tabwriter"
"time"

"github.com/containers/common/pkg/completion"
"github.com/containers/common/pkg/report"
"github.com/containers/podman/v2/cmd/podman/common"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)

var (
lsCmd = &cobra.Command{
Use: "ls [options]",
Aliases: []string{"list"},
Short: "List secrets",
RunE: ls,
Example: "podman secret ls",
Args: validate.NoArgs,
ValidArgsFunction: completion.AutocompleteNone,
}
listFlag = listFlagType{}
)

type listFlagType struct {
format string
noHeading bool
}

func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: lsCmd,
Parent: secretCmd,
})

flags := lsCmd.Flags()
formatFlagName := "format"
flags.StringVar(&listFlag.format, formatFlagName, "{{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.CreatedAt}}\t{{.UpdatedAt}}\t\n", "Format volume output using Go template")
_ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)

}

func ls(cmd *cobra.Command, args []string) error {
responses, err := registry.ContainerEngine().SecretList(context.Background())
if err != nil {
return err
}
listed := make([]*entities.SecretListReport, 0, len(responses))
for _, response := range responses {
listed = append(listed, &entities.SecretListReport{
ID: response.ID,
Name: response.Spec.Name,
CreatedAt: units.HumanDuration(time.Since(response.CreatedAt)) + " ago",
UpdatedAt: units.HumanDuration(time.Since(response.UpdatedAt)) + " ago",
Driver: response.Spec.Driver.Name,
})

}
return outputTemplate(cmd, listed)
}
ashley-cui marked this conversation as resolved.
Show resolved Hide resolved

func outputTemplate(cmd *cobra.Command, responses []*entities.SecretListReport) error {
headers := report.Headers(entities.SecretListReport{}, map[string]string{
"CreatedAt": "CREATED",
"UpdatedAt": "UPDATED",
})

row := report.NormalizeFormat(listFlag.format)
format := parse.EnforceRange(row)

tmpl, err := template.New("list secret").Parse(format)
if err != nil {
return err
}
w := tabwriter.NewWriter(os.Stdout, 12, 2, 2, ' ', 0)
defer w.Flush()

if cmd.Flags().Changed("format") && !parse.HasTable(listFlag.format) {
listFlag.noHeading = true
}

if !listFlag.noHeading {
if err := tmpl.Execute(w, headers); err != nil {
return errors.Wrapf(err, "failed to write report column headers")
}
}
return tmpl.Execute(w, responses)
}
Loading