github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/db/worker_test.go (about)

     1  package db_test
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/pf-qiu/concourse/v6/atc"
     9  	. "github.com/pf-qiu/concourse/v6/atc/db"
    10  
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/ginkgo/extensions/table"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/types"
    15  )
    16  
    17  var _ = Describe("Worker", func() {
    18  	var (
    19  		atcWorker atc.Worker
    20  		worker    Worker
    21  	)
    22  
    23  	BeforeEach(func() {
    24  		atcWorker = atc.Worker{
    25  			GardenAddr:       "some-garden-addr",
    26  			BaggageclaimURL:  "some-bc-url",
    27  			HTTPProxyURL:     "some-http-proxy-url",
    28  			HTTPSProxyURL:    "some-https-proxy-url",
    29  			NoProxy:          "some-no-proxy",
    30  			Ephemeral:        true,
    31  			ActiveContainers: 140,
    32  			ResourceTypes: []atc.WorkerResourceType{
    33  				{
    34  					Type:    "some-resource-type",
    35  					Image:   "some-image",
    36  					Version: "some-version",
    37  				},
    38  				{
    39  					Type:    "other-resource-type",
    40  					Image:   "other-image",
    41  					Version: "other-version",
    42  				},
    43  			},
    44  			Platform:  "some-platform",
    45  			Tags:      atc.Tags{"some", "tags"},
    46  			Name:      "some-name",
    47  			StartTime: 55912945,
    48  		}
    49  	})
    50  
    51  	Describe("Land", func() {
    52  		BeforeEach(func() {
    53  			var err error
    54  			worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
    55  			Expect(err).NotTo(HaveOccurred())
    56  		})
    57  
    58  		Context("when the worker is present", func() {
    59  			It("marks the worker as `landing`", func() {
    60  				err := worker.Land()
    61  				Expect(err).NotTo(HaveOccurred())
    62  
    63  				_, err = worker.Reload()
    64  				Expect(err).NotTo(HaveOccurred())
    65  				Expect(worker.Name()).To(Equal(atcWorker.Name))
    66  				Expect(worker.State()).To(Equal(WorkerStateLanding))
    67  			})
    68  
    69  			Context("when worker is already landed", func() {
    70  				BeforeEach(func() {
    71  					err := worker.Land()
    72  					Expect(err).NotTo(HaveOccurred())
    73  					_, err = workerLifecycle.LandFinishedLandingWorkers()
    74  					Expect(err).NotTo(HaveOccurred())
    75  				})
    76  
    77  				It("keeps worker state as landed", func() {
    78  					err := worker.Land()
    79  					Expect(err).NotTo(HaveOccurred())
    80  					_, err = worker.Reload()
    81  					Expect(err).NotTo(HaveOccurred())
    82  
    83  					Expect(worker.Name()).To(Equal(atcWorker.Name))
    84  					Expect(worker.State()).To(Equal(WorkerStateLanded))
    85  				})
    86  			})
    87  		})
    88  
    89  		Context("when the worker is not present", func() {
    90  			It("returns an error", func() {
    91  				err := worker.Delete()
    92  				Expect(err).NotTo(HaveOccurred())
    93  
    94  				err = worker.Land()
    95  				Expect(err).To(HaveOccurred())
    96  				Expect(err).To(Equal(ErrWorkerNotPresent))
    97  			})
    98  		})
    99  	})
   100  
   101  	Describe("Retire", func() {
   102  		BeforeEach(func() {
   103  			var err error
   104  			worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
   105  			Expect(err).NotTo(HaveOccurred())
   106  		})
   107  
   108  		Context("when the worker is present", func() {
   109  			It("marks the worker as `retiring`", func() {
   110  				err := worker.Retire()
   111  				Expect(err).NotTo(HaveOccurred())
   112  
   113  				_, err = worker.Reload()
   114  				Expect(err).NotTo(HaveOccurred())
   115  				Expect(worker.Name()).To(Equal(atcWorker.Name))
   116  				Expect(worker.State()).To(Equal(WorkerStateRetiring))
   117  			})
   118  		})
   119  
   120  		Context("when the worker is not present", func() {
   121  			BeforeEach(func() {
   122  				err := worker.Delete()
   123  				Expect(err).NotTo(HaveOccurred())
   124  			})
   125  
   126  			It("returns an error", func() {
   127  				err := worker.Retire()
   128  				Expect(err).To(HaveOccurred())
   129  				Expect(err).To(Equal(ErrWorkerNotPresent))
   130  			})
   131  		})
   132  	})
   133  
   134  	Describe("Delete", func() {
   135  		BeforeEach(func() {
   136  			var err error
   137  			worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
   138  			Expect(err).NotTo(HaveOccurred())
   139  		})
   140  
   141  		It("deletes the record for the worker", func() {
   142  			err := worker.Delete()
   143  			Expect(err).NotTo(HaveOccurred())
   144  
   145  			_, found, err := workerFactory.GetWorker(atcWorker.Name)
   146  			Expect(err).ToNot(HaveOccurred())
   147  			Expect(found).To(BeFalse())
   148  		})
   149  	})
   150  
   151  	Describe("Prune", func() {
   152  		Context("when worker exists", func() {
   153  			DescribeTable("worker in state",
   154  				func(workerState string, errMatch GomegaMatcher) {
   155  					worker, err := workerFactory.SaveWorker(atc.Worker{
   156  						Name:       "worker-to-prune",
   157  						GardenAddr: "1.2.3.4",
   158  						State:      workerState,
   159  					}, 5*time.Minute)
   160  					Expect(err).NotTo(HaveOccurred())
   161  
   162  					err = worker.Prune()
   163  					Expect(err).To(errMatch)
   164  				},
   165  
   166  				Entry("running", "running", Equal(ErrCannotPruneRunningWorker)),
   167  				Entry("landing", "landing", BeNil()),
   168  				Entry("retiring", "retiring", BeNil()),
   169  			)
   170  
   171  			Context("when worker is stalled", func() {
   172  				var pruneErr error
   173  				BeforeEach(func() {
   174  					worker, err := workerFactory.SaveWorker(atc.Worker{
   175  						Name:       "worker-to-prune",
   176  						GardenAddr: "1.2.3.4",
   177  						State:      "running",
   178  					}, -5*time.Minute)
   179  					Expect(err).NotTo(HaveOccurred())
   180  
   181  					_, err = workerLifecycle.StallUnresponsiveWorkers()
   182  					Expect(err).NotTo(HaveOccurred())
   183  					pruneErr = worker.Prune()
   184  				})
   185  
   186  				It("does not return error", func() {
   187  					Expect(pruneErr).NotTo(HaveOccurred())
   188  				})
   189  			})
   190  		})
   191  
   192  		Context("when worker does not exist", func() {
   193  			BeforeEach(func() {
   194  				var err error
   195  				worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
   196  				Expect(err).NotTo(HaveOccurred())
   197  				err = worker.Delete()
   198  				Expect(err).NotTo(HaveOccurred())
   199  			})
   200  
   201  			It("raises ErrWorkerNotPresent", func() {
   202  				err := worker.Prune()
   203  				Expect(err).To(Equal(ErrWorkerNotPresent))
   204  			})
   205  		})
   206  	})
   207  
   208  	Describe("FindContainer/CreateContainer", func() {
   209  		var (
   210  			containerMetadata ContainerMetadata
   211  			containerOwner    ContainerOwner
   212  
   213  			foundCreatingContainer CreatingContainer
   214  			foundCreatedContainer  CreatedContainer
   215  			worker                 Worker
   216  		)
   217  
   218  		expiries := ContainerOwnerExpiries{
   219  			Min: 5 * time.Minute,
   220  			Max: 1 * time.Hour,
   221  		}
   222  
   223  		BeforeEach(func() {
   224  			containerMetadata = ContainerMetadata{
   225  				Type: "check",
   226  			}
   227  
   228  			var err error
   229  			worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
   230  			Expect(err).NotTo(HaveOccurred())
   231  
   232  			atcWorker2 := atcWorker
   233  			atcWorker2.Name = "some-name2"
   234  			atcWorker2.GardenAddr = "some-garden-addr-other"
   235  			otherWorker, err = workerFactory.SaveWorker(atcWorker2, 5*time.Minute)
   236  			Expect(err).NotTo(HaveOccurred())
   237  
   238  			resourceConfig, err := resourceConfigFactory.FindOrCreateResourceConfig(
   239  				"some-resource-type",
   240  				atc.Source{"some": "source"},
   241  				atc.VersionedResourceTypes{},
   242  			)
   243  			Expect(err).ToNot(HaveOccurred())
   244  
   245  			containerOwner = NewResourceConfigCheckSessionContainerOwner(
   246  				resourceConfig.ID(),
   247  				resourceConfig.OriginBaseResourceType().ID,
   248  				expiries,
   249  			)
   250  		})
   251  
   252  		JustBeforeEach(func() {
   253  			var err error
   254  			foundCreatingContainer, foundCreatedContainer, err = worker.FindContainer(containerOwner)
   255  			Expect(err).ToNot(HaveOccurred())
   256  		})
   257  
   258  		Context("when there is a creating container", func() {
   259  			var creatingContainer CreatingContainer
   260  
   261  			BeforeEach(func() {
   262  				var err error
   263  				creatingContainer, err = worker.CreateContainer(containerOwner, containerMetadata)
   264  				Expect(err).ToNot(HaveOccurred())
   265  			})
   266  
   267  			It("returns it", func() {
   268  				Expect(foundCreatedContainer).To(BeNil())
   269  				Expect(foundCreatingContainer).ToNot(BeNil())
   270  			})
   271  
   272  			Context("when finding on another worker", func() {
   273  				BeforeEach(func() {
   274  					worker = otherWorker
   275  				})
   276  
   277  				It("does not find it", func() {
   278  					Expect(foundCreatingContainer).To(BeNil())
   279  					Expect(foundCreatedContainer).To(BeNil())
   280  				})
   281  			})
   282  
   283  			Context("when there is a created container", func() {
   284  				BeforeEach(func() {
   285  					_, err := creatingContainer.Created()
   286  					Expect(err).ToNot(HaveOccurred())
   287  				})
   288  
   289  				It("returns it", func() {
   290  					Expect(foundCreatedContainer).ToNot(BeNil())
   291  					Expect(foundCreatingContainer).To(BeNil())
   292  				})
   293  
   294  				Context("when finding on another worker", func() {
   295  					BeforeEach(func() {
   296  						worker = otherWorker
   297  					})
   298  
   299  					It("does not find it", func() {
   300  						Expect(foundCreatingContainer).To(BeNil())
   301  						Expect(foundCreatedContainer).To(BeNil())
   302  					})
   303  				})
   304  			})
   305  
   306  			Context("when the creating container is failed and gced", func() {
   307  				BeforeEach(func() {
   308  					var err error
   309  					_, err = creatingContainer.Failed()
   310  					Expect(err).ToNot(HaveOccurred())
   311  
   312  					containerRepository := NewContainerRepository(dbConn)
   313  					containersDestroyed, err := containerRepository.DestroyFailedContainers()
   314  					Expect(containersDestroyed).To(Equal(1))
   315  					Expect(err).ToNot(HaveOccurred())
   316  
   317  					var checkSessions int
   318  					err = dbConn.QueryRow("SELECT COUNT(*) FROM resource_config_check_sessions").Scan(&checkSessions)
   319  					Expect(err).ToNot(HaveOccurred())
   320  					Expect(checkSessions).To(Equal(1))
   321  				})
   322  
   323  				Context("and we create a new container", func() {
   324  					BeforeEach(func() {
   325  						_, err := worker.CreateContainer(containerOwner, containerMetadata)
   326  						Expect(err).ToNot(HaveOccurred())
   327  					})
   328  
   329  					It("does not duplicate the resource config check session", func() {
   330  						var checkSessions int
   331  						err := dbConn.QueryRow("SELECT COUNT(*) FROM resource_config_check_sessions").Scan(&checkSessions)
   332  						Expect(err).ToNot(HaveOccurred())
   333  						Expect(checkSessions).To(Equal(1))
   334  					})
   335  				})
   336  			})
   337  		})
   338  
   339  		Context("when there is no container", func() {
   340  			It("returns nil", func() {
   341  				Expect(foundCreatedContainer).To(BeNil())
   342  				Expect(foundCreatingContainer).To(BeNil())
   343  			})
   344  		})
   345  
   346  		Context("when the container has a meta type", func() {
   347  			var container CreatingContainer
   348  
   349  			Context("when the meta type is check", func() {
   350  				BeforeEach(func() {
   351  					containerMetadata = ContainerMetadata{
   352  						Type: "check",
   353  					}
   354  
   355  					var err error
   356  					container, err = worker.CreateContainer(containerOwner, containerMetadata)
   357  					Expect(err).ToNot(HaveOccurred())
   358  				})
   359  
   360  				It("returns a container with empty team id", func() {
   361  					var teamID sql.NullString
   362  
   363  					err := dbConn.QueryRow(fmt.Sprintf("SELECT team_id FROM containers WHERE id='%d'", container.ID())).Scan(&teamID)
   364  					Expect(err).ToNot(HaveOccurred())
   365  					Expect(teamID.Valid).To(BeFalse())
   366  				})
   367  			})
   368  
   369  			Context("when the meta type is not check", func() {
   370  				BeforeEach(func() {
   371  					containerMetadata = ContainerMetadata{
   372  						Type: "get",
   373  					}
   374  
   375  					oneOffBuild, err := defaultTeam.CreateOneOffBuild()
   376  					Expect(err).ToNot(HaveOccurred())
   377  
   378  					container, err = worker.CreateContainer(NewBuildStepContainerOwner(oneOffBuild.ID(), atc.PlanID("1"), 1), containerMetadata)
   379  					Expect(err).ToNot(HaveOccurred())
   380  				})
   381  
   382  				It("returns a container with a team id", func() {
   383  					var teamID sql.NullString
   384  
   385  					err := dbConn.QueryRow(fmt.Sprintf("SELECT team_id FROM containers WHERE id='%d'", container.ID())).Scan(&teamID)
   386  					Expect(err).ToNot(HaveOccurred())
   387  					Expect(teamID.Valid).To(BeTrue())
   388  				})
   389  			})
   390  		})
   391  	})
   392  
   393  	Describe("Active tasks", func() {
   394  		BeforeEach(func() {
   395  			var err error
   396  			worker, err = workerFactory.SaveWorker(atcWorker, 5*time.Minute)
   397  			Expect(err).NotTo(HaveOccurred())
   398  		})
   399  
   400  		Context("when the worker registers", func() {
   401  			It("has no active tasks", func() {
   402  				at, err := worker.ActiveTasks()
   403  				Expect(err).ToNot(HaveOccurred())
   404  				Expect(at).To(Equal(0))
   405  			})
   406  		})
   407  
   408  		Context("when the active task is increased", func() {
   409  			BeforeEach(func() {
   410  				err := worker.IncreaseActiveTasks()
   411  				Expect(err).ToNot(HaveOccurred())
   412  			})
   413  
   414  			It("increase the active tasks counter", func() {
   415  				at, err := worker.ActiveTasks()
   416  				Expect(err).ToNot(HaveOccurred())
   417  				Expect(at).To(Equal(1))
   418  			})
   419  			Context("when the active task is decreased", func() {
   420  				BeforeEach(func() {
   421  					err := worker.DecreaseActiveTasks()
   422  					Expect(err).ToNot(HaveOccurred())
   423  				})
   424  				It("reset the active tasks to 0", func() {
   425  					at, err := worker.ActiveTasks()
   426  					Expect(err).ToNot(HaveOccurred())
   427  					Expect(at).To(Equal(0))
   428  				})
   429  			})
   430  		})
   431  
   432  		Context("when the active task is decreased below 0", func() {
   433  			It("raise an error", func() {
   434  				err := worker.DecreaseActiveTasks()
   435  				Expect(err).To(HaveOccurred())
   436  			})
   437  		})
   438  	})
   439  })