github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/integration/lifecycle/flags_test.go (about)

     1  package lifecycle_test
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"os"
     9  	"os/exec"
    10  	"path"
    11  
    12  	"github.com/cloudfoundry-incubator/garden"
    13  	"github.com/cloudfoundry-incubator/garden-linux/integration/runner"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	"github.com/onsi/gomega/gbytes"
    17  )
    18  
    19  var _ = Describe("Garden startup flags", func() {
    20  
    21  	var debugAddr string
    22  
    23  	BeforeEach(func() {
    24  		debugAddr = fmt.Sprintf("0.0.0.0:%d", 15000+GinkgoParallelNode())
    25  	})
    26  
    27  	Context("when starting without the --debugAddr flag", func() {
    28  		BeforeEach(func() {
    29  			client = startGarden()
    30  		})
    31  
    32  		It("does not expose the pprof debug endpoint", func() {
    33  			_, err := http.Get(fmt.Sprintf("http://%s/debug/pprof/?debug=1", debugAddr))
    34  			Expect(err).To(HaveOccurred())
    35  		})
    36  
    37  		It("does not expose the log level adjustment endpoint", func() {
    38  			_, err := http.Get(fmt.Sprintf("http://%s/log-level -X PUT -d debug", debugAddr))
    39  			Expect(err).To(HaveOccurred())
    40  		})
    41  	})
    42  
    43  	Context("when started with the --maxContainers flag", func() {
    44  		Context("when maxContainers is lower than the subnet pool capacity", func() {
    45  			BeforeEach(func() {
    46  				client = startGarden("--maxContainers", "1")
    47  			})
    48  
    49  			Context("when getting the capacity", func() {
    50  				It("returns the maxContainers flag value", func() {
    51  					capacity, err := client.Capacity()
    52  					Expect(err).ToNot(HaveOccurred())
    53  					Expect(capacity.MaxContainers).To(Equal(uint64(1)))
    54  				})
    55  			})
    56  		})
    57  
    58  		Context("when maxContainers is higher than the subnet pool capacity", func() {
    59  			BeforeEach(func() {
    60  				client = startGarden("--maxContainers", "1000")
    61  			})
    62  
    63  			Context("when getting the capacity", func() {
    64  				It("returns the capacity of the subnet pool", func() {
    65  					capacity, err := client.Capacity()
    66  					Expect(err).ToNot(HaveOccurred())
    67  					Expect(capacity.MaxContainers).To(Equal(uint64(64)))
    68  				})
    69  			})
    70  		})
    71  	})
    72  
    73  	Context("when starting with the --debugAddr flag", func() {
    74  		BeforeEach(func() {
    75  			client = startGarden("--debugAddr", debugAddr)
    76  		})
    77  
    78  		It("exposes the pprof debug endpoint", func() {
    79  			_, err := http.Get(fmt.Sprintf("http://%s/debug/pprof/?debug=1", debugAddr))
    80  			Expect(err).ToNot(HaveOccurred())
    81  		})
    82  
    83  		It("exposes the log level adjustment endpoint", func() {
    84  			_, err := http.Get(fmt.Sprintf("http://%s/log-level -X PUT -d debug", debugAddr))
    85  			Expect(err).ToNot(HaveOccurred())
    86  
    87  			_, err = http.Get(fmt.Sprintf("http://%s/log-level -X PUT -d info", debugAddr))
    88  			Expect(err).ToNot(HaveOccurred())
    89  
    90  			_, err = http.Get(fmt.Sprintf("http://%s/log-level -X PUT -d error", debugAddr))
    91  			Expect(err).ToNot(HaveOccurred())
    92  
    93  			_, err = http.Get(fmt.Sprintf("http://%s/log-level -X PUT -d fatal", debugAddr))
    94  			Expect(err).ToNot(HaveOccurred())
    95  		})
    96  
    97  		Describe("vars", func() {
    98  			var (
    99  				diskLimits garden.DiskLimits
   100  				container  garden.Container
   101  				vars       map[string]interface{}
   102  			)
   103  
   104  			BeforeEach(func() {
   105  				diskLimits = garden.DiskLimits{
   106  					ByteHard: 10 * 1024 * 1024,
   107  					Scope:    garden.DiskLimitScopeExclusive,
   108  				}
   109  			})
   110  
   111  			JustBeforeEach(func() {
   112  				var err error
   113  
   114  				container, err = client.Create(garden.ContainerSpec{
   115  					Limits: garden.Limits{
   116  						Disk: diskLimits,
   117  					},
   118  					RootFSPath: "docker:///busybox",
   119  				})
   120  				Expect(err).NotTo(HaveOccurred())
   121  
   122  				response, err := http.Get(fmt.Sprintf("http://%s/debug/vars", debugAddr))
   123  				Expect(err).ToNot(HaveOccurred())
   124  
   125  				contents, err := ioutil.ReadAll(response.Body)
   126  				Expect(err).ToNot(HaveOccurred())
   127  
   128  				vars = make(map[string]interface{})
   129  				Expect(json.Unmarshal(contents, &vars)).To(Succeed())
   130  			})
   131  
   132  			AfterEach(func() {
   133  				Expect(client.Destroy(container.Handle())).To(Succeed())
   134  			})
   135  
   136  			It("exposes the number of loop devices", func() {
   137  				Expect(vars["loopDevices"]).To(BeNumerically(">=", float64(1)))
   138  			})
   139  
   140  			It("exposes the number of depot directories", func() {
   141  				Expect(vars["depotDirs"]).To(Equal(float64(1)))
   142  			})
   143  
   144  			It("exposes the number of backing stores", func() {
   145  				Expect(vars["backingStores"]).To(Equal(float64(1)))
   146  			})
   147  
   148  			Context("when the container does not have a limit", func() {
   149  				BeforeEach(func() {
   150  					diskLimits = garden.DiskLimits{}
   151  				})
   152  
   153  				It("should not have any backing stores", func() {
   154  					Expect(vars["depotDirs"]).To(Equal(float64(1)))
   155  					Expect(vars["backingStores"]).To(Equal(float64(0)))
   156  				})
   157  			})
   158  		})
   159  	})
   160  
   161  	Describe("graph cleanup flags", func() {
   162  		var (
   163  			layersPath           string
   164  			diffPath             string
   165  			mntPath              string
   166  			nonDefaultRootfsPath string
   167  			args                 []string
   168  			persistentImages     []string
   169  		)
   170  
   171  		numLayersInGraph := func() int {
   172  			layerFiles, err := ioutil.ReadDir(layersPath)
   173  			Expect(err).ToNot(HaveOccurred())
   174  			diffFiles, err := ioutil.ReadDir(diffPath)
   175  			Expect(err).ToNot(HaveOccurred())
   176  			mntFiles, err := ioutil.ReadDir(mntPath)
   177  			Expect(err).ToNot(HaveOccurred())
   178  
   179  			numLayerFiles := len(layerFiles)
   180  			Expect(numLayerFiles).To(Equal(len(diffFiles)))
   181  			Expect(numLayerFiles).To(Equal(len(mntFiles)))
   182  			return numLayerFiles
   183  		}
   184  
   185  		expectLayerCountAfterGraphCleanupToBe := func(layerCount int) {
   186  			nonPersistantRootfsContainer, err := client.Create(garden.ContainerSpec{
   187  				RootFSPath: nonDefaultRootfsPath,
   188  			})
   189  			Expect(err).ToNot(HaveOccurred())
   190  			Expect(client.Destroy(nonPersistantRootfsContainer.Handle())).To(Succeed())
   191  			Expect(numLayersInGraph()).To(Equal(layerCount + 2)) // +2 for the layers created for the nondefaultrootfs container
   192  		}
   193  
   194  		BeforeEach(func() {
   195  			var err error
   196  			nonDefaultRootfsPath, err = ioutil.TempDir("", "tmpRootfs")
   197  			Expect(err).ToNot(HaveOccurred())
   198  		})
   199  
   200  		JustBeforeEach(func() {
   201  			for _, image := range persistentImages {
   202  				args = append(args, "--persistentImage", image)
   203  			}
   204  			client = startGarden(args...)
   205  
   206  			layersPath = path.Join(client.GraphPath, "aufs", "layers")
   207  			diffPath = path.Join(client.GraphPath, "aufs", "diff")
   208  			mntPath = path.Join(client.GraphPath, "aufs", "mnt")
   209  		})
   210  
   211  		AfterEach(func() {
   212  			Expect(os.RemoveAll(nonDefaultRootfsPath)).To(Succeed())
   213  		})
   214  
   215  		Describe("--enableGraphCleanup", func() {
   216  
   217  			JustBeforeEach(func() {
   218  				container, err := client.Create(garden.ContainerSpec{
   219  					RootFSPath: "docker:///busybox",
   220  				})
   221  				Expect(err).ToNot(HaveOccurred())
   222  				Expect(client.Destroy(container.Handle())).To(Succeed())
   223  			})
   224  
   225  			Context("when starting without the flag", func() {
   226  				BeforeEach(func() {
   227  					args = []string{"-enableGraphCleanup=false"}
   228  				})
   229  
   230  				It("does NOT clean up the graph directory on create", func() {
   231  					initialNumberOfLayers := numLayersInGraph()
   232  					anotherContainer, err := client.Create(garden.ContainerSpec{})
   233  					Expect(err).ToNot(HaveOccurred())
   234  
   235  					Expect(numLayersInGraph()).To(BeNumerically(">", initialNumberOfLayers), "after creation, should NOT have deleted anything")
   236  					Expect(client.Destroy(anotherContainer.Handle())).To(Succeed())
   237  				})
   238  			})
   239  
   240  			Context("when starting with the flag", func() {
   241  				BeforeEach(func() {
   242  					args = []string{"-enableGraphCleanup=true"}
   243  				})
   244  
   245  				Context("when there are other rootfs layers in the graph dir", func() {
   246  					BeforeEach(func() {
   247  						args = append(args, "-persistentImage", "docker:///busybox")
   248  					})
   249  
   250  					It("cleans up the graph directory on container creation (and not on destruction)", func() {
   251  						restartGarden("-enableGraphCleanup=true") // restart with persistent image list empty
   252  						Expect(numLayersInGraph()).To(BeNumerically(">", 0))
   253  
   254  						anotherContainer, err := client.Create(garden.ContainerSpec{})
   255  						Expect(err).ToNot(HaveOccurred())
   256  
   257  						Expect(numLayersInGraph()).To(Equal(3), "after creation, should have deleted everything other than the default rootfs, uid translation layer and container layer")
   258  						Expect(client.Destroy(anotherContainer.Handle())).To(Succeed())
   259  						Expect(numLayersInGraph()).To(Equal(2), "should not garbage collect parent layers on destroy")
   260  					})
   261  				})
   262  			})
   263  		})
   264  
   265  		Describe("--persistentImage", func() {
   266  			BeforeEach(func() {
   267  				args = []string{"-enableGraphCleanup=true"}
   268  			})
   269  
   270  			Context("when set", func() {
   271  				JustBeforeEach(func() {
   272  					Eventually(client, "30s").Should(gbytes.Say("retain.retained"))
   273  				})
   274  
   275  				Context("and local images are used", func() {
   276  					BeforeEach(func() {
   277  						persistentImages = []string{runner.RootFSPath}
   278  					})
   279  
   280  					Describe("graph cleanup for a rootfs on the whitelist", func() {
   281  						It("keeps the rootfs in the graph", func() {
   282  							container, err := client.Create(garden.ContainerSpec{
   283  								RootFSPath: persistentImages[0],
   284  							})
   285  							Expect(err).ToNot(HaveOccurred())
   286  							Expect(client.Destroy(container.Handle())).To(Succeed())
   287  
   288  							expectLayerCountAfterGraphCleanupToBe(2)
   289  						})
   290  
   291  						Context("which is a symlink", func() {
   292  							BeforeEach(func() {
   293  								Expect(os.MkdirAll("/var/vcap/packages", 0755)).To(Succeed())
   294  								err := exec.Command("ln", "-s", runner.RootFSPath, "/var/vcap/packages/busybox").Run()
   295  								Expect(err).ToNot(HaveOccurred())
   296  
   297  								persistentImages = []string{"/var/vcap/packages/busybox"}
   298  							})
   299  
   300  							It("keeps the rootfs in the graph", func() {
   301  								container, err := client.Create(garden.ContainerSpec{
   302  									RootFSPath: persistentImages[0],
   303  								})
   304  								Expect(err).ToNot(HaveOccurred())
   305  								Expect(client.Destroy(container.Handle())).To(Succeed())
   306  
   307  								expectLayerCountAfterGraphCleanupToBe(2)
   308  							})
   309  						})
   310  					})
   311  
   312  					Describe("graph cleanup for a rootfs not on the whitelist", func() {
   313  						It("cleans up all unused images from the graph", func() {
   314  							container, err := client.Create(garden.ContainerSpec{
   315  								RootFSPath: nonDefaultRootfsPath,
   316  							})
   317  							Expect(err).ToNot(HaveOccurred())
   318  							Expect(client.Destroy(container.Handle())).To(Succeed())
   319  
   320  							expectLayerCountAfterGraphCleanupToBe(0)
   321  						})
   322  					})
   323  				})
   324  
   325  				Context("and docker images are used", func() {
   326  					BeforeEach(func() {
   327  						persistentImages = []string{
   328  							"docker:///busybox",
   329  							"docker:///ubuntu",
   330  							"docker://banana/bananatest",
   331  						}
   332  					})
   333  
   334  					Describe("graph cleanup for a rootfs on the whitelist", func() {
   335  						It("keeps the rootfs in the graph", func() {
   336  							numLayersBeforeDockerPull := numLayersInGraph()
   337  							container, err := client.Create(garden.ContainerSpec{
   338  								RootFSPath: persistentImages[0],
   339  							})
   340  							Expect(err).ToNot(HaveOccurred())
   341  							Expect(client.Destroy(container.Handle())).To(Succeed())
   342  							numLayersInImage := numLayersInGraph() - numLayersBeforeDockerPull
   343  
   344  							expectLayerCountAfterGraphCleanupToBe(numLayersInImage)
   345  						})
   346  					})
   347  
   348  					Describe("graph cleanup for a rootfs not on the whitelist", func() {
   349  						It("cleans up all unused images from the graph", func() {
   350  							container, err := client.Create(garden.ContainerSpec{
   351  								RootFSPath: "docker:///cfgarden/garden-busybox",
   352  							})
   353  							Expect(err).ToNot(HaveOccurred())
   354  							Expect(client.Destroy(container.Handle())).To(Succeed())
   355  
   356  							expectLayerCountAfterGraphCleanupToBe(0)
   357  						})
   358  					})
   359  				})
   360  			})
   361  
   362  			Context("when it is not set", func() {
   363  				BeforeEach(func() {
   364  					persistentImages = []string{}
   365  				})
   366  
   367  				It("cleans up all unused images from the graph", func() {
   368  					defaultRootfsContainer, err := client.Create(garden.ContainerSpec{})
   369  					Expect(err).ToNot(HaveOccurred())
   370  
   371  					nonDefaultRootfsContainer, err := client.Create(garden.ContainerSpec{
   372  						RootFSPath: nonDefaultRootfsPath,
   373  					})
   374  					Expect(err).ToNot(HaveOccurred())
   375  
   376  					Expect(client.Destroy(defaultRootfsContainer.Handle())).To(Succeed())
   377  					Expect(client.Destroy(nonDefaultRootfsContainer.Handle())).To(Succeed())
   378  
   379  					expectLayerCountAfterGraphCleanupToBe(0)
   380  				})
   381  			})
   382  		})
   383  	})
   384  })