1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
20 "git.arvados.org/arvados.git/sdk/go/arvados"
21 "git.arvados.org/arvados.git/sdk/go/arvadostest"
22 check "gopkg.in/check.v1"
25 type KeepstoreMigrationSuite struct {
26 hostname string // blank = use test system's hostname
27 ksByPort map[int]arvados.KeepService
30 var _ = check.Suite(&KeepstoreMigrationSuite{})
32 func (s *KeepstoreMigrationSuite) SetUpSuite(c *check.C) {
33 os.Setenv("ARVADOS_API_HOST", os.Getenv("ARVADOS_TEST_API_HOST"))
34 os.Setenv("ARVADOS_API_HOST_INSECURE", "1")
35 os.Setenv("ARVADOS_API_TOKEN", arvadostest.AdminToken)
37 // We don't need the keepstore servers, but we do need
38 // keep_services listings that point to localhost, rather than
39 // the apiserver fixtures that point to fictional hosts
40 // keep*.zzzzz.arvadosapi.com.
42 client := arvados.NewClientFromEnv()
44 // Delete existing non-proxy listings.
45 var svcList arvados.KeepServiceList
46 err := client.RequestAndDecode(&svcList, "GET", "arvados/v1/keep_services", nil, nil)
47 c.Assert(err, check.IsNil)
48 for _, ks := range svcList.Items {
49 if ks.ServiceType != "proxy" {
50 err = client.RequestAndDecode(new(struct{}), "DELETE", "arvados/v1/keep_services/"+ks.UUID, nil, nil)
51 c.Assert(err, check.IsNil)
54 // Add new fake listings.
55 s.ksByPort = map[int]arvados.KeepService{}
56 for _, port := range []int{25107, 25108} {
57 var ks arvados.KeepService
58 err = client.RequestAndDecode(&ks, "POST", "arvados/v1/keep_services", nil, map[string]interface{}{
59 "keep_service": map[string]interface{}{
60 "service_type": "disk",
61 "service_host": "localhost",
65 c.Assert(err, check.IsNil)
70 func (s *KeepstoreMigrationSuite) checkEquivalentWithKeepstoreConfig(c *check.C, keepstoreconfig, clusterconfig, expectedconfig string) {
71 keepstorefile, err := ioutil.TempFile("", "")
72 c.Assert(err, check.IsNil)
73 defer os.Remove(keepstorefile.Name())
74 _, err = io.WriteString(keepstorefile, keepstoreconfig)
75 c.Assert(err, check.IsNil)
76 err = keepstorefile.Close()
77 c.Assert(err, check.IsNil)
79 gotldr := testLoader(c, clusterconfig, nil)
80 gotldr.KeepstorePath = keepstorefile.Name()
81 expectedldr := testLoader(c, expectedconfig, nil)
82 checkEquivalentLoaders(c, gotldr, expectedldr)
85 func (s *KeepstoreMigrationSuite) TestDeprecatedKeepstoreConfig(c *check.C) {
86 keyfile, err := ioutil.TempFile("", "")
87 c.Assert(err, check.IsNil)
88 defer os.Remove(keyfile.Name())
89 io.WriteString(keyfile, "blobsigningkey\n")
91 hostname, err := os.Hostname()
92 c.Assert(err, check.IsNil)
94 s.checkEquivalentWithKeepstoreConfig(c, `
100 BlobSignatureTTL: 123m
101 BlobSigningKeyFile: `+keyfile.Name()+`
108 SystemRootToken: `+arvadostest.AdminToken+`
109 TLS: {Insecure: true}
112 ExternalURL: "https://`+os.Getenv("ARVADOS_API_HOST")+`/"
116 SystemRootToken: `+arvadostest.AdminToken+`
117 TLS: {Insecure: true}
121 "http://`+hostname+`:25107": {Rendezvous: `+s.ksByPort[25107].UUID[12:]+`}
123 ExternalURL: "https://`+os.Getenv("ARVADOS_API_HOST")+`/"
128 MaxKeepBlobBuffers: 1234
129 MaxConcurrentRequests: 2345
132 BlobSigningKey: blobsigningkey
134 z1111-nyw5e-`+s.ksByPort[25107].UUID[12:]+`:
136 "http://`+hostname+`:25107":
148 func (s *KeepstoreMigrationSuite) TestDiscoverLocalVolumes(c *check.C) {
149 tmpd, err := ioutil.TempDir("", "")
150 c.Assert(err, check.IsNil)
151 defer os.RemoveAll(tmpd)
152 err = os.Mkdir(tmpd+"/keep", 0777)
153 c.Assert(err, check.IsNil)
155 tmpf, err := ioutil.TempFile("", "")
156 c.Assert(err, check.IsNil)
157 defer os.Remove(tmpf.Name())
160 _, err = fmt.Fprintf(tmpf, "/dev/xvdb %s ext4 rw,noexec 0 0\n", tmpd)
161 c.Assert(err, check.IsNil)
163 s.testDeprecatedVolume(c, "DiscoverVolumesFromMountsFile: "+tmpf.Name(), arvados.Volume{
167 }, &arvados.DirectoryVolumeDriverParameters{
168 Root: tmpd + "/keep",
170 }, &arvados.DirectoryVolumeDriverParameters{})
173 tmpf.Seek(0, os.SEEK_SET)
175 _, err = fmt.Fprintf(tmpf, "/dev/xvdb %s ext4 ro,noexec 0 0\n", tmpd)
176 c.Assert(err, check.IsNil)
178 s.testDeprecatedVolume(c, "DiscoverVolumesFromMountsFile: "+tmpf.Name(), arvados.Volume{
182 }, &arvados.DirectoryVolumeDriverParameters{
183 Root: tmpd + "/keep",
185 }, &arvados.DirectoryVolumeDriverParameters{})
188 func (s *KeepstoreMigrationSuite) TestDeprecatedVolumes(c *check.C) {
189 accesskeyfile, err := ioutil.TempFile("", "")
190 c.Assert(err, check.IsNil)
191 defer os.Remove(accesskeyfile.Name())
192 io.WriteString(accesskeyfile, "accesskeydata\n")
194 secretkeyfile, err := ioutil.TempFile("", "")
195 c.Assert(err, check.IsNil)
196 defer os.Remove(secretkeyfile.Name())
197 io.WriteString(secretkeyfile, "secretkeydata\n")
200 s.testDeprecatedVolume(c, `
206 }, &arvados.S3VolumeDriverParameters{}, &arvados.S3VolumeDriverParameters{})
208 // s3, fully configured
209 s.testDeprecatedVolume(c, `
212 AccessKeyFile: `+accesskeyfile.Name()+`
213 SecretKeyFile: `+secretkeyfile.Name()+`
214 Endpoint: https://storage.googleapis.com
217 LocationConstraint: true
227 }, &arvados.S3VolumeDriverParameters{
228 AccessKeyID: "accesskeydata",
229 SecretAccessKey: "secretkeydata",
230 Endpoint: "https://storage.googleapis.com",
231 Region: "us-east-1z",
232 Bucket: "testbucket",
233 LocationConstraint: true,
235 ConnectTimeout: arvados.Duration(time.Minute * 3),
236 ReadTimeout: arvados.Duration(time.Minute * 4),
237 RaceWindow: arvados.Duration(time.Minute * 5),
239 }, &arvados.S3VolumeDriverParameters{})
241 // azure, empty/default
242 s.testDeprecatedVolume(c, `
248 }, &arvados.AzureVolumeDriverParameters{}, &arvados.AzureVolumeDriverParameters{})
250 // azure, fully configured
251 s.testDeprecatedVolume(c, `
255 StorageAccountName: storageacctname
256 StorageAccountKeyFile: `+secretkeyfile.Name()+`
257 StorageBaseURL: https://example.example/
258 ContainerName: testctr
259 LocationConstraint: true
262 ListBlobsRetryDelay: 4m
263 ListBlobsMaxAttempts: 5
268 }, &arvados.AzureVolumeDriverParameters{
269 StorageAccountName: "storageacctname",
270 StorageAccountKey: "secretkeydata",
271 StorageBaseURL: "https://example.example/",
272 ContainerName: "testctr",
273 RequestTimeout: arvados.Duration(time.Minute * 3),
274 ListBlobsRetryDelay: arvados.Duration(time.Minute * 4),
275 ListBlobsMaxAttempts: 5,
276 }, &arvados.AzureVolumeDriverParameters{})
278 // directory, empty/default
279 s.testDeprecatedVolume(c, `
286 }, &arvados.DirectoryVolumeDriverParameters{
288 }, &arvados.DirectoryVolumeDriverParameters{})
290 // directory, fully configured
291 s.testDeprecatedVolume(c, `
296 DirectoryReplication: 4
302 }, &arvados.DirectoryVolumeDriverParameters{
305 }, &arvados.DirectoryVolumeDriverParameters{})
308 func (s *KeepstoreMigrationSuite) testDeprecatedVolume(c *check.C, oldconfigdata string, expectvol arvados.Volume, expectparams interface{}, paramsdst interface{}) {
309 hostname := s.hostname
311 h, err := os.Hostname()
312 c.Assert(err, check.IsNil)
316 oldconfig, err := ioutil.TempFile("", "")
317 c.Assert(err, check.IsNil)
318 defer os.Remove(oldconfig.Name())
319 io.WriteString(oldconfig, "Listen: :12345\n"+oldconfigdata)
320 if !strings.Contains(oldconfigdata, "DiscoverVolumesFromMountsFile") {
321 // Prevent tests from looking at the real /proc/mounts on the test host.
322 io.WriteString(oldconfig, "\nDiscoverVolumesFromMountsFile: /dev/null\n")
325 ldr := testLoader(c, "Clusters: {z1111: {}}", nil)
326 ldr.KeepstorePath = oldconfig.Name()
327 cfg, err := ldr.Load()
328 c.Assert(err, check.IsNil)
329 cc := cfg.Clusters["z1111"]
330 c.Check(cc.Volumes, check.HasLen, 1)
331 for uuid, v := range cc.Volumes {
332 c.Check(uuid, check.HasLen, 27)
333 c.Check(v.Driver, check.Equals, expectvol.Driver)
334 c.Check(v.Replication, check.Equals, expectvol.Replication)
336 avh, ok := v.AccessViaHosts[arvados.URL{Scheme: "http", Host: hostname + ":12345", Path: "/"}]
337 c.Check(ok, check.Equals, true)
338 c.Check(avh.ReadOnly, check.Equals, expectvol.ReadOnly)
340 err := json.Unmarshal(v.DriverParameters, paramsdst)
341 c.Check(err, check.IsNil)
342 c.Check(paramsdst, check.DeepEquals, expectparams)
346 // How we handle a volume from a legacy keepstore config file depends
347 // on whether it's writable, whether a volume using the same cloud
348 // backend already exists in the cluster config, and (if so) whether
349 // it already has an AccessViaHosts entry for this host.
351 // In all cases, we should end up with an AccessViaHosts entry for
352 // this host, to indicate that the current host's volumes have been
355 // Same backend already referenced in cluster config, this host
356 // already listed in AccessViaHosts --> no change, except possibly
357 // updating the ReadOnly flag on the AccessViaHosts entry.
358 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AlreadyMigrated(c *check.C) {
359 before, after := s.loadWithKeepstoreConfig(c, `
363 Endpoint: https://storage.googleapis.com
365 Bucket: alreadymigrated
368 checkEqualYAML(c, after, before)
371 // Writable volume, same cloud backend already referenced in cluster
372 // config --> change UUID to match this keepstore's UUID.
373 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateUUID(c *check.C) {
374 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
376 before, after := s.loadWithKeepstoreConfig(c, `
377 Listen: :`+strconv.Itoa(port)+`
380 Endpoint: https://storage.googleapis.com
382 Bucket: readonlyonother
385 c.Check(after, check.HasLen, len(before))
386 newuuids := s.findAddedVolumes(c, before, after, 1)
387 newvol := after[newuuids[0]]
389 var params arvados.S3VolumeDriverParameters
390 json.Unmarshal(newvol.DriverParameters, ¶ms)
391 c.Check(params.Bucket, check.Equals, "readonlyonother")
392 c.Check(newuuids[0], check.Equals, expectUUID)
395 // Writable volume, same cloud backend not yet referenced --> add a
396 // new volume, with UUID to match this keepstore's UUID.
397 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddCloudVolume(c *check.C) {
398 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
400 before, after := s.loadWithKeepstoreConfig(c, `
401 Listen: :`+strconv.Itoa(port)+`
404 Endpoint: https://storage.googleapis.com
406 Bucket: bucket-to-migrate
409 newuuids := s.findAddedVolumes(c, before, after, 1)
410 newvol := after[newuuids[0]]
412 var params arvados.S3VolumeDriverParameters
413 json.Unmarshal(newvol.DriverParameters, ¶ms)
414 c.Check(params.Bucket, check.Equals, "bucket-to-migrate")
415 c.Check(newvol.Replication, check.Equals, 3)
417 c.Check(newuuids[0], check.Equals, expectUUID)
420 // Writable volume, same filesystem backend already referenced in
421 // cluster config, but this host isn't in AccessViaHosts --> add a new
422 // volume, with UUID to match this keepstore's UUID (filesystem-backed
423 // volumes are assumed to be different on different hosts, even if
424 // paths are the same).
425 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddLocalVolume(c *check.C) {
426 before, after := s.loadWithKeepstoreConfig(c, `
431 DirectoryReplication: 2
433 newuuids := s.findAddedVolumes(c, before, after, 1)
434 newvol := after[newuuids[0]]
436 var params arvados.DirectoryVolumeDriverParameters
437 json.Unmarshal(newvol.DriverParameters, ¶ms)
438 c.Check(params.Root, check.Equals, "/data/sdd")
439 c.Check(newvol.Replication, check.Equals, 2)
442 // Writable volume, same filesystem backend already referenced in
443 // cluster config, and this host is already listed in AccessViaHosts
444 // --> already migrated, don't change anything.
445 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_LocalVolumeAlreadyMigrated(c *check.C) {
446 before, after := s.loadWithKeepstoreConfig(c, `
451 DirectoryReplication: 2
453 checkEqualYAML(c, after, before)
456 // Multiple writable cloud-backed volumes --> one of them will get a
457 // UUID matching this keepstore's UUID.
458 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddMultipleCloudVolumes(c *check.C) {
459 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
461 before, after := s.loadWithKeepstoreConfig(c, `
462 Listen: :`+strconv.Itoa(port)+`
465 Endpoint: https://storage.googleapis.com
467 Bucket: first-bucket-to-migrate
470 Endpoint: https://storage.googleapis.com
472 Bucket: second-bucket-to-migrate
475 newuuids := s.findAddedVolumes(c, before, after, 2)
476 // Sort by bucket name (so "first" comes before "second")
477 params := map[string]arvados.S3VolumeDriverParameters{}
478 for _, uuid := range newuuids {
479 var p arvados.S3VolumeDriverParameters
480 json.Unmarshal(after[uuid].DriverParameters, &p)
483 sort.Slice(newuuids, func(i, j int) bool { return params[newuuids[i]].Bucket < params[newuuids[j]].Bucket })
484 newvol0, newvol1 := after[newuuids[0]], after[newuuids[1]]
485 params0, params1 := params[newuuids[0]], params[newuuids[1]]
487 c.Check(params0.Bucket, check.Equals, "first-bucket-to-migrate")
488 c.Check(newvol0.Replication, check.Equals, 3)
490 c.Check(params1.Bucket, check.Equals, "second-bucket-to-migrate")
491 c.Check(newvol1.Replication, check.Equals, 3)
493 // Don't care which one gets the special UUID
494 if newuuids[0] != expectUUID {
495 c.Check(newuuids[1], check.Equals, expectUUID)
499 // Non-writable volume, same cloud backend already referenced in
500 // cluster config --> add this host to AccessViaHosts with
502 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateWithReadOnly(c *check.C) {
503 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
504 before, after := s.loadWithKeepstoreConfig(c, `
505 Listen: :`+strconv.Itoa(port)+`
508 Endpoint: https://storage.googleapis.com
510 Bucket: readonlyonother
514 hostname, err := os.Hostname()
515 c.Assert(err, check.IsNil)
518 Host: fmt.Sprintf("%s:%d", hostname, port),
521 _, ok := before["zzzzz-nyw5e-readonlyonother"].AccessViaHosts[url]
522 c.Check(ok, check.Equals, false)
523 _, ok = after["zzzzz-nyw5e-readonlyonother"].AccessViaHosts[url]
524 c.Check(ok, check.Equals, true)
527 // Writable volume, same cloud backend already writable by another
528 // keepstore server --> add this host to AccessViaHosts with
530 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateAlreadyWritable(c *check.C) {
531 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
532 before, after := s.loadWithKeepstoreConfig(c, `
533 Listen: :`+strconv.Itoa(port)+`
536 Endpoint: https://storage.googleapis.com
538 Bucket: writableonother
542 hostname, err := os.Hostname()
543 c.Assert(err, check.IsNil)
546 Host: fmt.Sprintf("%s:%d", hostname, port),
549 _, ok := before["zzzzz-nyw5e-writableonother"].AccessViaHosts[url]
550 c.Check(ok, check.Equals, false)
551 _, ok = after["zzzzz-nyw5e-writableonother"].AccessViaHosts[url]
552 c.Check(ok, check.Equals, true)
555 // Non-writable volume, same cloud backend not already referenced in
556 // cluster config --> assign a new random volume UUID.
557 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddReadOnly(c *check.C) {
558 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
559 before, after := s.loadWithKeepstoreConfig(c, `
560 Listen: :`+strconv.Itoa(port)+`
563 Endpoint: https://storage.googleapis.com
565 Bucket: differentbucket
568 newuuids := s.findAddedVolumes(c, before, after, 1)
569 newvol := after[newuuids[0]]
571 var params arvados.S3VolumeDriverParameters
572 json.Unmarshal(newvol.DriverParameters, ¶ms)
573 c.Check(params.Bucket, check.Equals, "differentbucket")
575 hostname, err := os.Hostname()
576 c.Assert(err, check.IsNil)
577 _, ok := newvol.AccessViaHosts[arvados.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", hostname, port), Path: "/"}]
578 c.Check(ok, check.Equals, true)
581 // Ensure logs mention unmigrated servers.
582 func (s *KeepstoreMigrationSuite) TestPendingKeepstoreMigrations(c *check.C) {
583 client := arvados.NewClientFromEnv()
584 for _, host := range []string{"keep0", "keep1"} {
585 err := client.RequestAndDecode(new(struct{}), "POST", "arvados/v1/keep_services", nil, map[string]interface{}{
586 "keep_service": map[string]interface{}{
587 "service_type": "disk",
588 "service_host": host + ".zzzzz.example.com",
589 "service_port": 25107,
592 c.Assert(err, check.IsNil)
595 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
596 logs := s.logsWithKeepstoreConfig(c, `
597 Listen: :`+strconv.Itoa(port)+`
600 Endpoint: https://storage.googleapis.com
603 c.Check(logs, check.Matches, `(?ms).*you should remove the legacy keepstore config file.*`)
604 c.Check(logs, check.Matches, `(?ms).*you should migrate the legacy keepstore configuration file on host keep1.zzzzz.example.com.*`)
605 c.Check(logs, check.Not(check.Matches), `(?ms).*should migrate.*keep0.zzzzz.example.com.*`)
606 c.Check(logs, check.Matches, `(?ms).*keepstore configured at http://keep2.zzzzz.example.com:25107/ does not have access to any volumes.*`)
607 c.Check(logs, check.Matches, `(?ms).*Volumes.zzzzz-nyw5e-possconfigerror.AccessViaHosts refers to nonexistent keepstore server http://keep00.zzzzz.example.com:25107.*`)
610 const clusterConfigForKeepstoreMigrationTest = `
613 SystemRootToken: ` + arvadostest.AdminToken + `
617 "http://{{.hostname}}:12345": {}
618 "http://keep0.zzzzz.example.com:25107": {}
619 "http://keep2.zzzzz.example.com:25107": {}
621 ExternalURL: "https://{{.controller}}"
626 zzzzz-nyw5e-alreadymigrated:
628 "http://{{.hostname}}:12345": {}
631 Endpoint: https://storage.googleapis.com
633 Bucket: alreadymigrated
636 zzzzz-nyw5e-readonlyonother:
638 "http://keep0.zzzzz.example.com:25107": {ReadOnly: true}
641 Endpoint: https://storage.googleapis.com
643 Bucket: readonlyonother
646 zzzzz-nyw5e-writableonother:
648 "http://keep0.zzzzz.example.com:25107": {}
651 Endpoint: https://storage.googleapis.com
653 Bucket: writableonother
656 zzzzz-nyw5e-localfilesystem:
658 "http://keep0.zzzzz.example.com:25107": {}
664 zzzzz-nyw5e-localismigrated:
666 "http://{{.hostname}}:12345": {}
672 zzzzz-nyw5e-possconfigerror:
674 "http://keep00.zzzzz.example.com:25107": {}
681 // Determine the effect of combining the given legacy keepstore config
682 // YAML (just the "Volumes" entries of an old keepstore config file)
683 // with the example clusterConfigForKeepstoreMigrationTest config.
685 // Return two Volumes configs -- one without loading keepstoreYAML
686 // ("before") and one with ("after") -- for the caller to compare.
687 func (s *KeepstoreMigrationSuite) loadWithKeepstoreConfig(c *check.C, keepstoreYAML string) (before, after map[string]arvados.Volume) {
688 ldr := testLoader(c, s.clusterConfigYAML(c), nil)
689 cBefore, err := ldr.Load()
690 c.Assert(err, check.IsNil)
692 keepstoreconfig, err := ioutil.TempFile("", "")
693 c.Assert(err, check.IsNil)
694 defer os.Remove(keepstoreconfig.Name())
695 io.WriteString(keepstoreconfig, keepstoreYAML)
697 ldr = testLoader(c, s.clusterConfigYAML(c), nil)
698 ldr.KeepstorePath = keepstoreconfig.Name()
699 cAfter, err := ldr.Load()
700 c.Assert(err, check.IsNil)
702 return cBefore.Clusters["zzzzz"].Volumes, cAfter.Clusters["zzzzz"].Volumes
705 // Return the log messages emitted when loading keepstoreYAML along
706 // with clusterConfigForKeepstoreMigrationTest.
707 func (s *KeepstoreMigrationSuite) logsWithKeepstoreConfig(c *check.C, keepstoreYAML string) string {
708 var logs bytes.Buffer
710 keepstoreconfig, err := ioutil.TempFile("", "")
711 c.Assert(err, check.IsNil)
712 defer os.Remove(keepstoreconfig.Name())
713 io.WriteString(keepstoreconfig, keepstoreYAML)
715 ldr := testLoader(c, s.clusterConfigYAML(c), &logs)
716 ldr.KeepstorePath = keepstoreconfig.Name()
718 c.Assert(err, check.IsNil)
723 func (s *KeepstoreMigrationSuite) clusterConfigYAML(c *check.C) string {
724 hostname, err := os.Hostname()
725 c.Assert(err, check.IsNil)
727 tmpl := template.Must(template.New("config").Parse(clusterConfigForKeepstoreMigrationTest))
729 var clusterconfigdata bytes.Buffer
730 err = tmpl.Execute(&clusterconfigdata, map[string]interface{}{
731 "hostname": hostname,
732 "controller": os.Getenv("ARVADOS_API_HOST"),
734 c.Assert(err, check.IsNil)
736 return clusterconfigdata.String()
739 // Return the uuids of volumes that appear in "after" but not
742 // Assert the returned slice has at least minAdded entries.
743 func (s *KeepstoreMigrationSuite) findAddedVolumes(c *check.C, before, after map[string]arvados.Volume, minAdded int) (uuids []string) {
744 for uuid := range after {
745 if _, ok := before[uuid]; !ok {
746 uuids = append(uuids, uuid)
749 if len(uuids) < minAdded {
750 c.Assert(uuids, check.HasLen, minAdded)
755 func (s *KeepstoreMigrationSuite) getTestKeepstorePortAndMatchingVolumeUUID(c *check.C) (int, string) {
756 for port, ks := range s.ksByPort {
757 c.Assert(ks.UUID, check.HasLen, 27)
758 return port, "zzzzz-nyw5e-" + ks.UUID[12:]
760 c.Fatal("s.ksByPort is empty")
764 func (s *KeepstoreMigrationSuite) TestKeepServiceIsMe(c *check.C) {
765 for i, trial := range []struct {
772 {true, "keep0", "keep0", "keep0", 80},
773 {true, "keep0", "[::1]:http", "keep0", 80},
774 {true, "keep0", "[::]:http", "keep0", 80},
775 {true, "keep0", "keep0:25107", "keep0", 25107},
776 {true, "keep0", ":25107", "keep0", 25107},
777 {true, "keep0.domain", ":25107", "keep0.domain.example", 25107},
778 {true, "keep0.domain.example", ":25107", "keep0.domain.example", 25107},
779 {true, "keep0", ":25107", "keep0.domain.example", 25107},
780 {true, "keep0", ":25107", "Keep0.domain.example", 25107},
781 {true, "keep0", ":http", "keep0.domain.example", 80},
782 {true, "keep0", ":25107", "localhost", 25107},
783 {true, "keep0", ":25107", "::1", 25107},
784 {false, "keep0", ":25107", "keep0", 1111}, // different port
785 {false, "keep0", ":25107", "localhost", 1111}, // different port
786 {false, "keep0", ":http", "keep0.domain.example", 443}, // different port
787 {false, "keep0", ":bogussss", "keep0", 25107}, // unresolvable port
788 {false, "keep0", ":25107", "keep1", 25107}, // different hostname
789 {false, "keep1", ":25107", "keep10", 25107}, // different hostname (prefix, but not on a "." boundary)
791 c.Check(keepServiceIsMe(arvados.KeepService{ServiceHost: trial.serviceHost, ServicePort: trial.servicePort}, trial.hostname, trial.listen), check.Equals, trial.match, check.Commentf("trial #%d: %#v", i, trial))