1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
20 "git.curoverse.com/arvados.git/sdk/go/arvados"
21 "git.curoverse.com/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 // We don't need the keepstore servers, but we do need
34 // keep_services listings that point to localhost, rather than
35 // the apiserver fixtures that point to fictional hosts
36 // keep*.zzzzz.arvadosapi.com.
38 client := arvados.NewClientFromEnv()
40 // Delete existing non-proxy listings.
41 var svcList arvados.KeepServiceList
42 err := client.RequestAndDecode(&svcList, "GET", "arvados/v1/keep_services", nil, nil)
43 c.Assert(err, check.IsNil)
44 for _, ks := range svcList.Items {
45 if ks.ServiceType != "proxy" {
46 err = client.RequestAndDecode(new(struct{}), "DELETE", "arvados/v1/keep_services/"+ks.UUID, nil, nil)
47 c.Assert(err, check.IsNil)
50 // Add new fake listings.
51 s.ksByPort = map[int]arvados.KeepService{}
52 for _, port := range []int{25107, 25108} {
53 var ks arvados.KeepService
54 err = client.RequestAndDecode(&ks, "POST", "arvados/v1/keep_services", nil, map[string]interface{}{
55 "keep_service": map[string]interface{}{
56 "service_type": "disk",
57 "service_host": "localhost",
61 c.Assert(err, check.IsNil)
66 func (s *KeepstoreMigrationSuite) checkEquivalentWithKeepstoreConfig(c *check.C, keepstoreconfig, clusterconfig, expectedconfig string) {
67 keepstorefile, err := ioutil.TempFile("", "")
68 c.Assert(err, check.IsNil)
69 defer os.Remove(keepstorefile.Name())
70 _, err = io.WriteString(keepstorefile, keepstoreconfig)
71 c.Assert(err, check.IsNil)
72 err = keepstorefile.Close()
73 c.Assert(err, check.IsNil)
75 gotldr := testLoader(c, clusterconfig, nil)
76 gotldr.KeepstorePath = keepstorefile.Name()
77 expectedldr := testLoader(c, expectedconfig, nil)
78 checkEquivalentLoaders(c, gotldr, expectedldr)
81 func (s *KeepstoreMigrationSuite) TestDeprecatedKeepstoreConfig(c *check.C) {
82 keyfile, err := ioutil.TempFile("", "")
83 c.Assert(err, check.IsNil)
84 defer os.Remove(keyfile.Name())
85 io.WriteString(keyfile, "blobsigningkey\n")
87 hostname, err := os.Hostname()
88 c.Assert(err, check.IsNil)
90 s.checkEquivalentWithKeepstoreConfig(c, `
96 BlobSignatureTTL: 123m
97 BlobSigningKeyFile: `+keyfile.Name()+`
104 SystemRootToken: `+arvadostest.AdminToken+`
105 TLS: {Insecure: true}
108 ExternalURL: "https://`+os.Getenv("ARVADOS_API_HOST")+`"
112 SystemRootToken: `+arvadostest.AdminToken+`
113 TLS: {Insecure: true}
117 "http://`+hostname+`:25107": {Rendezvous: `+s.ksByPort[25107].UUID[12:]+`}
119 ExternalURL: "https://`+os.Getenv("ARVADOS_API_HOST")+`"
124 MaxKeepBlobBuffers: 1234
125 MaxConcurrentRequests: 2345
128 BlobSigningKey: blobsigningkey
130 z1111-nyw5e-`+s.ksByPort[25107].UUID[12:]+`:
132 "http://`+hostname+`:25107":
144 func (s *KeepstoreMigrationSuite) TestDiscoverLocalVolumes(c *check.C) {
145 tmpd, err := ioutil.TempDir("", "")
146 c.Assert(err, check.IsNil)
147 defer os.RemoveAll(tmpd)
148 err = os.Mkdir(tmpd+"/keep", 0777)
149 c.Assert(err, check.IsNil)
151 tmpf, err := ioutil.TempFile("", "")
152 c.Assert(err, check.IsNil)
153 defer os.Remove(tmpf.Name())
156 _, err = fmt.Fprintf(tmpf, "/dev/xvdb %s ext4 rw,noexec 0 0\n", tmpd)
157 c.Assert(err, check.IsNil)
159 s.testDeprecatedVolume(c, "DiscoverVolumesFromMountsFile: "+tmpf.Name(), arvados.Volume{
163 }, &arvados.DirectoryVolumeDriverParameters{
164 Root: tmpd + "/keep",
166 }, &arvados.DirectoryVolumeDriverParameters{})
169 tmpf.Seek(0, os.SEEK_SET)
171 _, err = fmt.Fprintf(tmpf, "/dev/xvdb %s ext4 ro,noexec 0 0\n", tmpd)
172 c.Assert(err, check.IsNil)
174 s.testDeprecatedVolume(c, "DiscoverVolumesFromMountsFile: "+tmpf.Name(), arvados.Volume{
178 }, &arvados.DirectoryVolumeDriverParameters{
179 Root: tmpd + "/keep",
181 }, &arvados.DirectoryVolumeDriverParameters{})
184 func (s *KeepstoreMigrationSuite) TestDeprecatedVolumes(c *check.C) {
185 accesskeyfile, err := ioutil.TempFile("", "")
186 c.Assert(err, check.IsNil)
187 defer os.Remove(accesskeyfile.Name())
188 io.WriteString(accesskeyfile, "accesskeydata\n")
190 secretkeyfile, err := ioutil.TempFile("", "")
191 c.Assert(err, check.IsNil)
192 defer os.Remove(secretkeyfile.Name())
193 io.WriteString(secretkeyfile, "secretkeydata\n")
196 s.testDeprecatedVolume(c, `
202 }, &arvados.S3VolumeDriverParameters{}, &arvados.S3VolumeDriverParameters{})
204 // s3, fully configured
205 s.testDeprecatedVolume(c, `
208 AccessKeyFile: `+accesskeyfile.Name()+`
209 SecretKeyFile: `+secretkeyfile.Name()+`
210 Endpoint: https://storage.googleapis.com
213 LocationConstraint: true
223 }, &arvados.S3VolumeDriverParameters{
224 AccessKey: "accesskeydata",
225 SecretKey: "secretkeydata",
226 Endpoint: "https://storage.googleapis.com",
227 Region: "us-east-1z",
228 Bucket: "testbucket",
229 LocationConstraint: true,
231 ConnectTimeout: arvados.Duration(time.Minute * 3),
232 ReadTimeout: arvados.Duration(time.Minute * 4),
233 RaceWindow: arvados.Duration(time.Minute * 5),
235 }, &arvados.S3VolumeDriverParameters{})
237 // azure, empty/default
238 s.testDeprecatedVolume(c, `
244 }, &arvados.AzureVolumeDriverParameters{}, &arvados.AzureVolumeDriverParameters{})
246 // azure, fully configured
247 s.testDeprecatedVolume(c, `
251 StorageAccountName: storageacctname
252 StorageAccountKeyFile: `+secretkeyfile.Name()+`
253 StorageBaseURL: https://example.example
254 ContainerName: testctr
255 LocationConstraint: true
258 ListBlobsRetryDelay: 4m
259 ListBlobsMaxAttempts: 5
264 }, &arvados.AzureVolumeDriverParameters{
265 StorageAccountName: "storageacctname",
266 StorageAccountKey: "secretkeydata",
267 StorageBaseURL: "https://example.example",
268 ContainerName: "testctr",
269 RequestTimeout: arvados.Duration(time.Minute * 3),
270 ListBlobsRetryDelay: arvados.Duration(time.Minute * 4),
271 ListBlobsMaxAttempts: 5,
272 }, &arvados.AzureVolumeDriverParameters{})
274 // directory, empty/default
275 s.testDeprecatedVolume(c, `
282 }, &arvados.DirectoryVolumeDriverParameters{
284 }, &arvados.DirectoryVolumeDriverParameters{})
286 // directory, fully configured
287 s.testDeprecatedVolume(c, `
292 DirectoryReplication: 4
298 }, &arvados.DirectoryVolumeDriverParameters{
301 }, &arvados.DirectoryVolumeDriverParameters{})
304 func (s *KeepstoreMigrationSuite) testDeprecatedVolume(c *check.C, oldconfigdata string, expectvol arvados.Volume, expectparams interface{}, paramsdst interface{}) {
305 hostname := s.hostname
307 h, err := os.Hostname()
308 c.Assert(err, check.IsNil)
312 oldconfig, err := ioutil.TempFile("", "")
313 c.Assert(err, check.IsNil)
314 defer os.Remove(oldconfig.Name())
315 io.WriteString(oldconfig, "Listen: :12345\n"+oldconfigdata)
316 if !strings.Contains(oldconfigdata, "DiscoverVolumesFromMountsFile") {
317 // Prevent tests from looking at the real /proc/mounts on the test host.
318 io.WriteString(oldconfig, "\nDiscoverVolumesFromMountsFile: /dev/null\n")
321 ldr := testLoader(c, "Clusters: {z1111: {}}", nil)
322 ldr.KeepstorePath = oldconfig.Name()
323 cfg, err := ldr.Load()
324 c.Assert(err, check.IsNil)
325 cc := cfg.Clusters["z1111"]
326 c.Check(cc.Volumes, check.HasLen, 1)
327 for uuid, v := range cc.Volumes {
328 c.Check(uuid, check.HasLen, 27)
329 c.Check(v.Driver, check.Equals, expectvol.Driver)
330 c.Check(v.Replication, check.Equals, expectvol.Replication)
332 avh, ok := v.AccessViaHosts[arvados.URL{Scheme: "http", Host: hostname + ":12345"}]
333 c.Check(ok, check.Equals, true)
334 c.Check(avh.ReadOnly, check.Equals, expectvol.ReadOnly)
336 err := json.Unmarshal(v.DriverParameters, paramsdst)
337 c.Check(err, check.IsNil)
338 c.Check(paramsdst, check.DeepEquals, expectparams)
342 // How we handle a volume from a legacy keepstore config file depends
343 // on whether it's writable, whether a volume using the same cloud
344 // backend already exists in the cluster config, and (if so) whether
345 // it already has an AccessViaHosts entry for this host.
347 // In all cases, we should end up with an AccessViaHosts entry for
348 // this host, to indicate that the current host's volumes have been
351 // Same backend already referenced in cluster config, this host
352 // already listed in AccessViaHosts --> no change, except possibly
353 // updating the ReadOnly flag on the AccessViaHosts entry.
354 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AlreadyMigrated(c *check.C) {
355 before, after := s.loadWithKeepstoreConfig(c, `
359 Endpoint: https://storage.googleapis.com
361 Bucket: alreadymigrated
364 checkEqualYAML(c, after, before)
367 // Writable volume, same cloud backend already referenced in cluster
368 // config --> change UUID to match this keepstore's UUID.
369 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateUUID(c *check.C) {
370 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
372 before, after := s.loadWithKeepstoreConfig(c, `
373 Listen: :`+strconv.Itoa(port)+`
376 Endpoint: https://storage.googleapis.com
378 Bucket: readonlyonother
381 c.Check(after, check.HasLen, len(before))
382 newuuids := s.findAddedVolumes(c, before, after, 1)
383 newvol := after[newuuids[0]]
385 var params arvados.S3VolumeDriverParameters
386 json.Unmarshal(newvol.DriverParameters, ¶ms)
387 c.Check(params.Bucket, check.Equals, "readonlyonother")
388 c.Check(newuuids[0], check.Equals, expectUUID)
391 // Writable volume, same cloud backend not yet referenced --> add a
392 // new volume, with UUID to match this keepstore's UUID.
393 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddCloudVolume(c *check.C) {
394 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
396 before, after := s.loadWithKeepstoreConfig(c, `
397 Listen: :`+strconv.Itoa(port)+`
400 Endpoint: https://storage.googleapis.com
402 Bucket: bucket-to-migrate
405 newuuids := s.findAddedVolumes(c, before, after, 1)
406 newvol := after[newuuids[0]]
408 var params arvados.S3VolumeDriverParameters
409 json.Unmarshal(newvol.DriverParameters, ¶ms)
410 c.Check(params.Bucket, check.Equals, "bucket-to-migrate")
411 c.Check(newvol.Replication, check.Equals, 3)
413 c.Check(newuuids[0], check.Equals, expectUUID)
416 // Writable volume, same filesystem backend already referenced in
417 // cluster config, but this host isn't in AccessViaHosts --> add a new
418 // volume, with UUID to match this keepstore's UUID (filesystem-backed
419 // volumes are assumed to be different on different hosts, even if
420 // paths are the same).
421 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddLocalVolume(c *check.C) {
422 before, after := s.loadWithKeepstoreConfig(c, `
427 DirectoryReplication: 2
429 newuuids := s.findAddedVolumes(c, before, after, 1)
430 newvol := after[newuuids[0]]
432 var params arvados.DirectoryVolumeDriverParameters
433 json.Unmarshal(newvol.DriverParameters, ¶ms)
434 c.Check(params.Root, check.Equals, "/data/sdd")
435 c.Check(newvol.Replication, check.Equals, 2)
438 // Writable volume, same filesystem backend already referenced in
439 // cluster config, and this host is already listed in AccessViaHosts
440 // --> already migrated, don't change anything.
441 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_LocalVolumeAlreadyMigrated(c *check.C) {
442 before, after := s.loadWithKeepstoreConfig(c, `
447 DirectoryReplication: 2
449 checkEqualYAML(c, after, before)
452 // Multiple writable cloud-backed volumes --> one of them will get a
453 // UUID matching this keepstore's UUID.
454 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddMultipleCloudVolumes(c *check.C) {
455 port, expectUUID := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
457 before, after := s.loadWithKeepstoreConfig(c, `
458 Listen: :`+strconv.Itoa(port)+`
461 Endpoint: https://storage.googleapis.com
463 Bucket: first-bucket-to-migrate
466 Endpoint: https://storage.googleapis.com
468 Bucket: second-bucket-to-migrate
471 newuuids := s.findAddedVolumes(c, before, after, 2)
472 // Sort by bucket name (so "first" comes before "second")
473 params := map[string]arvados.S3VolumeDriverParameters{}
474 for _, uuid := range newuuids {
475 var p arvados.S3VolumeDriverParameters
476 json.Unmarshal(after[uuid].DriverParameters, &p)
479 sort.Slice(newuuids, func(i, j int) bool { return params[newuuids[i]].Bucket < params[newuuids[j]].Bucket })
480 newvol0, newvol1 := after[newuuids[0]], after[newuuids[1]]
481 params0, params1 := params[newuuids[0]], params[newuuids[1]]
483 c.Check(params0.Bucket, check.Equals, "first-bucket-to-migrate")
484 c.Check(newvol0.Replication, check.Equals, 3)
486 c.Check(params1.Bucket, check.Equals, "second-bucket-to-migrate")
487 c.Check(newvol1.Replication, check.Equals, 3)
489 // Don't care which one gets the special UUID
490 if newuuids[0] != expectUUID {
491 c.Check(newuuids[1], check.Equals, expectUUID)
495 // Non-writable volume, same cloud backend already referenced in
496 // cluster config --> add this host to AccessViaHosts with
498 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateWithReadOnly(c *check.C) {
499 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
500 before, after := s.loadWithKeepstoreConfig(c, `
501 Listen: :`+strconv.Itoa(port)+`
504 Endpoint: https://storage.googleapis.com
506 Bucket: readonlyonother
510 hostname, err := os.Hostname()
511 c.Assert(err, check.IsNil)
514 Host: fmt.Sprintf("%s:%d", hostname, port),
516 _, ok := before["zzzzz-nyw5e-readonlyonother"].AccessViaHosts[url]
517 c.Check(ok, check.Equals, false)
518 _, ok = after["zzzzz-nyw5e-readonlyonother"].AccessViaHosts[url]
519 c.Check(ok, check.Equals, true)
522 // Writable volume, same cloud backend already writable by another
523 // keepstore server --> add this host to AccessViaHosts with
525 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_UpdateAlreadyWritable(c *check.C) {
526 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
527 before, after := s.loadWithKeepstoreConfig(c, `
528 Listen: :`+strconv.Itoa(port)+`
531 Endpoint: https://storage.googleapis.com
533 Bucket: writableonother
537 hostname, err := os.Hostname()
538 c.Assert(err, check.IsNil)
541 Host: fmt.Sprintf("%s:%d", hostname, port),
543 _, ok := before["zzzzz-nyw5e-writableonother"].AccessViaHosts[url]
544 c.Check(ok, check.Equals, false)
545 _, ok = after["zzzzz-nyw5e-writableonother"].AccessViaHosts[url]
546 c.Check(ok, check.Equals, true)
549 // Non-writable volume, same cloud backend not already referenced in
550 // cluster config --> assign a new random volume UUID.
551 func (s *KeepstoreMigrationSuite) TestIncrementalVolumeMigration_AddReadOnly(c *check.C) {
552 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
553 before, after := s.loadWithKeepstoreConfig(c, `
554 Listen: :`+strconv.Itoa(port)+`
557 Endpoint: https://storage.googleapis.com
559 Bucket: differentbucket
562 newuuids := s.findAddedVolumes(c, before, after, 1)
563 newvol := after[newuuids[0]]
565 var params arvados.S3VolumeDriverParameters
566 json.Unmarshal(newvol.DriverParameters, ¶ms)
567 c.Check(params.Bucket, check.Equals, "differentbucket")
569 hostname, err := os.Hostname()
570 c.Assert(err, check.IsNil)
571 _, ok := newvol.AccessViaHosts[arvados.URL{Scheme: "http", Host: fmt.Sprintf("%s:%d", hostname, port)}]
572 c.Check(ok, check.Equals, true)
575 // Ensure logs mention unmigrated servers.
576 func (s *KeepstoreMigrationSuite) TestPendingKeepstoreMigrations(c *check.C) {
577 client := arvados.NewClientFromEnv()
578 for _, host := range []string{"keep0", "keep1"} {
579 err := client.RequestAndDecode(new(struct{}), "POST", "arvados/v1/keep_services", nil, map[string]interface{}{
580 "keep_service": map[string]interface{}{
581 "service_type": "disk",
582 "service_host": host + ".zzzzz.example.com",
583 "service_port": 25107,
586 c.Assert(err, check.IsNil)
589 port, _ := s.getTestKeepstorePortAndMatchingVolumeUUID(c)
590 logs := s.logsWithKeepstoreConfig(c, `
591 Listen: :`+strconv.Itoa(port)+`
594 Endpoint: https://storage.googleapis.com
597 c.Check(logs, check.Matches, `(?ms).*you should remove the legacy keepstore config file.*`)
598 c.Check(logs, check.Matches, `(?ms).*you should migrate the legacy keepstore configuration file on host keep1.zzzzz.example.com.*`)
599 c.Check(logs, check.Not(check.Matches), `(?ms).*should migrate.*keep0.zzzzz.example.com.*`)
600 c.Check(logs, check.Matches, `(?ms).*keepstore configured at http://keep2.zzzzz.example.com:25107 does not have access to any volumes.*`)
601 c.Check(logs, check.Matches, `(?ms).*Volumes.zzzzz-nyw5e-possconfigerror.AccessViaHosts refers to nonexistent keepstore server http://keep00.zzzzz.example.com:25107.*`)
604 const clusterConfigForKeepstoreMigrationTest = `
607 SystemRootToken: ` + arvadostest.AdminToken + `
611 "http://{{.hostname}}:12345": {}
612 "http://keep0.zzzzz.example.com:25107": {}
613 "http://keep2.zzzzz.example.com:25107": {}
615 ExternalURL: "https://{{.controller}}"
620 zzzzz-nyw5e-alreadymigrated:
622 "http://{{.hostname}}:12345": {}
625 Endpoint: https://storage.googleapis.com
627 Bucket: alreadymigrated
630 zzzzz-nyw5e-readonlyonother:
632 "http://keep0.zzzzz.example.com:25107": {ReadOnly: true}
635 Endpoint: https://storage.googleapis.com
637 Bucket: readonlyonother
640 zzzzz-nyw5e-writableonother:
642 "http://keep0.zzzzz.example.com:25107": {}
645 Endpoint: https://storage.googleapis.com
647 Bucket: writableonother
650 zzzzz-nyw5e-localfilesystem:
652 "http://keep0.zzzzz.example.com:25107": {}
658 zzzzz-nyw5e-localismigrated:
660 "http://{{.hostname}}:12345": {}
666 zzzzz-nyw5e-possconfigerror:
668 "http://keep00.zzzzz.example.com:25107": {}
675 // Determine the effect of combining the given legacy keepstore config
676 // YAML (just the "Volumes" entries of an old keepstore config file)
677 // with the example clusterConfigForKeepstoreMigrationTest config.
679 // Return two Volumes configs -- one without loading keepstoreYAML
680 // ("before") and one with ("after") -- for the caller to compare.
681 func (s *KeepstoreMigrationSuite) loadWithKeepstoreConfig(c *check.C, keepstoreYAML string) (before, after map[string]arvados.Volume) {
682 ldr := testLoader(c, s.clusterConfigYAML(c), nil)
683 cBefore, err := ldr.Load()
684 c.Assert(err, check.IsNil)
686 keepstoreconfig, err := ioutil.TempFile("", "")
687 c.Assert(err, check.IsNil)
688 defer os.Remove(keepstoreconfig.Name())
689 io.WriteString(keepstoreconfig, keepstoreYAML)
691 ldr = testLoader(c, s.clusterConfigYAML(c), nil)
692 ldr.KeepstorePath = keepstoreconfig.Name()
693 cAfter, err := ldr.Load()
694 c.Assert(err, check.IsNil)
696 return cBefore.Clusters["zzzzz"].Volumes, cAfter.Clusters["zzzzz"].Volumes
699 // Return the log messages emitted when loading keepstoreYAML along
700 // with clusterConfigForKeepstoreMigrationTest.
701 func (s *KeepstoreMigrationSuite) logsWithKeepstoreConfig(c *check.C, keepstoreYAML string) string {
702 var logs bytes.Buffer
704 keepstoreconfig, err := ioutil.TempFile("", "")
705 c.Assert(err, check.IsNil)
706 defer os.Remove(keepstoreconfig.Name())
707 io.WriteString(keepstoreconfig, keepstoreYAML)
709 ldr := testLoader(c, s.clusterConfigYAML(c), &logs)
710 ldr.KeepstorePath = keepstoreconfig.Name()
712 c.Assert(err, check.IsNil)
717 func (s *KeepstoreMigrationSuite) clusterConfigYAML(c *check.C) string {
718 hostname, err := os.Hostname()
719 c.Assert(err, check.IsNil)
721 tmpl := template.Must(template.New("config").Parse(clusterConfigForKeepstoreMigrationTest))
723 var clusterconfigdata bytes.Buffer
724 err = tmpl.Execute(&clusterconfigdata, map[string]interface{}{
725 "hostname": hostname,
726 "controller": os.Getenv("ARVADOS_API_HOST"),
728 c.Assert(err, check.IsNil)
730 return clusterconfigdata.String()
733 // Return the uuids of volumes that appear in "after" but not
736 // Assert the returned slice has at least minAdded entries.
737 func (s *KeepstoreMigrationSuite) findAddedVolumes(c *check.C, before, after map[string]arvados.Volume, minAdded int) (uuids []string) {
738 for uuid := range after {
739 if _, ok := before[uuid]; !ok {
740 uuids = append(uuids, uuid)
743 if len(uuids) < minAdded {
744 c.Assert(uuids, check.HasLen, minAdded)
749 func (s *KeepstoreMigrationSuite) getTestKeepstorePortAndMatchingVolumeUUID(c *check.C) (int, string) {
750 for port, ks := range s.ksByPort {
751 c.Assert(ks.UUID, check.HasLen, 27)
752 return port, "zzzzz-nyw5e-" + ks.UUID[12:]
754 c.Fatal("s.ksByPort is empty")
758 func (s *KeepstoreMigrationSuite) TestKeepServiceIsMe(c *check.C) {
759 for i, trial := range []struct {
766 {true, "keep0", "keep0", "keep0", 80},
767 {true, "keep0", "[::1]:http", "keep0", 80},
768 {true, "keep0", "[::]:http", "keep0", 80},
769 {true, "keep0", "keep0:25107", "keep0", 25107},
770 {true, "keep0", ":25107", "keep0", 25107},
771 {true, "keep0.domain", ":25107", "keep0.domain.example", 25107},
772 {true, "keep0.domain.example", ":25107", "keep0.domain.example", 25107},
773 {true, "keep0", ":25107", "keep0.domain.example", 25107},
774 {true, "keep0", ":25107", "Keep0.domain.example", 25107},
775 {true, "keep0", ":http", "keep0.domain.example", 80},
776 {true, "keep0", ":25107", "localhost", 25107},
777 {true, "keep0", ":25107", "::1", 25107},
778 {false, "keep0", ":25107", "keep0", 1111}, // different port
779 {false, "keep0", ":25107", "localhost", 1111}, // different port
780 {false, "keep0", ":http", "keep0.domain.example", 443}, // different port
781 {false, "keep0", ":bogussss", "keep0", 25107}, // unresolvable port
782 {false, "keep0", ":25107", "keep1", 25107}, // different hostname
783 {false, "keep1", ":25107", "keep10", 25107}, // different hostname (prefix, but not on a "." boundary)
785 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))