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 }