github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/topgun/both/worker_landing_test.go (about) 1 package topgun_test 2 3 import ( 4 "os" 5 "regexp" 6 "strings" 7 "time" 8 9 . "github.com/pf-qiu/concourse/v6/topgun/common" 10 _ "github.com/lib/pq" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 "github.com/onsi/gomega/gbytes" 14 "github.com/onsi/gomega/gexec" 15 ) 16 17 var _ = Describe("Worker landing", func() { 18 landWorker := func() (string, BoshInstance) { 19 workerToLand := FlyTable("workers")[0]["name"] 20 21 // the bosh release ensures the first guid segment matches the first guid 22 // segment of the instance ID, so that they can be correlated 23 guidSegments := strings.Split(workerToLand, "-") 24 prefix := guidSegments[0] 25 26 var instance BoshInstance 27 for _, i := range JobInstances("worker") { 28 if strings.HasPrefix(i.ID, prefix) { 29 instance = i 30 break 31 } 32 } 33 34 Expect(instance.ID).ToNot(BeEmpty(), "should have found a corresponding bosh instance") 35 36 // unmonitor worker, otherwise monit will just restart it once it's landed 37 Bosh("ssh", instance.Name, "-c", "sudo /var/vcap/bosh/bin/monit unmonitor worker") 38 39 // land worker via fly; this will cause the worker process to exit 40 Fly.Run("land-worker", "-w", workerToLand) 41 42 return workerToLand, instance 43 } 44 45 startLandedWorker := func(instance BoshInstance) { 46 Bosh("ssh", instance.Name, "-c", "sudo /var/vcap/bosh/bin/monit monitor worker") 47 Bosh("ssh", instance.Name, "-c", "sudo /var/vcap/bosh/bin/monit start worker") 48 } 49 50 Context("with two workers available", func() { 51 BeforeEach(func() { 52 Deploy( 53 "deployments/concourse.yml", 54 "-o", "operations/worker-instances.yml", 55 "-v", "worker_instances=2", 56 ) 57 }) 58 59 Describe("landing the worker", func() { 60 var landingWorkerName string 61 var landingWorkerInstance BoshInstance 62 63 JustBeforeEach(func() { 64 landingWorkerName, landingWorkerInstance = landWorker() 65 }) 66 67 AfterEach(func() { 68 startLandedWorker(landingWorkerInstance) 69 }) 70 71 Context("while in landing or landed state", func() { 72 It("is not used for new workloads", func() { 73 for i := 0; i < 10; i++ { 74 Fly.Run("execute", "-c", "tasks/tiny.yml") 75 usedWorkers := WorkersWithContainers() 76 Expect(usedWorkers).To(HaveLen(1)) 77 Expect(usedWorkers).ToNot(ContainElement(landingWorkerName)) 78 } 79 }) 80 81 It("can be pruned", func() { 82 Fly.Run("prune-worker", "-w", landingWorkerName) 83 WaitForWorkersToBeRunning(1) 84 }) 85 }) 86 }) 87 }) 88 89 describeLandingTheWorker := func() { 90 Describe("landing the worker", func() { 91 var landingWorkerName string 92 var landingWorkerInstance BoshInstance 93 94 JustBeforeEach(func() { 95 landingWorkerName, landingWorkerInstance = landWorker() 96 }) 97 98 AfterEach(func() { 99 startLandedWorker(landingWorkerInstance) 100 }) 101 102 Context("with volumes and containers present", func() { 103 var preservedContainerID string 104 105 BeforeEach(func() { 106 By("setting pipeline that creates volumes for image") 107 Fly.Run("set-pipeline", "-n", "-c", "pipelines/get-task.yml", "-p", "topgun") 108 109 By("unpausing the pipeline") 110 Fly.Run("unpause-pipeline", "-p", "topgun") 111 112 By("triggering a job") 113 buildSession := Fly.Start("trigger-job", "-w", "-j", "topgun/simple-job") 114 Eventually(buildSession).Should(gbytes.Say("mirroring self image")) 115 <-buildSession.Exited 116 Expect(buildSession.ExitCode()).To(Equal(0)) 117 118 By("getting identifier for check container") 119 hijackSession := Fly.Start("hijack", "-c", "topgun/tick-tock", "--", "hostname") 120 <-hijackSession.Exited 121 Expect(buildSession.ExitCode()).To(Equal(0)) 122 123 preservedContainerID = string(hijackSession.Out.Contents()) 124 }) 125 126 It("keeps volumes and containers after restart", func() { 127 By("starting the worker back up") 128 WaitForLandedWorker() 129 startLandedWorker(landingWorkerInstance) 130 WaitForWorkersToBeRunning(1) 131 132 By("retaining cached image resource in second job build") 133 buildSession := Fly.Start("trigger-job", "-w", "-j", "topgun/simple-job") 134 <-buildSession.Exited 135 Expect(buildSession).NotTo(gbytes.Say("mirroring self image")) 136 Expect(buildSession.ExitCode()).To(Equal(0)) 137 138 By("retaining check containers") 139 hijackSession := Fly.Start("hijack", "-c", "topgun/tick-tock", "--", "hostname") 140 <-hijackSession.Exited 141 Expect(buildSession.ExitCode()).To(Equal(0)) 142 143 currentContainerID := string(hijackSession.Out.Contents()) 144 Expect(currentContainerID).To(Equal(preservedContainerID)) 145 }) 146 }) 147 148 Context("with an interruptible build in-flight", func() { 149 var buildSession *gexec.Session 150 151 BeforeEach(func() { 152 By("setting pipeline that has an infinite but interruptible job") 153 Fly.Run("set-pipeline", "-n", "-c", "pipelines/interruptible.yml", "-p", "topgun") 154 155 By("unpausing the pipeline") 156 Fly.Run("unpause-pipeline", "-p", "topgun") 157 158 By("triggering a job") 159 buildSession = Fly.Start("trigger-job", "-w", "-j", "topgun/interruptible-job") 160 Eventually(buildSession).Should(gbytes.Say("waiting forever")) 161 }) 162 163 It("does not wait for the build", func() { 164 By("landing without the drain timeout kicking in") 165 WaitForLandedWorker() 166 }) 167 }) 168 169 Context("with uninterruptible build in-flight", func() { 170 var buildSession *gexec.Session 171 var buildID string 172 173 BeforeEach(func() { 174 buildSession = Fly.Start("execute", "-c", "tasks/wait.yml") 175 Eventually(buildSession).Should(gbytes.Say("executing build")) 176 177 buildRegex := regexp.MustCompile(`executing build (\d+)`) 178 matches := buildRegex.FindSubmatch(buildSession.Out.Contents()) 179 buildID = string(matches[1]) 180 181 Eventually(buildSession).Should(gbytes.Say("waiting for /tmp/stop-waiting")) 182 }) 183 184 AfterEach(func() { 185 buildSession.Signal(os.Interrupt) 186 <-buildSession.Exited 187 }) 188 189 It("waits for the build", func() { 190 Consistently(func() string { 191 return WorkerState(landingWorkerName) 192 }, 5*time.Minute).Should(Equal("landing")) 193 }) 194 195 It("finishes landing once the build is done", func() { 196 By("hijacking the build to tell it to finish") 197 Eventually(func() int { 198 hijackSession := Fly.Start( 199 "hijack", 200 "-b", buildID, 201 "-s", "one-off", "--", 202 "touch", "/tmp/stop-waiting", 203 ) 204 <-hijackSession.Exited 205 return hijackSession.ExitCode() 206 }).Should(Equal(0)) 207 208 By("waiting for the build to exit") 209 Eventually(buildSession).Should(gbytes.Say("done")) 210 <-buildSession.Exited 211 Expect(buildSession.ExitCode()).To(Equal(0)) 212 213 By("successfully landing") 214 WaitForLandedWorker() 215 }) 216 }) 217 }) 218 } 219 220 Context("with one worker", func() { 221 BeforeEach(func() { 222 Deploy("deployments/concourse.yml") 223 WaitForRunningWorker() 224 }) 225 226 describeLandingTheWorker() 227 }) 228 229 //TODO: Un-pend this Context when team workers can run check containers 230 // see: - https://github.com/pf-qiu/concourse/v6/issues/2910 231 // - https://github.com/pf-qiu/concourse/v6/issues/2951 232 XContext("with a single team worker", func() { 233 BeforeEach(func() { 234 Deploy( 235 "deployments/concourse.yml", 236 "-o", "operations/worker-instances.yml", 237 "-v", "worker_instances=0", 238 ) 239 240 Fly.Run("set-team", "--non-interactive", "-n", "team-a", "--local-user", AtcUsername) 241 242 Deploy( 243 "deployments/concourse.yml", 244 "-o", "operations/worker-team.yml", 245 ) 246 247 Fly.Run("login", "-c", AtcExternalURL, "-n", "team-a", "-u", AtcUsername, "-p", AtcPassword) 248 249 // wait for the team's worker to arrive now that team exists 250 WaitForRunningWorker() 251 }) 252 253 describeLandingTheWorker() 254 }) 255 })