Skip to content

Commit

Permalink
Add podman volume create --ignore
Browse files Browse the repository at this point in the history
This ignores the create request if the named volume already exists.
It is very useful when scripting stuff.

Signed-off-by: Alexander Larsson <[email protected]>
  • Loading branch information
alexlarsson committed Oct 24, 2022
1 parent a77ac5b commit 734c435
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 12 deletions.
11 changes: 9 additions & 2 deletions cmd/podman/volumes/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ var (
var (
createOpts = entities.VolumeCreateOptions{}
opts = struct {
Label []string
Opts []string
Label []string
Opts []string
Ignore bool
}{}
)

Expand All @@ -53,6 +54,9 @@ func init() {
optFlagName := "opt"
flags.StringArrayVarP(&opts.Opts, optFlagName, "o", []string{}, "Set driver specific options (default [])")
_ = createCommand.RegisterFlagCompletionFunc(optFlagName, completion.AutocompleteNone)

ignoreFlagName := "ignore"
flags.BoolVar(&opts.Ignore, ignoreFlagName, false, "Don't fail if volume already exists")
}

func create(cmd *cobra.Command, args []string) error {
Expand All @@ -62,6 +66,9 @@ func create(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
createOpts.Name = args[0]
}

createOpts.IgnoreIfExists = opts.Ignore

createOpts.Label, err = parse.GetAllLabels([]string{}, opts.Label)
if err != nil {
return fmt.Errorf("unable to process labels: %w", err)
Expand Down
4 changes: 4 additions & 0 deletions docs/source/markdown/podman-volume-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Such plugins must be defined in the **volume_plugins** section of the **[contain

Print usage statement

#### **--ignore**

Don't fail if the named volume already exists, instead just print the name. Note that the new options are not applied to the existing volume.

#### **--label**, **-l**=*label*

Set metadata for a volume (e.g., --label mykey=value).
Expand Down
11 changes: 11 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,17 @@ func WithCreateWorkingDir() CtrCreateOption {

// Volume Creation Options

func WithVolumeIgnoreIfExist() VolumeCreateOption {
return func(volume *Volume) error {
if volume.valid {
return define.ErrVolumeFinalized
}
volume.ignoreIfExists = true

return nil
}
}

// WithVolumeName sets the name of the volume.
func WithVolumeName(name string) VolumeCreateOption {
return func(volume *Volume) error {
Expand Down
21 changes: 15 additions & 6 deletions libpod/runtime_volume_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,14 @@ func (r *Runtime) newVolume(ctx context.Context, noCreatePluginVolume bool, opti
volume.config.CreatedTime = time.Now()

// Check if volume with given name exists.
exists, err := r.state.HasVolume(volume.config.Name)
if err != nil {
return nil, fmt.Errorf("checking if volume with name %s exists: %w", volume.config.Name, err)
}
if exists {
return nil, fmt.Errorf("volume with name %s already exists: %w", volume.config.Name, define.ErrVolumeExists)
if !volume.ignoreIfExists {
exists, err := r.state.HasVolume(volume.config.Name)
if err != nil {
return nil, fmt.Errorf("checking if volume with name %s exists: %w", volume.config.Name, err)
}
if exists {
return nil, fmt.Errorf("volume with name %s already exists: %w", volume.config.Name, define.ErrVolumeExists)
}
}

// Plugin can be nil if driver is local, but that's OK - superfluous
Expand Down Expand Up @@ -209,6 +211,13 @@ func (r *Runtime) newVolume(ctx context.Context, noCreatePluginVolume bool, opti

// Add the volume to state
if err := r.state.AddVolume(volume); err != nil {
if volume.ignoreIfExists && errors.Is(err, define.ErrVolumeExists) {
existingVolume, err := r.state.Volume(volume.config.Name)
if err != nil {
return nil, fmt.Errorf("reading volume from state: %w", err)
}
return existingVolume, nil
}
return nil, fmt.Errorf("adding volume to state: %w", err)
}
defer volume.newVolumeEvent(events.Create)
Expand Down
9 changes: 5 additions & 4 deletions libpod/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ type Volume struct {
config *VolumeConfig
state *VolumeState

valid bool
plugin *plugin.VolumePlugin
runtime *Runtime
lock lock.Locker
ignoreIfExists bool
valid bool
plugin *plugin.VolumePlugin
runtime *Runtime
lock lock.Locker
}

// VolumeConfig holds the volume's immutable configuration.
Expand Down
5 changes: 5 additions & 0 deletions pkg/api/handlers/libpod/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func CreateVolume(w http.ResponseWriter, r *http.Request) {
}
volumeOptions = append(volumeOptions, parsedOptions...)
}

if input.IgnoreIfExists {
volumeOptions = append(volumeOptions, libpod.WithVolumeIgnoreIfExist())
}

vol, err := runtime.NewVolume(r.Context(), volumeOptions...)
if err != nil {
utils.InternalServerError(w, err)
Expand Down
2 changes: 2 additions & 0 deletions pkg/domain/entities/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ type VolumeCreateOptions struct {
Labels map[string]string `schema:"labels"`
// Mapping of driver options and values.
Options map[string]string `schema:"opts"`
// Ignore existing volumes
IgnoreIfExists bool `schema:"ignoreIfExist"`
}

type VolumeConfigResponse struct {
Expand Down
5 changes: 5 additions & 0 deletions pkg/domain/infra/abi/volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.Volum
}
volumeOptions = append(volumeOptions, parsedOptions...)
}

if opts.IgnoreIfExists {
volumeOptions = append(volumeOptions, libpod.WithVolumeIgnoreIfExist())
}

vol, err := ic.Libpod.NewVolume(ctx, volumeOptions...)
if err != nil {
return nil, err
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/volume_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,28 @@ var _ = Describe("Podman volume create", func() {
Expect(check.OutputToStringArray()).To(HaveLen(1))
})

It("podman create volume with existing name fails", func() {
session := podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))

session = podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})

It("podman create volume --ignore", func() {
session := podmanTest.Podman([]string{"volume", "create", "myvol"})
session.WaitWithDefaultTimeout()
volName := session.OutputToString()
Expect(session).Should(Exit(0))

session = podmanTest.Podman([]string{"volume", "create", "--ignore", "myvol"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(Equal(volName))
})

It("podman create and export volume", func() {
if podmanTest.RemoteTest {
Skip("Volume export check does not work with a remote client")
Expand Down

0 comments on commit 734c435

Please sign in to comment.