github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/api/handlers/libpod/volumes.go (about)

     1  package libpod
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  
     7  	"github.com/containers/podman/v2/libpod"
     8  	"github.com/containers/podman/v2/libpod/define"
     9  	"github.com/containers/podman/v2/pkg/api/handlers/utils"
    10  	"github.com/containers/podman/v2/pkg/domain/entities"
    11  	"github.com/containers/podman/v2/pkg/domain/filters"
    12  	"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
    13  	"github.com/gorilla/schema"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  func CreateVolume(w http.ResponseWriter, r *http.Request) {
    18  	var (
    19  		volumeOptions []libpod.VolumeCreateOption
    20  		runtime       = r.Context().Value("runtime").(*libpod.Runtime)
    21  		decoder       = r.Context().Value("decoder").(*schema.Decoder)
    22  	)
    23  	query := struct {
    24  	}{
    25  		// override any golang type defaults
    26  	}
    27  	input := entities.VolumeCreateOptions{}
    28  	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
    29  		utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
    30  			errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
    31  		return
    32  	}
    33  	// decode params from body
    34  	if err := json.NewDecoder(r.Body).Decode(&input); err != nil {
    35  		utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
    36  		return
    37  	}
    38  
    39  	if len(input.Name) > 0 {
    40  		volumeOptions = append(volumeOptions, libpod.WithVolumeName(input.Name))
    41  	}
    42  	if len(input.Driver) > 0 {
    43  		volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(input.Driver))
    44  	}
    45  	if len(input.Label) > 0 {
    46  		volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(input.Label))
    47  	}
    48  	if len(input.Options) > 0 {
    49  		parsedOptions, err := parse.VolumeOptions(input.Options)
    50  		if err != nil {
    51  			utils.InternalServerError(w, err)
    52  			return
    53  		}
    54  		volumeOptions = append(volumeOptions, parsedOptions...)
    55  	}
    56  	vol, err := runtime.NewVolume(r.Context(), volumeOptions...)
    57  	if err != nil {
    58  		utils.InternalServerError(w, err)
    59  		return
    60  	}
    61  	config, err := vol.Config()
    62  	if err != nil {
    63  		utils.InternalServerError(w, err)
    64  		return
    65  	}
    66  	volResponse := entities.VolumeConfigResponse{
    67  		Name:       config.Name,
    68  		Driver:     config.Driver,
    69  		Mountpoint: config.MountPoint,
    70  		CreatedAt:  config.CreatedTime,
    71  		Labels:     config.Labels,
    72  		Options:    config.Options,
    73  		UID:        config.UID,
    74  		GID:        config.GID,
    75  	}
    76  	utils.WriteResponse(w, http.StatusCreated, volResponse)
    77  }
    78  
    79  func InspectVolume(w http.ResponseWriter, r *http.Request) {
    80  	var (
    81  		runtime = r.Context().Value("runtime").(*libpod.Runtime)
    82  	)
    83  	name := utils.GetName(r)
    84  	vol, err := runtime.GetVolume(name)
    85  	if err != nil {
    86  		utils.VolumeNotFound(w, name, err)
    87  		return
    88  	}
    89  	var uid, gid int
    90  	uid, err = vol.UID()
    91  	if err != nil {
    92  		utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
    93  		return
    94  	}
    95  	gid, err = vol.GID()
    96  	if err != nil {
    97  		utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
    98  		return
    99  	}
   100  	volResponse := entities.VolumeConfigResponse{
   101  		Name:       vol.Name(),
   102  		Driver:     vol.Driver(),
   103  		Mountpoint: vol.MountPoint(),
   104  		CreatedAt:  vol.CreatedTime(),
   105  		Labels:     vol.Labels(),
   106  		Scope:      vol.Scope(),
   107  		Options:    vol.Options(),
   108  		UID:        uid,
   109  		GID:        gid,
   110  	}
   111  	utils.WriteResponse(w, http.StatusOK, volResponse)
   112  }
   113  
   114  func ListVolumes(w http.ResponseWriter, r *http.Request) {
   115  	var (
   116  		decoder = r.Context().Value("decoder").(*schema.Decoder)
   117  		runtime = r.Context().Value("runtime").(*libpod.Runtime)
   118  	)
   119  	query := struct {
   120  		Filters map[string][]string `schema:"filters"`
   121  	}{
   122  		// override any golang type defaults
   123  	}
   124  
   125  	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
   126  		utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
   127  			errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
   128  		return
   129  	}
   130  
   131  	volumeFilters, err := filters.GenerateVolumeFilters(query.Filters)
   132  	if err != nil {
   133  		utils.InternalServerError(w, err)
   134  		return
   135  	}
   136  
   137  	vols, err := runtime.Volumes(volumeFilters...)
   138  	if err != nil {
   139  		utils.InternalServerError(w, err)
   140  		return
   141  	}
   142  	volumeConfigs := make([]*entities.VolumeListReport, 0, len(vols))
   143  	for _, v := range vols {
   144  		var uid, gid int
   145  		uid, err = v.UID()
   146  		if err != nil {
   147  			utils.Error(w, "Error fetching volume UID", http.StatusInternalServerError, err)
   148  			return
   149  		}
   150  		gid, err = v.GID()
   151  		if err != nil {
   152  			utils.Error(w, "Error fetching volume GID", http.StatusInternalServerError, err)
   153  			return
   154  		}
   155  		config := entities.VolumeConfigResponse{
   156  			Name:       v.Name(),
   157  			Driver:     v.Driver(),
   158  			Mountpoint: v.MountPoint(),
   159  			CreatedAt:  v.CreatedTime(),
   160  			Labels:     v.Labels(),
   161  			Scope:      v.Scope(),
   162  			Options:    v.Options(),
   163  			UID:        uid,
   164  			GID:        gid,
   165  		}
   166  		volumeConfigs = append(volumeConfigs, &entities.VolumeListReport{VolumeConfigResponse: config})
   167  	}
   168  	utils.WriteResponse(w, http.StatusOK, volumeConfigs)
   169  }
   170  
   171  func PruneVolumes(w http.ResponseWriter, r *http.Request) {
   172  	reports, err := pruneVolumesHelper(r)
   173  	if err != nil {
   174  		utils.InternalServerError(w, err)
   175  		return
   176  	}
   177  	utils.WriteResponse(w, http.StatusOK, reports)
   178  }
   179  
   180  func pruneVolumesHelper(r *http.Request) ([]*entities.VolumePruneReport, error) {
   181  	var (
   182  		runtime = r.Context().Value("runtime").(*libpod.Runtime)
   183  	)
   184  	pruned, err := runtime.PruneVolumes(r.Context())
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	reports := make([]*entities.VolumePruneReport, 0, len(pruned))
   189  	for k, v := range pruned {
   190  		reports = append(reports, &entities.VolumePruneReport{
   191  			Err: v,
   192  			Id:  k,
   193  		})
   194  	}
   195  	return reports, nil
   196  }
   197  func RemoveVolume(w http.ResponseWriter, r *http.Request) {
   198  	var (
   199  		runtime = r.Context().Value("runtime").(*libpod.Runtime)
   200  		decoder = r.Context().Value("decoder").(*schema.Decoder)
   201  	)
   202  	query := struct {
   203  		Force bool `schema:"force"`
   204  	}{
   205  		// override any golang type defaults
   206  	}
   207  
   208  	if err := decoder.Decode(&query, r.URL.Query()); err != nil {
   209  		utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
   210  			errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
   211  		return
   212  	}
   213  	name := utils.GetName(r)
   214  	vol, err := runtime.LookupVolume(name)
   215  	if err != nil {
   216  		utils.VolumeNotFound(w, name, err)
   217  		return
   218  	}
   219  	if err := runtime.RemoveVolume(r.Context(), vol, query.Force); err != nil {
   220  		if errors.Cause(err) == define.ErrVolumeBeingUsed {
   221  			utils.Error(w, "volumes being used", http.StatusConflict, err)
   222  			return
   223  		}
   224  		utils.InternalServerError(w, err)
   225  		return
   226  	}
   227  	utils.WriteResponse(w, http.StatusNoContent, "")
   228  }