github.com/containers/podman/v4@v4.9.4/pkg/bindings/test/pods_test.go (about)

     1  package bindings_test
     2  
     3  import (
     4  	"fmt"
     5  	"net/http"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/containers/podman/v4/libpod/define"
    10  	"github.com/containers/podman/v4/pkg/bindings"
    11  	"github.com/containers/podman/v4/pkg/bindings/pods"
    12  	"github.com/containers/podman/v4/pkg/domain/entities"
    13  	"github.com/containers/podman/v4/pkg/errorhandling"
    14  	"github.com/containers/podman/v4/pkg/specgen"
    15  	"github.com/containers/podman/v4/utils"
    16  	. "github.com/onsi/ginkgo/v2"
    17  	. "github.com/onsi/gomega"
    18  	"github.com/onsi/gomega/gexec"
    19  )
    20  
    21  var _ = Describe("Podman pods", func() {
    22  	var (
    23  		bt     *bindingTest
    24  		s      *gexec.Session
    25  		newpod string
    26  		err    error
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		bt = newBindingTest()
    31  		newpod = "newpod"
    32  		bt.RestoreImagesFromCache()
    33  		bt.Podcreate(&newpod)
    34  		s = bt.startAPIService()
    35  		time.Sleep(1 * time.Second)
    36  		err := bt.NewConnection()
    37  		Expect(err).ToNot(HaveOccurred())
    38  	})
    39  
    40  	AfterEach(func() {
    41  		s.Kill()
    42  		bt.cleanup()
    43  	})
    44  
    45  	It("inspect pod", func() {
    46  		// Inspect an invalid pod name
    47  		_, err := pods.Inspect(bt.conn, "dummyname", nil)
    48  		Expect(err).To(HaveOccurred())
    49  		code, _ := bindings.CheckResponseCode(err)
    50  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
    51  
    52  		// Inspect a valid pod name
    53  		response, err := pods.Inspect(bt.conn, newpod, nil)
    54  		Expect(err).ToNot(HaveOccurred())
    55  		Expect(response.Name).To(Equal(newpod))
    56  	})
    57  
    58  	// Test validates the list all api returns
    59  	It("list pod", func() {
    60  		// List all the pods in the current instance
    61  		podSummary, err := pods.List(bt.conn, nil)
    62  		Expect(err).ToNot(HaveOccurred())
    63  		Expect(podSummary).To(HaveLen(1))
    64  
    65  		// Start the pod
    66  		_, err = pods.Start(bt.conn, newpod, nil)
    67  		Expect(err).ToNot(HaveOccurred())
    68  
    69  		// Adding an alpine container to the existing pod
    70  		_, err = bt.RunTopContainer(nil, &newpod)
    71  		Expect(err).ToNot(HaveOccurred())
    72  		podSummary, err = pods.List(bt.conn, nil)
    73  		// Verify no errors.
    74  		Expect(err).ToNot(HaveOccurred())
    75  		// Verify number of containers in the pod.
    76  		Expect(podSummary[0].Containers).To(HaveLen(2))
    77  
    78  		// Add multiple pods and verify them by name and size.
    79  		var newpod2 = "newpod2"
    80  		bt.Podcreate(&newpod2)
    81  		podSummary, err = pods.List(bt.conn, nil)
    82  		Expect(err).ToNot(HaveOccurred(), "Error from pods.List")
    83  		Expect(podSummary).To(HaveLen(2))
    84  		var names []string
    85  		for _, i := range podSummary {
    86  			names = append(names, i.Name)
    87  		}
    88  		Expect(StringInSlice(newpod, names)).To(BeTrue())
    89  		Expect(StringInSlice("newpod2", names)).To(BeTrue())
    90  	})
    91  
    92  	// The test validates the list pod endpoint with passing filters as the params.
    93  	It("List pods with filters", func() {
    94  		newpod2 := "newpod2"
    95  		bt.Podcreate(&newpod2)
    96  
    97  		// Start the pod
    98  		_, err = pods.Start(bt.conn, newpod, nil)
    99  		Expect(err).ToNot(HaveOccurred())
   100  
   101  		_, err = bt.RunTopContainer(nil, &newpod)
   102  		Expect(err).ToNot(HaveOccurred())
   103  
   104  		// Expected err with invalid filter params
   105  		filters := make(map[string][]string)
   106  		filters["dummy"] = []string{"dummy"}
   107  		options := new(pods.ListOptions).WithFilters(filters)
   108  		filteredPods, err := pods.List(bt.conn, options)
   109  		Expect(err).To(HaveOccurred())
   110  		Expect(filteredPods).To(BeEmpty(), "len(filteredPods)")
   111  		code, _ := bindings.CheckResponseCode(err)
   112  		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
   113  
   114  		// Expected empty response with invalid filters
   115  		filters = make(map[string][]string)
   116  		filters["name"] = []string{"dummy"}
   117  		options = new(pods.ListOptions).WithFilters(filters)
   118  		filteredPods, err = pods.List(bt.conn, options)
   119  		Expect(err).ToNot(HaveOccurred())
   120  		Expect(filteredPods).To(BeEmpty())
   121  
   122  		// Validate list pod with name filter
   123  		filters = make(map[string][]string)
   124  		filters["name"] = []string{newpod2}
   125  		options = new(pods.ListOptions).WithFilters(filters)
   126  		filteredPods, err = pods.List(bt.conn, options)
   127  		Expect(err).ToNot(HaveOccurred())
   128  		Expect(filteredPods).To(HaveLen(1))
   129  		var names []string
   130  		for _, i := range filteredPods {
   131  			names = append(names, i.Name)
   132  		}
   133  		Expect(StringInSlice("newpod2", names)).To(BeTrue())
   134  
   135  		// Validate list pod with id filter
   136  		filters = make(map[string][]string)
   137  		response, err := pods.Inspect(bt.conn, newpod, nil)
   138  		Expect(err).ToNot(HaveOccurred())
   139  		id := response.ID
   140  		filters["id"] = []string{id}
   141  		options = new(pods.ListOptions).WithFilters(filters)
   142  		filteredPods, err = pods.List(bt.conn, options)
   143  		Expect(err).ToNot(HaveOccurred())
   144  		Expect(filteredPods).To(HaveLen(1))
   145  		names = names[:0]
   146  		for _, i := range filteredPods {
   147  			names = append(names, i.Name)
   148  		}
   149  		Expect(StringInSlice("newpod", names)).To(BeTrue())
   150  
   151  		// Using multiple filters
   152  		filters["name"] = []string{newpod}
   153  		options = new(pods.ListOptions).WithFilters(filters)
   154  		filteredPods, err = pods.List(bt.conn, options)
   155  		Expect(err).ToNot(HaveOccurred())
   156  		Expect(filteredPods).To(HaveLen(1))
   157  		names = names[:0]
   158  		for _, i := range filteredPods {
   159  			names = append(names, i.Name)
   160  		}
   161  		Expect(StringInSlice("newpod", names)).To(BeTrue())
   162  	})
   163  
   164  	// The test validates if the exists responds
   165  	It("exists pod", func() {
   166  		response, err := pods.Exists(bt.conn, "dummyName", nil)
   167  		Expect(err).ToNot(HaveOccurred())
   168  		Expect(response).To(BeFalse())
   169  
   170  		// Should exit with no error and response should be true
   171  		response, err = pods.Exists(bt.conn, "newpod", nil)
   172  		Expect(err).ToNot(HaveOccurred())
   173  		Expect(response).To(BeTrue())
   174  	})
   175  
   176  	// This test validates if All running containers within
   177  	// each specified pod are paused and unpaused
   178  	It("pause unpause pod", func() {
   179  		// TODO fix this
   180  		Skip("Pod behavior is jacked right now.")
   181  		// Pause invalid container
   182  		_, err := pods.Pause(bt.conn, "dummyName", nil)
   183  		Expect(err).To(HaveOccurred())
   184  		code, _ := bindings.CheckResponseCode(err)
   185  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
   186  
   187  		// Adding an alpine container to the existing pod
   188  		_, err = bt.RunTopContainer(nil, &newpod)
   189  		Expect(err).ToNot(HaveOccurred())
   190  
   191  		// Binding needs to be modified to inspect the pod state.
   192  		// Since we don't have a pod state we inspect the states of the containers within the pod.
   193  		// Pause a valid container
   194  		_, err = pods.Pause(bt.conn, newpod, nil)
   195  		Expect(err).ToNot(HaveOccurred())
   196  		response, err := pods.Inspect(bt.conn, newpod, nil)
   197  		Expect(err).ToNot(HaveOccurred())
   198  		Expect(response.State).To(Equal(define.PodStatePaused))
   199  		for _, i := range response.Containers {
   200  			Expect(define.StringToContainerStatus(i.State)).
   201  				To(Equal(define.ContainerStatePaused))
   202  		}
   203  
   204  		// Unpause a valid container
   205  		_, err = pods.Unpause(bt.conn, newpod, nil)
   206  		Expect(err).ToNot(HaveOccurred())
   207  		response, err = pods.Inspect(bt.conn, newpod, nil)
   208  		Expect(err).ToNot(HaveOccurred())
   209  		Expect(response.State).To(Equal(define.PodStateRunning))
   210  		for _, i := range response.Containers {
   211  			Expect(define.StringToContainerStatus(i.State)).
   212  				To(Equal(define.ContainerStateRunning))
   213  		}
   214  	})
   215  
   216  	It("start pod with port conflict", func() {
   217  		randomport, err := utils.GetRandomPort()
   218  		Expect(err).ToNot(HaveOccurred())
   219  
   220  		portPublish := fmt.Sprintf("%d:%d", randomport, randomport)
   221  		var podwithport = "newpodwithport"
   222  		bt.PodcreateAndExpose(&podwithport, &portPublish)
   223  
   224  		// Start pod and expose port 12345
   225  		_, err = pods.Start(bt.conn, podwithport, nil)
   226  		Expect(err).ToNot(HaveOccurred())
   227  
   228  		// Start another pod and expose same port 12345
   229  		var podwithport2 = "newpodwithport2"
   230  		bt.PodcreateAndExpose(&podwithport2, &portPublish)
   231  
   232  		_, err = pods.Start(bt.conn, podwithport2, nil)
   233  		Expect(err).To(HaveOccurred())
   234  		code, _ := bindings.CheckResponseCode(err)
   235  		Expect(code).To(BeNumerically("==", http.StatusConflict))
   236  		Expect(err).To(BeAssignableToTypeOf(&errorhandling.PodConflictErrorModel{}))
   237  	})
   238  
   239  	It("start stop restart pod", func() {
   240  		// Start an invalid pod
   241  		_, err = pods.Start(bt.conn, "dummyName", nil)
   242  		Expect(err).To(HaveOccurred())
   243  		code, _ := bindings.CheckResponseCode(err)
   244  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
   245  
   246  		// Stop an invalid pod
   247  		_, err = pods.Stop(bt.conn, "dummyName", nil)
   248  		Expect(err).To(HaveOccurred())
   249  		code, _ = bindings.CheckResponseCode(err)
   250  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
   251  
   252  		// Restart an invalid pod
   253  		_, err = pods.Restart(bt.conn, "dummyName", nil)
   254  		Expect(err).To(HaveOccurred())
   255  		code, _ = bindings.CheckResponseCode(err)
   256  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
   257  
   258  		// Start a valid pod and inspect status of each container
   259  		_, err = pods.Start(bt.conn, newpod, nil)
   260  		Expect(err).ToNot(HaveOccurred())
   261  
   262  		response, err := pods.Inspect(bt.conn, newpod, nil)
   263  		Expect(err).ToNot(HaveOccurred())
   264  		Expect(response.State).To(Equal(define.PodStateRunning))
   265  		for _, i := range response.Containers {
   266  			Expect(define.StringToContainerStatus(i.State)).
   267  				To(Equal(define.ContainerStateRunning))
   268  		}
   269  
   270  		// Start an already running  pod
   271  		_, err = pods.Start(bt.conn, newpod, nil)
   272  		Expect(err).ToNot(HaveOccurred())
   273  
   274  		// Stop the running pods
   275  		_, err = pods.Stop(bt.conn, newpod, nil)
   276  		Expect(err).ToNot(HaveOccurred())
   277  		response, _ = pods.Inspect(bt.conn, newpod, nil)
   278  		Expect(response.State).To(Equal(define.PodStateExited))
   279  		for _, i := range response.Containers {
   280  			Expect(define.StringToContainerStatus(i.State)).
   281  				To(Equal(define.ContainerStateExited))
   282  		}
   283  
   284  		// Stop an already stopped pod
   285  		_, err = pods.Stop(bt.conn, newpod, nil)
   286  		Expect(err).ToNot(HaveOccurred())
   287  
   288  		_, err = pods.Restart(bt.conn, newpod, nil)
   289  		Expect(err).ToNot(HaveOccurred())
   290  		response, _ = pods.Inspect(bt.conn, newpod, nil)
   291  		Expect(response.State).To(Equal(define.PodStateRunning))
   292  		for _, i := range response.Containers {
   293  			Expect(define.StringToContainerStatus(i.State)).
   294  				To(Equal(define.ContainerStateRunning))
   295  		}
   296  	})
   297  
   298  	// Test to validate all the pods in the stopped/exited state are pruned successfully.
   299  	It("prune pod", func() {
   300  		// Add a new pod
   301  		var newpod2 = "newpod2"
   302  		bt.Podcreate(&newpod2)
   303  		// No pods pruned since no pod in exited state
   304  		pruneResponse, err := pods.Prune(bt.conn, nil)
   305  		Expect(err).ToNot(HaveOccurred())
   306  		Expect(pruneResponse).To(BeEmpty(), "len(pruneResponse)")
   307  		podSummary, err := pods.List(bt.conn, nil)
   308  		Expect(err).ToNot(HaveOccurred())
   309  		Expect(podSummary).To(HaveLen(2))
   310  
   311  		// Prune only one pod which is in exited state.
   312  		// Start then stop a pod.
   313  		// pod moves to exited state one pod should be pruned now.
   314  		_, err = pods.Start(bt.conn, newpod, nil)
   315  		Expect(err).ToNot(HaveOccurred())
   316  		_, err = pods.Stop(bt.conn, newpod, nil)
   317  		Expect(err).ToNot(HaveOccurred())
   318  		response, err := pods.Inspect(bt.conn, newpod, nil)
   319  		Expect(err).ToNot(HaveOccurred())
   320  		Expect(response.State).To(Equal(define.PodStateExited))
   321  		pruneResponse, err = pods.Prune(bt.conn, nil)
   322  		Expect(err).ToNot(HaveOccurred())
   323  		Expect(pruneResponse).To(HaveLen(1), "len(pruneResponse)")
   324  		// Validate status and record pod id of pod to be pruned
   325  		Expect(response.State).To(Equal(define.PodStateExited))
   326  		podID := response.ID
   327  		// Check if right pod was pruned
   328  		Expect(pruneResponse).To(HaveLen(1))
   329  		Expect(pruneResponse[0].Id).To(Equal(podID))
   330  		// One pod is pruned hence only one pod should be active.
   331  		podSummary, err = pods.List(bt.conn, nil)
   332  		Expect(err).ToNot(HaveOccurred())
   333  		Expect(podSummary).To(HaveLen(1))
   334  
   335  		// Test prune multiple pods.
   336  		bt.Podcreate(&newpod)
   337  		_, err = pods.Start(bt.conn, newpod, nil)
   338  		Expect(err).ToNot(HaveOccurred())
   339  		_, err = pods.Start(bt.conn, newpod2, nil)
   340  		Expect(err).ToNot(HaveOccurred())
   341  		_, err = pods.Stop(bt.conn, newpod, nil)
   342  		Expect(err).ToNot(HaveOccurred())
   343  		response, err = pods.Inspect(bt.conn, newpod, nil)
   344  		Expect(err).ToNot(HaveOccurred())
   345  		Expect(response.State).To(Equal(define.PodStateExited))
   346  		for _, i := range response.Containers {
   347  			Expect(define.StringToContainerStatus(i.State)).
   348  				To(Equal(define.ContainerStateExited))
   349  		}
   350  		_, err = pods.Stop(bt.conn, newpod2, nil)
   351  		Expect(err).ToNot(HaveOccurred())
   352  		response, err = pods.Inspect(bt.conn, newpod2, nil)
   353  		Expect(err).ToNot(HaveOccurred())
   354  		Expect(response.State).To(Equal(define.PodStateExited))
   355  		for _, i := range response.Containers {
   356  			Expect(define.StringToContainerStatus(i.State)).
   357  				To(Equal(define.ContainerStateExited))
   358  		}
   359  		_, err = pods.Prune(bt.conn, nil)
   360  		Expect(err).ToNot(HaveOccurred())
   361  		podSummary, err = pods.List(bt.conn, nil)
   362  		Expect(err).ToNot(HaveOccurred())
   363  		Expect(podSummary).To(BeEmpty())
   364  	})
   365  
   366  	It("simple create pod", func() {
   367  		ps := entities.PodSpec{PodSpecGen: specgen.PodSpecGenerator{InfraContainerSpec: &specgen.SpecGenerator{}}}
   368  		ps.PodSpecGen.Name = "foobar"
   369  		_, err := pods.CreatePodFromSpec(bt.conn, &ps)
   370  		Expect(err).ToNot(HaveOccurred())
   371  
   372  		exists, err := pods.Exists(bt.conn, "foobar", nil)
   373  		Expect(err).ToNot(HaveOccurred())
   374  		Expect(exists).To(BeTrue())
   375  	})
   376  
   377  	// Test validates the pod top bindings
   378  	It("pod top", func() {
   379  		var name = "podA"
   380  
   381  		bt.Podcreate(&name)
   382  		_, err := pods.Start(bt.conn, name, nil)
   383  		Expect(err).ToNot(HaveOccurred())
   384  
   385  		// By name
   386  		_, err = pods.Top(bt.conn, name, nil)
   387  		Expect(err).ToNot(HaveOccurred())
   388  
   389  		// With descriptors
   390  		options := new(pods.TopOptions).WithDescriptors([]string{"user,pid,hpid"})
   391  		output, err := pods.Top(bt.conn, name, options)
   392  		Expect(err).ToNot(HaveOccurred())
   393  		header := strings.Split(output[0], "\t")
   394  		for _, d := range []string{"USER", "PID", "HPID"} {
   395  			Expect(d).To(BeElementOf(header))
   396  		}
   397  
   398  		// With bogus ID
   399  		_, err = pods.Top(bt.conn, "IdoNotExist", nil)
   400  		Expect(err).To(HaveOccurred())
   401  
   402  		// With bogus descriptors
   403  		options = new(pods.TopOptions).WithDescriptors([]string{"Me,Neither"})
   404  		_, err = pods.Top(bt.conn, name, options)
   405  		Expect(err).To(HaveOccurred())
   406  	})
   407  })