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

     1  package bindings_test
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"time"
     8  
     9  	"github.com/containers/podman/v4/pkg/bindings"
    10  	"github.com/containers/podman/v4/pkg/bindings/containers"
    11  	"github.com/containers/podman/v4/pkg/bindings/volumes"
    12  	"github.com/containers/podman/v4/pkg/domain/entities"
    13  	"github.com/containers/podman/v4/pkg/domain/entities/reports"
    14  	. "github.com/onsi/ginkgo/v2"
    15  	. "github.com/onsi/gomega"
    16  	"github.com/onsi/gomega/gexec"
    17  )
    18  
    19  var _ = Describe("Podman volumes", func() {
    20  	var (
    21  		bt       *bindingTest
    22  		s        *gexec.Session
    23  		connText context.Context
    24  		err      error
    25  	)
    26  
    27  	BeforeEach(func() {
    28  		bt = newBindingTest()
    29  		bt.RestoreImagesFromCache()
    30  		s = bt.startAPIService()
    31  		time.Sleep(1 * time.Second)
    32  		connText, err = bindings.NewConnection(context.Background(), bt.sock)
    33  		Expect(err).ToNot(HaveOccurred())
    34  	})
    35  
    36  	AfterEach(func() {
    37  		s.Kill()
    38  		bt.cleanup()
    39  	})
    40  
    41  	It("create volume", func() {
    42  		// create a volume with blank config should work
    43  		_, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
    44  		Expect(err).ToNot(HaveOccurred())
    45  
    46  		vcc := entities.VolumeCreateOptions{
    47  			Name:    "foobar",
    48  			Label:   nil,
    49  			Options: nil,
    50  		}
    51  		vol, err := volumes.Create(connText, vcc, nil)
    52  		Expect(err).ToNot(HaveOccurred())
    53  		Expect(vol.Name).To(Equal("foobar"))
    54  
    55  		// create volume with same name should 500
    56  		_, err = volumes.Create(connText, vcc, nil)
    57  		Expect(err).To(HaveOccurred())
    58  		code, _ := bindings.CheckResponseCode(err)
    59  		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
    60  	})
    61  
    62  	It("inspect volume", func() {
    63  		vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
    64  		Expect(err).ToNot(HaveOccurred())
    65  		data, err := volumes.Inspect(connText, vol.Name, nil)
    66  		Expect(err).ToNot(HaveOccurred())
    67  		Expect(data.Name).To(Equal(vol.Name))
    68  	})
    69  
    70  	It("remove volume", func() {
    71  		// removing a bogus volume should result in 404
    72  		err := volumes.Remove(connText, "foobar", nil)
    73  		code, err := bindings.CheckResponseCode(err)
    74  		Expect(err).ToNot(HaveOccurred())
    75  		Expect(code).To(BeNumerically("==", http.StatusNotFound))
    76  
    77  		// Removing an unused volume should work
    78  		vol, err := volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
    79  		Expect(err).ToNot(HaveOccurred())
    80  		err = volumes.Remove(connText, vol.Name, nil)
    81  		Expect(err).ToNot(HaveOccurred())
    82  
    83  		// Removing a volume that is being used without force should be 409
    84  		vol, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
    85  		Expect(err).ToNot(HaveOccurred())
    86  		session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/foobar", vol.Name), "--name", "vtest", alpine.name, "top"})
    87  		session.Wait(45)
    88  		Expect(session.ExitCode()).To(BeZero())
    89  
    90  		err = volumes.Remove(connText, vol.Name, nil)
    91  		Expect(err).To(HaveOccurred())
    92  		code, err = bindings.CheckResponseCode(err)
    93  		Expect(err).ToNot(HaveOccurred())
    94  		Expect(code).To(BeNumerically("==", http.StatusConflict))
    95  
    96  		// Removing with a volume in use with force should work with a stopped container
    97  		err = containers.Stop(connText, "vtest", new(containers.StopOptions).WithTimeout(0))
    98  		Expect(err).ToNot(HaveOccurred())
    99  		options := new(volumes.RemoveOptions).WithForce(true)
   100  		err = volumes.Remove(connText, vol.Name, options)
   101  		Expect(err).ToNot(HaveOccurred())
   102  	})
   103  
   104  	It("list volumes", func() {
   105  		// no volumes should be ok
   106  		vols, err := volumes.List(connText, nil)
   107  		Expect(err).ToNot(HaveOccurred())
   108  		Expect(vols).To(BeEmpty())
   109  
   110  		// create a bunch of named volumes and make verify with list
   111  		volNames := []string{"homer", "bart", "lisa", "maggie", "marge"}
   112  		for i := 0; i < 5; i++ {
   113  			_, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: volNames[i]}, nil)
   114  			Expect(err).ToNot(HaveOccurred())
   115  		}
   116  		vols, err = volumes.List(connText, nil)
   117  		Expect(err).ToNot(HaveOccurred())
   118  		Expect(vols).To(HaveLen(5))
   119  		for _, v := range vols {
   120  			Expect(StringInSlice(v.Name, volNames)).To(BeTrue())
   121  		}
   122  
   123  		// list with bad filter should be 500
   124  		filters := make(map[string][]string)
   125  		filters["foobar"] = []string{"1234"}
   126  		options := new(volumes.ListOptions).WithFilters(filters)
   127  		_, err = volumes.List(connText, options)
   128  		Expect(err).To(HaveOccurred())
   129  		code, _ := bindings.CheckResponseCode(err)
   130  		Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
   131  
   132  		filters = make(map[string][]string)
   133  		filters["name"] = []string{"homer"}
   134  		options = new(volumes.ListOptions).WithFilters(filters)
   135  		vols, err = volumes.List(connText, options)
   136  		Expect(err).ToNot(HaveOccurred())
   137  		Expect(vols).To(HaveLen(1))
   138  		Expect(vols[0].Name).To(Equal("homer"))
   139  	})
   140  
   141  	It("prune unused volume", func() {
   142  		// Pruning when no volumes present should be ok
   143  		_, err := volumes.Prune(connText, nil)
   144  		Expect(err).ToNot(HaveOccurred())
   145  
   146  		// Removing an unused volume should work
   147  		_, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
   148  		Expect(err).ToNot(HaveOccurred())
   149  		vols, err := volumes.Prune(connText, nil)
   150  		Expect(err).ToNot(HaveOccurred())
   151  		Expect(vols).To(HaveLen(1))
   152  
   153  		_, err = volumes.Create(connText, entities.VolumeCreateOptions{Name: "homer"}, nil)
   154  		Expect(err).ToNot(HaveOccurred())
   155  		_, err = volumes.Create(connText, entities.VolumeCreateOptions{}, nil)
   156  		Expect(err).ToNot(HaveOccurred())
   157  		session := bt.runPodman([]string{"run", "-dt", "-v", fmt.Sprintf("%s:/homer", "homer"), "--name", "vtest", alpine.name, "top"})
   158  		session.Wait(45)
   159  		vols, err = volumes.Prune(connText, nil)
   160  		Expect(err).ToNot(HaveOccurred())
   161  		Expect(reports.PruneReportsIds(vols)).To(HaveLen(1))
   162  		_, err = volumes.Inspect(connText, "homer", nil)
   163  		Expect(err).ToNot(HaveOccurred())
   164  
   165  		// Removing volume with non matching filter shouldn't prune any volumes
   166  		filters := make(map[string][]string)
   167  		filters["label"] = []string{"label1=idontmatch"}
   168  		_, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
   169  			"label1": "value1",
   170  		}}, nil)
   171  		Expect(err).ToNot(HaveOccurred())
   172  		options := new(volumes.PruneOptions).WithFilters(filters)
   173  		vols, err = volumes.Prune(connText, options)
   174  		Expect(err).ToNot(HaveOccurred())
   175  		Expect(vols).To(BeEmpty())
   176  		vol2, err := volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
   177  			"label1": "value2",
   178  		}}, nil)
   179  		Expect(err).ToNot(HaveOccurred())
   180  		_, err = volumes.Create(connText, entities.VolumeCreateOptions{Label: map[string]string{
   181  			"label1": "value3",
   182  		}}, nil)
   183  		Expect(err).ToNot(HaveOccurred())
   184  
   185  		// Removing volume with matching filter label and value should remove specific entry
   186  		filters = make(map[string][]string)
   187  		filters["label"] = []string{"label1=value2"}
   188  		options = new(volumes.PruneOptions).WithFilters(filters)
   189  		vols, err = volumes.Prune(connText, options)
   190  		Expect(err).ToNot(HaveOccurred())
   191  		Expect(vols).To(HaveLen(1))
   192  		Expect(vols[0].Id).To(Equal(vol2.Name))
   193  
   194  		// Removing volumes with matching filter label should remove all matching volumes
   195  		filters = make(map[string][]string)
   196  		filters["label"] = []string{"label1"}
   197  		options = new(volumes.PruneOptions).WithFilters(filters)
   198  		vols, err = volumes.Prune(connText, options)
   199  		Expect(err).ToNot(HaveOccurred())
   200  		Expect(vols).To(HaveLen(2))
   201  	})
   202  
   203  })