github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/topgun/both/build_container_gc_test.go (about)

     1  package topgun_test
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	sq "github.com/Masterminds/squirrel"
     8  	. "github.com/pf-qiu/concourse/v6/topgun/common"
     9  	_ "github.com/lib/pq"
    10  	. "github.com/onsi/ginkgo"
    11  	. "github.com/onsi/gomega"
    12  	"github.com/onsi/gomega/gbytes"
    13  )
    14  
    15  var _ = Describe("Garbage collecting build containers", func() {
    16  	BeforeEach(func() {
    17  		Deploy("deployments/concourse.yml")
    18  	})
    19  
    20  	getContainers := func(condition, value string) []string {
    21  		containers := FlyTable("containers")
    22  
    23  		var handles []string
    24  		for _, c := range containers {
    25  			if c[condition] == value {
    26  				handles = append(handles, c["handle"])
    27  			}
    28  		}
    29  
    30  		return handles
    31  	}
    32  
    33  	Describe("A container that belonged to a build that succeeded", func() {
    34  		Context("one-off builds", func() {
    35  			It("is removed from the database and worker [#129725995]", func() {
    36  				By("running a task with container having a rootfs, input, and output volume")
    37  				Fly.Run("execute", "-c", "tasks/input-output.yml", "-i", "some-input=./tasks")
    38  
    39  				By("collecting the build containers")
    40  				buildContainerHandles := getContainers("build id", "1")
    41  
    42  				By(fmt.Sprintf("eventually expiring the build containers: %v", buildContainerHandles))
    43  				Eventually(func() int {
    44  					var containerNum int
    45  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": buildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
    46  					Expect(err).ToNot(HaveOccurred())
    47  
    48  					return containerNum
    49  				}, 10*time.Minute, time.Second).Should(BeZero())
    50  
    51  				By("having removed the containers from the worker")
    52  				containers, err := WorkerGardenClient.Containers(nil)
    53  				Expect(err).ToNot(HaveOccurred())
    54  
    55  				existingHandles := []string{}
    56  				for _, c := range containers {
    57  					existingHandles = append(existingHandles, c.Handle())
    58  				}
    59  
    60  				for _, handle := range buildContainerHandles {
    61  					Expect(existingHandles).ToNot(ContainElement(handle))
    62  				}
    63  			})
    64  		})
    65  
    66  		Context("pipeline builds", func() {
    67  			It("is removed from the database and worker [#129725995]", func() {
    68  				By("setting pipeline that creates containers for check, get, task, put")
    69  				Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task-put.yml", "-p", "build-container-gc")
    70  
    71  				By("unpausing the pipeline")
    72  				Fly.Run("unpause-pipeline", "-p", "build-container-gc")
    73  
    74  				By("triggering job")
    75  				Fly.Run("trigger-job", "-w", "-j", "build-container-gc/simple-job")
    76  
    77  				By("collecting the build containers")
    78  				buildContainerHandles := getContainers("type", "task")
    79  
    80  				By(fmt.Sprintf("eventually expiring the build containers: %v", buildContainerHandles))
    81  				Eventually(func() int {
    82  					var containerNum int
    83  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": buildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
    84  					Expect(err).ToNot(HaveOccurred())
    85  
    86  					return containerNum
    87  				}, 10*time.Minute, time.Second).Should(BeZero())
    88  
    89  				By("having removed the containers from the worker")
    90  				containers, err := WorkerGardenClient.Containers(nil)
    91  				Expect(err).ToNot(HaveOccurred())
    92  
    93  				existingHandles := []string{}
    94  				for _, c := range containers {
    95  					existingHandles = append(existingHandles, c.Handle())
    96  				}
    97  
    98  				for _, handle := range buildContainerHandles {
    99  					Expect(existingHandles).ToNot(ContainElement(handle))
   100  				}
   101  			})
   102  		})
   103  	})
   104  
   105  	Describe("A container that belonged to a build that fails", func() {
   106  		Context("pipeline builds", func() {
   107  			It("keeps in the database and worker [#129725995]", func() {
   108  				By("setting pipeline that creates containers for check, get, task, put")
   109  				Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task-put-failing.yml", "-p", "build-container-gc")
   110  
   111  				By("unpausing the pipeline")
   112  				Fly.Run("unpause-pipeline", "-p", "build-container-gc")
   113  
   114  				By("triggering job")
   115  				<-Fly.Start("trigger-job", "-w", "-j", "build-container-gc/simple-job").Exited
   116  
   117  				By("collecting the build containers")
   118  				buildContainerHandles := getContainers("type", "task")
   119  
   120  				By(fmt.Sprintf("not expiring the build containers: %v", buildContainerHandles))
   121  				Consistently(func() int {
   122  					var containerNum int
   123  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": buildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
   124  					Expect(err).ToNot(HaveOccurred())
   125  
   126  					return containerNum
   127  				}, 2*time.Minute, time.Second).Should(Equal(len(buildContainerHandles)))
   128  
   129  				By("not removing the containers from the worker")
   130  				containers, err := WorkerGardenClient.Containers(nil)
   131  				Expect(err).ToNot(HaveOccurred())
   132  
   133  				existingHandles := []string{}
   134  				for _, c := range containers {
   135  					existingHandles = append(existingHandles, c.Handle())
   136  				}
   137  
   138  				for _, handle := range buildContainerHandles {
   139  					Expect(existingHandles).To(ContainElement(handle))
   140  				}
   141  			})
   142  		})
   143  
   144  		Context("pipeline builds that fail subsequently", func() {
   145  			It("keeps the latest build containers in the database and worker, removes old build containers from database and worker [#129725995]", func() {
   146  				By("setting pipeline that creates containers for check, get, task, put")
   147  				Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task-put-failing.yml", "-p", "build-container-gc")
   148  
   149  				By("unpausing the pipeline")
   150  				Fly.Run("unpause-pipeline", "-p", "build-container-gc")
   151  
   152  				By("triggering first job")
   153  				<-Fly.Start("trigger-job", "-w", "-j", "build-container-gc/simple-job").Exited
   154  
   155  				By("collecting the first build containers")
   156  				firstBuildContainerHandles := getContainers("type", "task")
   157  
   158  				By("triggering second job")
   159  				<-Fly.Start("trigger-job", "-w", "-j", "build-container-gc/simple-job").Exited
   160  
   161  				By("collecting the second build containers")
   162  				allBuildContainerHandles := getContainers("type", "task")
   163  
   164  				var secondBuildContainerHandles []string
   165  				for _, handle := range allBuildContainerHandles {
   166  					alreadyExisted := false
   167  					for _, preHandle := range firstBuildContainerHandles {
   168  						if preHandle == handle {
   169  							alreadyExisted = true
   170  							break
   171  						}
   172  					}
   173  
   174  					if !alreadyExisted {
   175  						secondBuildContainerHandles = append(secondBuildContainerHandles, handle)
   176  					}
   177  				}
   178  
   179  				By(fmt.Sprintf("eventually expiring the first build containers: %v", firstBuildContainerHandles))
   180  				Eventually(func() int {
   181  					var containerNum int
   182  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": firstBuildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
   183  					Expect(err).ToNot(HaveOccurred())
   184  
   185  					return containerNum
   186  				}, 10*time.Minute, time.Second).Should(BeZero())
   187  
   188  				By("having removed the first build containers from the worker")
   189  				containers, err := WorkerGardenClient.Containers(nil)
   190  				Expect(err).ToNot(HaveOccurred())
   191  
   192  				existingHandles := []string{}
   193  				for _, c := range containers {
   194  					existingHandles = append(existingHandles, c.Handle())
   195  				}
   196  
   197  				for _, handle := range firstBuildContainerHandles {
   198  					Expect(existingHandles).NotTo(ContainElement(handle))
   199  				}
   200  
   201  				By(fmt.Sprintf("not expiring the second build containers: %v", secondBuildContainerHandles))
   202  				Consistently(func() int {
   203  					var containerNum int
   204  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": secondBuildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
   205  					Expect(err).ToNot(HaveOccurred())
   206  
   207  					return containerNum
   208  				}, 2*time.Minute, time.Second).Should(Equal(len(secondBuildContainerHandles)))
   209  
   210  				By("not removing the containers from the worker")
   211  				for _, handle := range secondBuildContainerHandles {
   212  					Expect(existingHandles).To(ContainElement(handle))
   213  				}
   214  			})
   215  		})
   216  
   217  		Context("pipeline builds that is running and previous build failed", func() {
   218  			It("keeps both the latest and previous build containers in the database and worker [#129725995]", func() {
   219  				By("setting pipeline that creates containers for check, get, task, put")
   220  				Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task-put-failing.yml", "-p", "build-container-gc")
   221  
   222  				By("unpausing the pipeline")
   223  				Fly.Run("unpause-pipeline", "-p", "build-container-gc")
   224  
   225  				By("triggering first failing job")
   226  				<-Fly.Start("trigger-job", "-w", "-j", "build-container-gc/simple-job").Exited
   227  
   228  				By("collecting the first build containers")
   229  				firstBuildContainerHandles := getContainers("type", "task")
   230  
   231  				By("triggering second long running job")
   232  				Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task-put-waiting.yml", "-p", "build-container-gc")
   233  				runningBuildSession := Fly.Start("trigger-job", "-w", "-j", "build-container-gc/simple-job")
   234  				Eventually(runningBuildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting"))
   235  
   236  				By("collecting the second build containers")
   237  				allBuildContainerHandles := getContainers("type", "task")
   238  
   239  				var secondBuildContainerHandles []string
   240  				for _, handle := range allBuildContainerHandles {
   241  					alreadyExisted := false
   242  					for _, preHandle := range firstBuildContainerHandles {
   243  						if preHandle == handle {
   244  							alreadyExisted = true
   245  							break
   246  						}
   247  					}
   248  
   249  					if !alreadyExisted {
   250  						secondBuildContainerHandles = append(secondBuildContainerHandles, handle)
   251  					}
   252  				}
   253  
   254  				By(fmt.Sprintf("not expiring the first build containers: %v", firstBuildContainerHandles))
   255  				Consistently(func() int {
   256  					var containerNum int
   257  					err := Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": firstBuildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
   258  					Expect(err).ToNot(HaveOccurred())
   259  
   260  					return containerNum
   261  				}, 2*time.Minute, time.Second).Should(Equal(len(firstBuildContainerHandles)))
   262  
   263  				By("not removing the first build containers from the worker")
   264  				containers, err := WorkerGardenClient.Containers(nil)
   265  				Expect(err).ToNot(HaveOccurred())
   266  
   267  				existingHandles := []string{}
   268  				for _, c := range containers {
   269  					existingHandles = append(existingHandles, c.Handle())
   270  				}
   271  
   272  				for _, handle := range firstBuildContainerHandles {
   273  					Expect(existingHandles).To(ContainElement(handle))
   274  				}
   275  
   276  				By(fmt.Sprintf("not expiring the second build containers: %v", secondBuildContainerHandles))
   277  				Consistently(func() int {
   278  					var containerNum int
   279  					err = Psql.Select("COUNT(id)").From("containers").Where(sq.Eq{"handle": secondBuildContainerHandles}).RunWith(DbConn).QueryRow().Scan(&containerNum)
   280  					Expect(err).ToNot(HaveOccurred())
   281  
   282  					return containerNum
   283  				}, 2*time.Minute, time.Second).Should(Equal(len(secondBuildContainerHandles)))
   284  
   285  				By("not removing the second build containers from the worker")
   286  				for _, handle := range secondBuildContainerHandles {
   287  					Expect(existingHandles).To(ContainElement(handle))
   288  				}
   289  
   290  				Fly.Run("abort-build", "-j", "build-container-gc/simple-job", "-b", "2")
   291  
   292  				<-runningBuildSession.Exited
   293  			})
   294  		})
   295  	})
   296  })