spiegel_podman/vendor/github.com/fsouza/go-dockerclient/volume.go
Matthew Heon 5e94c95ad0 Move to deterministic network setup order
This was implemented by containers/netavark #1369; this commit
completes the process by wiring it into Podman. We now respect
the CLI order for configured networks - if a user passes
`--net net1,net2` we guarantee that net1 will be configured
before net2.

For containers created before this patch, we don't retain enough
information to configure networks in CLI order, so we use
alphabetical order instead to still guarantee consistency.

No breaking API changes have been made, but we do add a new
field to supplement the existing map to (optionally) provide
ordering information. The Podman CLI will always pass this.
Existing applications that do not will, again, receive]
deterministic ordering based on an alphabetical sort of network
names.

This requires the latest version of Netavark to work properly.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
2026-04-17 10:00:32 -04:00

194 lines
5.4 KiB
Go

// Copyright 2015 go-dockerclient authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package docker
import (
"context"
"encoding/json"
"errors"
"net/http"
"time"
)
var (
// ErrNoSuchVolume is the error returned when the volume does not exist.
ErrNoSuchVolume = errors.New("no such volume")
// ErrVolumeInUse is the error returned when the volume requested to be removed is still in use.
ErrVolumeInUse = errors.New("volume in use and cannot be removed")
)
// Volume represents a volume.
//
// See https://goo.gl/3wgTsd for more details.
type Volume struct {
Name string `json:"Name" yaml:"Name" toml:"Name"`
Driver string `json:"Driver,omitempty" yaml:"Driver,omitempty" toml:"Driver,omitempty"`
Mountpoint string `json:"Mountpoint,omitempty" yaml:"Mountpoint,omitempty" toml:"Mountpoint,omitempty"`
Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty" toml:"Labels,omitempty"`
Options map[string]string `json:"Options,omitempty" yaml:"Options,omitempty" toml:"Options,omitempty"`
CreatedAt time.Time `json:"CreatedAt" yaml:"CreatedAt,omitempty" toml:"CreatedAt,omitempty"`
}
// ListVolumesOptions specify parameters to the ListVolumes function.
//
// See https://goo.gl/3wgTsd for more details.
type ListVolumesOptions struct {
Filters map[string][]string
Context context.Context
}
// ListVolumes returns a list of available volumes in the server.
//
// See https://goo.gl/3wgTsd for more details.
func (c *Client) ListVolumes(opts ListVolumesOptions) ([]Volume, error) {
resp, err := c.do(http.MethodGet, "/volumes?"+queryString(opts), doOptions{
context: opts.Context,
})
if err != nil {
return nil, err
}
defer resp.Body.Close()
m := make(map[string]any)
if err = json.NewDecoder(resp.Body).Decode(&m); err != nil {
return nil, err
}
var volumes []Volume
volumesJSON, ok := m["Volumes"]
if !ok {
return volumes, nil
}
data, err := json.Marshal(volumesJSON)
if err != nil {
return nil, err
}
if err := json.Unmarshal(data, &volumes); err != nil {
return nil, err
}
return volumes, nil
}
// CreateVolumeOptions specify parameters to the CreateVolume function.
//
// See https://goo.gl/qEhmEC for more details.
type CreateVolumeOptions struct {
Name string
Driver string
DriverOpts map[string]string
Context context.Context `json:"-"`
Labels map[string]string
}
// CreateVolume creates a volume on the server.
//
// See https://goo.gl/qEhmEC for more details.
func (c *Client) CreateVolume(opts CreateVolumeOptions) (*Volume, error) {
resp, err := c.do(http.MethodPost, "/volumes/create", doOptions{
data: opts,
context: opts.Context,
})
if err != nil {
return nil, err
}
defer resp.Body.Close()
var volume Volume
if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil {
return nil, err
}
return &volume, nil
}
// InspectVolume returns a volume by its name.
//
// See https://goo.gl/GMjsMc for more details.
func (c *Client) InspectVolume(name string) (*Volume, error) {
resp, err := c.do(http.MethodGet, "/volumes/"+name, doOptions{})
if err != nil {
var e *Error
if errors.As(err, &e) && e.Status == http.StatusNotFound {
return nil, ErrNoSuchVolume
}
return nil, err
}
defer resp.Body.Close()
var volume Volume
if err := json.NewDecoder(resp.Body).Decode(&volume); err != nil {
return nil, err
}
return &volume, nil
}
// RemoveVolume removes a volume by its name.
//
// Deprecated: Use RemoveVolumeWithOptions instead.
func (c *Client) RemoveVolume(name string) error {
return c.RemoveVolumeWithOptions(RemoveVolumeOptions{Name: name})
}
// RemoveVolumeOptions specify parameters to the RemoveVolumeWithOptions
// function.
//
// See https://goo.gl/nvd6qj for more details.
type RemoveVolumeOptions struct {
Context context.Context
Name string `qs:"-"`
Force bool
}
// RemoveVolumeWithOptions removes a volume by its name and takes extra
// parameters.
//
// See https://goo.gl/nvd6qj for more details.
func (c *Client) RemoveVolumeWithOptions(opts RemoveVolumeOptions) error {
path := "/volumes/" + opts.Name
resp, err := c.do(http.MethodDelete, path+"?"+queryString(opts), doOptions{context: opts.Context})
if err != nil {
var e *Error
if errors.As(err, &e) {
if e.Status == http.StatusNotFound {
return ErrNoSuchVolume
}
if e.Status == http.StatusConflict {
return ErrVolumeInUse
}
}
return err
}
defer resp.Body.Close()
return nil
}
// PruneVolumesOptions specify parameters to the PruneVolumes function.
//
// See https://goo.gl/f9XDem for more details.
type PruneVolumesOptions struct {
Filters map[string][]string
Context context.Context
}
// PruneVolumesResults specify results from the PruneVolumes function.
//
// See https://goo.gl/f9XDem for more details.
type PruneVolumesResults struct {
VolumesDeleted []string
SpaceReclaimed int64
}
// PruneVolumes deletes volumes which are unused.
//
// See https://goo.gl/f9XDem for more details.
func (c *Client) PruneVolumes(opts PruneVolumesOptions) (*PruneVolumesResults, error) {
path := "/volumes/prune?" + queryString(opts)
resp, err := c.do(http.MethodPost, path, doOptions{context: opts.Context})
if err != nil {
return nil, err
}
defer resp.Body.Close()
var results PruneVolumesResults
if err := json.NewDecoder(resp.Body).Decode(&results); err != nil {
return nil, err
}
return &results, nil
}