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