github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/api/handlers/libpod/pods.go (about) 1 package libpod 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strings" 8 9 "github.com/containers/libpod/libpod" 10 "github.com/containers/libpod/libpod/define" 11 "github.com/containers/libpod/pkg/api/handlers" 12 "github.com/containers/libpod/pkg/api/handlers/utils" 13 "github.com/containers/libpod/pkg/domain/entities" 14 "github.com/containers/libpod/pkg/specgen" 15 "github.com/containers/libpod/pkg/specgen/generate" 16 "github.com/containers/libpod/pkg/util" 17 "github.com/gorilla/schema" 18 "github.com/pkg/errors" 19 ) 20 21 func PodCreate(w http.ResponseWriter, r *http.Request) { 22 var ( 23 runtime = r.Context().Value("runtime").(*libpod.Runtime) 24 err error 25 ) 26 var psg specgen.PodSpecGenerator 27 if err := json.NewDecoder(r.Body).Decode(&psg); err != nil { 28 utils.Error(w, "Failed to decode specgen", http.StatusInternalServerError, errors.Wrap(err, "failed to decode specgen")) 29 return 30 } 31 pod, err := generate.MakePod(&psg, runtime) 32 if err != nil { 33 http_code := http.StatusInternalServerError 34 if errors.Cause(err) == define.ErrPodExists { 35 http_code = http.StatusConflict 36 } 37 utils.Error(w, "Something went wrong.", http_code, err) 38 return 39 } 40 utils.WriteResponse(w, http.StatusCreated, handlers.IDResponse{ID: pod.ID()}) 41 } 42 43 func Pods(w http.ResponseWriter, r *http.Request) { 44 decoder := r.Context().Value("decoder").(*schema.Decoder) 45 query := struct { 46 Filters map[string][]string `schema:"filters"` 47 }{ 48 // override any golang type defaults 49 } 50 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 51 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 52 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 53 return 54 } 55 56 pods, err := utils.GetPods(w, r) 57 if err != nil { 58 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 59 return 60 } 61 utils.WriteResponse(w, http.StatusOK, pods) 62 } 63 64 func PodInspect(w http.ResponseWriter, r *http.Request) { 65 runtime := r.Context().Value("runtime").(*libpod.Runtime) 66 name := utils.GetName(r) 67 pod, err := runtime.LookupPod(name) 68 if err != nil { 69 utils.PodNotFound(w, name, err) 70 return 71 } 72 podData, err := pod.Inspect() 73 if err != nil { 74 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 75 return 76 } 77 report := entities.PodInspectReport{ 78 PodInspect: podData, 79 } 80 utils.WriteResponse(w, http.StatusOK, report) 81 } 82 83 func PodStop(w http.ResponseWriter, r *http.Request) { 84 var ( 85 stopError error 86 runtime = r.Context().Value("runtime").(*libpod.Runtime) 87 decoder = r.Context().Value("decoder").(*schema.Decoder) 88 responses map[string]error 89 errs []error 90 ) 91 query := struct { 92 Timeout int `schema:"t"` 93 }{ 94 // override any golang type defaults 95 } 96 97 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 98 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 99 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 100 return 101 } 102 name := utils.GetName(r) 103 pod, err := runtime.LookupPod(name) 104 if err != nil { 105 utils.PodNotFound(w, name, err) 106 return 107 } 108 109 status, err := pod.GetPodStatus() 110 if err != nil { 111 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 112 return 113 } 114 if status != define.PodStateRunning { 115 utils.WriteResponse(w, http.StatusNotModified, "") 116 return 117 } 118 119 if query.Timeout > 0 { 120 responses, stopError = pod.StopWithTimeout(r.Context(), false, query.Timeout) 121 } else { 122 responses, stopError = pod.Stop(r.Context(), false) 123 } 124 if stopError != nil { 125 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 126 return 127 } 128 for _, err := range responses { 129 errs = append(errs, err) 130 } 131 report := entities.PodStopReport{ 132 Errs: errs, 133 Id: pod.ID(), 134 } 135 utils.WriteResponse(w, http.StatusOK, report) 136 } 137 138 func PodStart(w http.ResponseWriter, r *http.Request) { 139 var ( 140 errs []error 141 ) 142 runtime := r.Context().Value("runtime").(*libpod.Runtime) 143 name := utils.GetName(r) 144 pod, err := runtime.LookupPod(name) 145 if err != nil { 146 utils.PodNotFound(w, name, err) 147 return 148 } 149 status, err := pod.GetPodStatus() 150 if err != nil { 151 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 152 return 153 } 154 if status == define.PodStateRunning { 155 utils.WriteResponse(w, http.StatusNotModified, "") 156 return 157 } 158 responses, err := pod.Start(r.Context()) 159 if err != nil { 160 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 161 return 162 } 163 for _, err := range responses { 164 errs = append(errs, err) 165 } 166 report := entities.PodStartReport{ 167 Errs: errs, 168 Id: pod.ID(), 169 } 170 utils.WriteResponse(w, http.StatusOK, report) 171 } 172 173 func PodDelete(w http.ResponseWriter, r *http.Request) { 174 var ( 175 runtime = r.Context().Value("runtime").(*libpod.Runtime) 176 decoder = r.Context().Value("decoder").(*schema.Decoder) 177 ) 178 query := struct { 179 Force bool `schema:"force"` 180 }{ 181 // override any golang type defaults 182 } 183 184 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 185 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 186 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 187 return 188 } 189 name := utils.GetName(r) 190 pod, err := runtime.LookupPod(name) 191 if err != nil { 192 utils.PodNotFound(w, name, err) 193 return 194 } 195 if err := runtime.RemovePod(r.Context(), pod, true, query.Force); err != nil { 196 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 197 return 198 } 199 report := entities.PodRmReport{ 200 Id: pod.ID(), 201 } 202 utils.WriteResponse(w, http.StatusOK, report) 203 } 204 205 func PodRestart(w http.ResponseWriter, r *http.Request) { 206 var ( 207 errs []error 208 ) 209 runtime := r.Context().Value("runtime").(*libpod.Runtime) 210 name := utils.GetName(r) 211 pod, err := runtime.LookupPod(name) 212 if err != nil { 213 utils.PodNotFound(w, name, err) 214 return 215 } 216 responses, err := pod.Restart(r.Context()) 217 if err != nil { 218 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 219 return 220 } 221 for _, err := range responses { 222 errs = append(errs, err) 223 } 224 report := entities.PodRestartReport{ 225 Errs: errs, 226 Id: pod.ID(), 227 } 228 utils.WriteResponse(w, http.StatusOK, report) 229 } 230 231 func PodPrune(w http.ResponseWriter, r *http.Request) { 232 var ( 233 runtime = r.Context().Value("runtime").(*libpod.Runtime) 234 ) 235 pruned, err := runtime.PrunePods() 236 if err != nil { 237 utils.InternalServerError(w, err) 238 return 239 } 240 utils.WriteResponse(w, http.StatusOK, pruned) 241 } 242 243 func PodPause(w http.ResponseWriter, r *http.Request) { 244 var ( 245 errs []error 246 ) 247 runtime := r.Context().Value("runtime").(*libpod.Runtime) 248 name := utils.GetName(r) 249 pod, err := runtime.LookupPod(name) 250 if err != nil { 251 utils.PodNotFound(w, name, err) 252 return 253 } 254 responses, err := pod.Pause() 255 if err != nil { 256 utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) 257 return 258 } 259 for _, v := range responses { 260 errs = append(errs, v) 261 } 262 report := entities.PodPauseReport{ 263 Errs: errs, 264 Id: pod.ID(), 265 } 266 utils.WriteResponse(w, http.StatusOK, report) 267 } 268 269 func PodUnpause(w http.ResponseWriter, r *http.Request) { 270 var ( 271 errs []error 272 ) 273 runtime := r.Context().Value("runtime").(*libpod.Runtime) 274 name := utils.GetName(r) 275 pod, err := runtime.LookupPod(name) 276 if err != nil { 277 utils.PodNotFound(w, name, err) 278 return 279 } 280 responses, err := pod.Unpause() 281 if err != nil { 282 utils.Error(w, "failed to pause pod", http.StatusInternalServerError, err) 283 return 284 } 285 for _, v := range responses { 286 errs = append(errs, v) 287 } 288 report := entities.PodUnpauseReport{ 289 Errs: errs, 290 Id: pod.ID(), 291 } 292 utils.WriteResponse(w, http.StatusOK, &report) 293 } 294 295 func PodTop(w http.ResponseWriter, r *http.Request) { 296 runtime := r.Context().Value("runtime").(*libpod.Runtime) 297 decoder := r.Context().Value("decoder").(*schema.Decoder) 298 299 query := struct { 300 PsArgs string `schema:"ps_args"` 301 }{ 302 PsArgs: "", 303 } 304 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 305 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 306 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 307 return 308 } 309 310 name := utils.GetName(r) 311 pod, err := runtime.LookupPod(name) 312 if err != nil { 313 utils.ContainerNotFound(w, name, err) 314 return 315 } 316 317 args := []string{} 318 if query.PsArgs != "" { 319 args = append(args, query.PsArgs) 320 } 321 output, err := pod.GetPodPidInformation(args) 322 if err != nil { 323 utils.InternalServerError(w, err) 324 return 325 } 326 327 var body = handlers.PodTopOKBody{} 328 if len(output) > 0 { 329 body.Titles = strings.Split(output[0], "\t") 330 for _, line := range output[1:] { 331 body.Processes = append(body.Processes, strings.Split(line, "\t")) 332 } 333 } 334 utils.WriteJSON(w, http.StatusOK, body) 335 } 336 337 func PodKill(w http.ResponseWriter, r *http.Request) { 338 var ( 339 runtime = r.Context().Value("runtime").(*libpod.Runtime) 340 decoder = r.Context().Value("decoder").(*schema.Decoder) 341 signal = "SIGKILL" 342 errs []error 343 ) 344 query := struct { 345 Signal string `schema:"signal"` 346 }{ 347 // override any golang type defaults 348 } 349 if err := decoder.Decode(&query, r.URL.Query()); err != nil { 350 utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, 351 errors.Wrapf(err, "Failed to parse parameters for %s", r.URL.String())) 352 return 353 } 354 if _, found := r.URL.Query()["signal"]; found { 355 signal = query.Signal 356 } 357 358 sig, err := util.ParseSignal(signal) 359 if err != nil { 360 utils.InternalServerError(w, errors.Wrapf(err, "unable to parse signal value")) 361 } 362 name := utils.GetName(r) 363 pod, err := runtime.LookupPod(name) 364 if err != nil { 365 utils.PodNotFound(w, name, err) 366 return 367 } 368 podStates, err := pod.Status() 369 if err != nil { 370 utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err) 371 return 372 } 373 hasRunning := false 374 for _, s := range podStates { 375 if s == define.ContainerStateRunning { 376 hasRunning = true 377 break 378 } 379 } 380 if !hasRunning { 381 msg := fmt.Sprintf("Container %s is not running", pod.ID()) 382 utils.Error(w, msg, http.StatusConflict, errors.Errorf("cannot kill a pod with no running containers: %s", pod.ID())) 383 return 384 } 385 386 responses, err := pod.Kill(uint(sig)) 387 if err != nil { 388 utils.Error(w, "failed to kill pod", http.StatusInternalServerError, err) 389 return 390 } 391 392 for _, v := range responses { 393 if v != nil { 394 errs = append(errs, v) 395 } 396 } 397 report := &entities.PodKillReport{ 398 Errs: errs, 399 Id: pod.ID(), 400 } 401 utils.WriteResponse(w, http.StatusOK, report) 402 } 403 404 func PodExists(w http.ResponseWriter, r *http.Request) { 405 runtime := r.Context().Value("runtime").(*libpod.Runtime) 406 name := utils.GetName(r) 407 _, err := runtime.LookupPod(name) 408 if err != nil { 409 utils.PodNotFound(w, name, err) 410 return 411 } 412 utils.WriteResponse(w, http.StatusNoContent, "") 413 }