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  }