[ARVADOS] updated: 1.3.0-2258-g71b3aadcb

Git user git at public.arvados.org
Thu Feb 20 19:25:21 UTC 2020


Summary of changes:
 apps/workbench/config/application.rb |   4 +
 lib/boot/cmd.go                      | 130 ++++++++++++++++++++--------
 lib/boot/log.go                      |   8 +-
 lib/boot/nginx.go                    |   2 +
 lib/boot/passenger.go                |  11 +++
 lib/boot/postgresql.go               |   2 +
 lib/boot/service.go                  |   9 +-
 lib/controller/integration_test.go   | 158 +++++++++++++++++++++++++++++++++++
 sdk/go/auth/auth.go                  |   4 +-
 sdk/go/ctxlog/log.go                 |   6 ++
 sdk/python/tests/run_test_server.py  |   7 +-
 services/api/config/application.rb   |   4 +
 12 files changed, 302 insertions(+), 43 deletions(-)
 create mode 100644 lib/controller/integration_test.go

       via  71b3aadcbf0d8a3c0b283fc27a17773951d417c7 (commit)
       via  1522882c653c7e991406a461305bd998b7af5501 (commit)
       via  6a40ad14cf9b06382fd28c8fb19761553f905b2f (commit)
       via  9e18d1e4bfe71ed00589c4d26d89b07db2bf9527 (commit)
       via  20b817b6e8129bf86300f2f3580b9798b7210aaf (commit)
       via  67c0989ae7d54d9aa809c507c657d78059ed0f39 (commit)
       via  49db4a42db194423978996acb9325aeb3eaaf403 (commit)
       via  d527d35430978b42448388dad241b57851fda335 (commit)
       via  0e9e741685fc74b39bffd0a3ad1092391224626c (commit)
       via  343e87375ce53c0b9c4234ed69206b31e206c877 (commit)
       via  0857d7c48349d0d2e3a0570540e7a9e6ba25dca0 (commit)
       via  1a8d5e88202046dbfe7f2114bf30ee5970c505be (commit)
       via  c483ba94df5f80396101dda756e702f280942ca9 (commit)
       via  4dc3ab33afc13fa05926cb090141c34e3fb82ee7 (commit)
       via  d12c72e462cd200a2e90fab77762faa6a0c49398 (commit)
       via  ee9a3015a9bd5779f9866224cef7cce9b3b8e96b (commit)
      from  8983a69aecb0ea186d2e4222bdb7d244388765a1 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 71b3aadcbf0d8a3c0b283fc27a17773951d417c7
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Thu Feb 20 14:24:30 2020 -0500

    15954: Don't return from Stop() until child processes end.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index b11cb89e4..5f5bb1ee7 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -97,7 +97,8 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
 	defer boot.Stop()
 	if url, ok := boot.WaitReady(); ok {
 		fmt.Fprintln(stdout, url)
-		<-ctx.Done() // wait for signal
+		// Wait for signal/crash + orderly shutdown
+		<-boot.done
 		return 0
 	} else {
 		return 1
@@ -121,6 +122,7 @@ type Booter struct {
 	done          chan struct{}
 	healthChecker *health.Aggregator
 	tasksReady    map[string]chan bool
+	waitShutdown  sync.WaitGroup
 
 	tempdir    string
 	configfile string
@@ -288,6 +290,7 @@ func (boot *Booter) run(cfg *arvados.Config) error {
 	boot.healthChecker = &health.Aggregator{Cluster: boot.cluster}
 	<-boot.ctx.Done()
 	boot.logger.Info("shutting down")
+	boot.waitShutdown.Wait()
 	return boot.ctx.Err()
 }
 
@@ -315,9 +318,12 @@ func (boot *Booter) Stop() {
 }
 
 func (boot *Booter) WaitReady() (*arvados.URL, bool) {
+	ticker := time.NewTicker(time.Second)
+	defer ticker.Stop()
 	for waiting := true; waiting; {
-		time.Sleep(time.Second)
-		if boot.ctx.Err() != nil {
+		select {
+		case <-ticker.C:
+		case <-boot.ctx.Done():
 			return nil, false
 		}
 		if boot.healthChecker == nil {
diff --git a/lib/boot/nginx.go b/lib/boot/nginx.go
index 5c1954c83..a06d3a700 100644
--- a/lib/boot/nginx.go
+++ b/lib/boot/nginx.go
@@ -77,7 +77,9 @@ func (runNginx) Run(ctx context.Context, fail func(error), boot *Booter) error {
 			}
 		}
 	}
+	boot.waitShutdown.Add(1)
 	go func() {
+		defer boot.waitShutdown.Done()
 		fail(boot.RunProgram(ctx, ".", nil, nil, nginx,
 			"-g", "error_log stderr info;",
 			"-g", "pid "+filepath.Join(boot.tempdir, "nginx.pid")+";",
diff --git a/lib/boot/passenger.go b/lib/boot/passenger.go
index 822e737cb..21834dab2 100644
--- a/lib/boot/passenger.go
+++ b/lib/boot/passenger.go
@@ -90,7 +90,9 @@ func (runner runPassenger) Run(ctx context.Context, fail func(error), boot *Boot
 	if err != nil {
 		return fmt.Errorf("bug: no InternalURLs for component %q: %v", runner, runner.svc.InternalURLs)
 	}
+	boot.waitShutdown.Add(1)
 	go func() {
+		defer boot.waitShutdown.Done()
 		err = boot.RunProgram(ctx, runner.src, nil, nil, "bundle", "exec",
 			"passenger", "start",
 			"-p", port,
diff --git a/lib/boot/postgresql.go b/lib/boot/postgresql.go
index 48e24ffae..ed5aecd09 100644
--- a/lib/boot/postgresql.go
+++ b/lib/boot/postgresql.go
@@ -56,7 +56,9 @@ func (runPostgreSQL) Run(ctx context.Context, fail func(error), boot *Booter) er
 
 	port := boot.cluster.PostgreSQL.Connection["port"]
 
+	boot.waitShutdown.Add(1)
 	go func() {
+		defer boot.waitShutdown.Done()
 		fail(boot.RunProgram(ctx, boot.tempdir, nil, nil, filepath.Join(bindir, "postgres"),
 			"-l",          // enable ssl
 			"-D", datadir, // data dir
diff --git a/lib/boot/service.go b/lib/boot/service.go
index 6edf78b3c..4b35e1376 100644
--- a/lib/boot/service.go
+++ b/lib/boot/service.go
@@ -45,7 +45,10 @@ func (runner runGoProgram) String() string {
 
 func (runner runGoProgram) Run(ctx context.Context, fail func(error), boot *Booter) error {
 	boot.wait(ctx, runner.depends...)
-	boot.RunProgram(ctx, runner.src, nil, nil, "go", "install")
+	err := boot.RunProgram(ctx, runner.src, nil, nil, "go", "install")
+	if err != nil {
+		return err
+	}
 	if ctx.Err() != nil {
 		return ctx.Err()
 	}
@@ -54,13 +57,17 @@ func (runner runGoProgram) Run(ctx context.Context, fail func(error), boot *Boot
 		// Run one for each URL
 		for u := range runner.svc.InternalURLs {
 			u := u
+			boot.waitShutdown.Add(1)
 			go func() {
+				defer boot.waitShutdown.Done()
 				fail(boot.RunProgram(ctx, boot.tempdir, nil, []string{"ARVADOS_SERVICE_INTERNAL_URL=" + u.String()}, basename))
 			}()
 		}
 	} else {
 		// Just run one
+		boot.waitShutdown.Add(1)
 		go func() {
+			defer boot.waitShutdown.Done()
 			fail(boot.RunProgram(ctx, boot.tempdir, nil, nil, basename))
 		}()
 	}

commit 1522882c653c7e991406a461305bd998b7af5501
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Thu Feb 20 14:22:56 2020 -0500

    15954: Close fds if Wait() doesn't return after child is killed.
    
    Otherwise, PassengerAgent processes accumulate.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index 78cfc7b87..b11cb89e4 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -444,15 +444,24 @@ func (boot *Booter) RunProgram(ctx context.Context, dir string, output io.Writer
 	if !strings.HasPrefix(dir, "/") {
 		logprefix = dir + ": " + logprefix
 	}
-	stderr := &logPrefixer{Writer: boot.Stderr, Prefix: []byte("[" + logprefix + "] ")}
 
 	cmd := exec.Command(boot.lookPath(prog), args...)
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		return err
+	}
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return err
+	}
+	logwriter := &logPrefixer{Writer: boot.Stderr, Prefix: []byte("[" + logprefix + "] ")}
+	go io.Copy(logwriter, stderr)
 	if output == nil {
-		cmd.Stdout = stderr
+		go io.Copy(logwriter, stdout)
 	} else {
-		cmd.Stdout = output
+		go io.Copy(output, stdout)
 	}
-	cmd.Stderr = stderr
+
 	if strings.HasPrefix(dir, "/") {
 		cmd.Dir = dir
 	} else {
@@ -474,13 +483,19 @@ func (boot *Booter) RunProgram(ctx context.Context, dir string, output io.Writer
 				cmd.Process.Signal(syscall.SIGTERM)
 				time.Sleep(5 * time.Second)
 				if !exited {
+					stdout.Close()
+					stderr.Close()
 					log.WithField("PID", cmd.Process.Pid).Warn("still waiting for child process to exit 5s after SIGTERM")
 				}
 			}
 		}
 	}()
 
-	err := cmd.Run()
+	err = cmd.Start()
+	if err != nil {
+		return err
+	}
+	err = cmd.Wait()
 	if err != nil && ctx.Err() == nil {
 		// Only report errors that happen before the context ends.
 		return fmt.Errorf("%s: error: %v", cmdline, err)

commit 6a40ad14cf9b06382fd28c8fb19761553f905b2f
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Thu Feb 20 13:34:07 2020 -0500

    15954: Handle signals when used as module.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index 834d99ca5..78cfc7b87 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -56,15 +56,6 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
 	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
-	ch := make(chan os.Signal)
-	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
-	go func() {
-		for sig := range ch {
-			boot.logger.WithField("signal", sig).Info("caught signal")
-			cancel()
-		}
-	}()
-
 	var err error
 	defer func() {
 		if err != nil {
@@ -143,7 +134,18 @@ type Booter struct {
 func (boot *Booter) Start(ctx context.Context, cfg *arvados.Config) {
 	boot.ctx, boot.cancel = context.WithCancel(ctx)
 	boot.done = make(chan struct{})
+
 	go func() {
+		sigch := make(chan os.Signal)
+		signal.Notify(sigch, syscall.SIGINT, syscall.SIGTERM)
+		defer signal.Stop(sigch)
+		go func() {
+			for sig := range sigch {
+				boot.logger.WithField("signal", sig).Info("caught signal")
+				boot.cancel()
+			}
+		}()
+
 		err := boot.run(cfg)
 		if err != nil {
 			fmt.Fprintln(boot.Stderr, err)
@@ -298,7 +300,9 @@ func (boot *Booter) wait(ctx context.Context, tasks ...bootTask) error {
 		boot.logger.WithField("task", task.String()).Info("waiting")
 		select {
 		case <-ch:
+			boot.logger.WithField("task", task.String()).Info("ready")
 		case <-ctx.Done():
+			boot.logger.WithField("task", task.String()).Info("task was never ready")
 			return ctx.Err()
 		}
 	}

commit 9e18d1e4bfe71ed00589c4d26d89b07db2bf9527
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Thu Feb 20 10:25:54 2020 -0500

    15954: Send rails logs to stdout when running in test mode.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/apps/workbench/config/application.rb b/apps/workbench/config/application.rb
index 514d57196..2d331c70a 100644
--- a/apps/workbench/config/application.rb
+++ b/apps/workbench/config/application.rb
@@ -19,6 +19,10 @@ require "rails/test_unit/railtie"
 
 Bundler.require(:default, Rails.env)
 
+if Rails.env == 'test'
+  Rails.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
+end
+
 module ArvadosWorkbench
   class Application < Rails::Application
 
diff --git a/sdk/python/tests/run_test_server.py b/sdk/python/tests/run_test_server.py
index 147a26426..5b75de08f 100644
--- a/sdk/python/tests/run_test_server.py
+++ b/sdk/python/tests/run_test_server.py
@@ -326,15 +326,16 @@ def run(leave_running_atexit=False):
     env.pop('ARVADOS_API_HOST', None)
     env.pop('ARVADOS_API_HOST_INSECURE', None)
     env.pop('ARVADOS_API_TOKEN', None)
+    logf = open(_logfilename('railsapi'), 'a')
     start_msg = subprocess.check_output(
         ['bundle', 'exec',
          'passenger', 'start', '-d', '-p{}'.format(port),
          '--pid-file', pid_file,
-         '--log-file', os.path.join(os.getcwd(), 'log/test.log'),
+         '--log-file', '/dev/stdout',
          '--ssl',
          '--ssl-certificate', 'tmp/self-signed.pem',
          '--ssl-certificate-key', 'tmp/self-signed.key'],
-        env=env)
+        env=env, stdin=open('/dev/null'), stdout=logf, stderr=logf)
 
     if not leave_running_atexit:
         atexit.register(kill_server_pid, pid_file, passenger_root=api_src_dir)
diff --git a/services/api/config/application.rb b/services/api/config/application.rb
index f211ec9e0..7901a7fd8 100644
--- a/services/api/config/application.rb
+++ b/services/api/config/application.rb
@@ -40,6 +40,10 @@ if defined?(Bundler)
   end
 end
 
+if Rails.env == 'test'
+  Rails.logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
+end
+
 module Server
   class Application < Rails::Application
     # The following is to avoid SafeYAML's warning message

commit 20b817b6e8129bf86300f2f3580b9798b7210aaf
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 14:30:00 2020 -0500

    15954: Fix deadlock.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/passenger.go b/lib/boot/passenger.go
index 31b4afaad..822e737cb 100644
--- a/lib/boot/passenger.go
+++ b/lib/boot/passenger.go
@@ -30,13 +30,14 @@ func (runner installPassenger) String() string {
 }
 
 func (runner installPassenger) Run(ctx context.Context, fail func(error), boot *Booter) error {
-	passengerInstallMutex.Lock()
-	defer passengerInstallMutex.Unlock()
-
 	err := boot.wait(ctx, runner.depends...)
 	if err != nil {
 		return err
 	}
+
+	passengerInstallMutex.Lock()
+	defer passengerInstallMutex.Unlock()
+
 	var buf bytes.Buffer
 	err = boot.RunProgram(ctx, runner.src, &buf, nil, "gem", "list", "--details", "bundler")
 	if err != nil {

commit 67c0989ae7d54d9aa809c507c657d78059ed0f39
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 10:25:26 2020 -0500

    15954: Remove debug printf.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/controller/integration_test.go b/lib/controller/integration_test.go
index b605fde06..157998aa7 100644
--- a/lib/controller/integration_test.go
+++ b/lib/controller/integration_test.go
@@ -101,7 +101,6 @@ func (s *IntegrationSuite) SetUpSuite(c *check.C) {
 			config: *cfg,
 		}
 		s.testClusters[id].booter.Start(context.Background(), &s.testClusters[id].config)
-		c.Logf("%v", &s.testClusters[id].config)
 	}
 	for _, tc := range s.testClusters {
 		au, ok := tc.booter.WaitReady()

commit 49db4a42db194423978996acb9325aeb3eaaf403
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 10:25:08 2020 -0500

    15954: Avoid doing concurrent bundle/passenger installs.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/passenger.go b/lib/boot/passenger.go
index 61f97df52..31b4afaad 100644
--- a/lib/boot/passenger.go
+++ b/lib/boot/passenger.go
@@ -11,10 +11,15 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"sync"
 
 	"git.arvados.org/arvados.git/sdk/go/arvados"
 )
 
+// Don't trust "passenger-config" (or "bundle install") to handle
+// concurrent installs.
+var passengerInstallMutex sync.Mutex
+
 type installPassenger struct {
 	src     string
 	depends []bootTask
@@ -25,6 +30,9 @@ func (runner installPassenger) String() string {
 }
 
 func (runner installPassenger) Run(ctx context.Context, fail func(error), boot *Booter) error {
+	passengerInstallMutex.Lock()
+	defer passengerInstallMutex.Unlock()
+
 	err := boot.wait(ctx, runner.depends...)
 	if err != nil {
 		return err

commit d527d35430978b42448388dad241b57851fda335
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 10:24:48 2020 -0500

    15954: Fix up logging prefixes.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/log.go b/lib/boot/log.go
index 062a854a0..eaaca8567 100644
--- a/lib/boot/log.go
+++ b/lib/boot/log.go
@@ -19,11 +19,13 @@ func (lp *logPrefixer) Write(p []byte) (int, error) {
 	if len(p) == 0 {
 		return 0, nil
 	}
+	var out []byte
 	if !lp.did {
-		lp.Writer.Write(lp.Prefix)
-		lp.did = p[len(p)-1] != '\n'
+		out = append(out, lp.Prefix...)
 	}
-	out := append(bytes.Replace(p[:len(p)-1], []byte("\n"), append([]byte("\n"), lp.Prefix...), -1), p[len(p)-1])
+	lp.did = p[len(p)-1] != '\n'
+	out = append(out, bytes.Replace(p[:len(p)-1], []byte("\n"), append([]byte("\n"), lp.Prefix...), -1)...)
+	out = append(out, p[len(p)-1])
 	_, err := lp.Writer.Write(out)
 	if err != nil {
 		return 0, err

commit 0e9e741685fc74b39bffd0a3ad1092391224626c
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 10:24:18 2020 -0500

    15954: Don't start health checks until everything is started.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index 105c94e9f..834d99ca5 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -212,7 +212,6 @@ func (boot *Booter) run(cfg *arvados.Config) error {
 	boot.logger = ctxlog.New(boot.Stderr, boot.cluster.SystemLogs.Format, loglevel).WithFields(logrus.Fields{
 		"PID": os.Getpid(),
 	})
-	boot.healthChecker = &health.Aggregator{Cluster: boot.cluster}
 
 	for _, dir := range []string{boot.LibPath, filepath.Join(boot.LibPath, "bin")} {
 		if _, err = os.Stat(filepath.Join(dir, ".")); os.IsNotExist(err) {
@@ -283,7 +282,10 @@ func (boot *Booter) run(cfg *arvados.Config) error {
 	if err != nil {
 		return err
 	}
+	boot.logger.Info("all startup tasks are complete; starting health checks")
+	boot.healthChecker = &health.Aggregator{Cluster: boot.cluster}
 	<-boot.ctx.Done()
+	boot.logger.Info("shutting down")
 	return boot.ctx.Err()
 }
 

commit 343e87375ce53c0b9c4234ed69206b31e206c877
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 10:23:47 2020 -0500

    15954: Move passenger temp files into tempdir.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index d8a915b18..105c94e9f 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -196,6 +196,7 @@ func (boot *Booter) run(cfg *arvados.Config) error {
 	boot.cleanEnv()
 	boot.setEnv("ARVADOS_CONFIG", boot.configfile)
 	boot.setEnv("RAILS_ENV", boot.ClusterType)
+	boot.setEnv("TMPDIR", boot.tempdir)
 	boot.prependEnv("PATH", filepath.Join(boot.LibPath, "bin")+":")
 
 	boot.cluster, err = cfg.GetCluster("")

commit 0857d7c48349d0d2e3a0570540e7a9e6ba25dca0
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 09:46:55 2020 -0500

    15954: Stub multi-cluster integration test.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/controller/integration_test.go b/lib/controller/integration_test.go
new file mode 100644
index 000000000..b605fde06
--- /dev/null
+++ b/lib/controller/integration_test.go
@@ -0,0 +1,159 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package controller
+
+import (
+	"bytes"
+	"context"
+	"net"
+	"net/url"
+	"os"
+	"path/filepath"
+
+	"git.arvados.org/arvados.git/lib/boot"
+	"git.arvados.org/arvados.git/lib/config"
+	"git.arvados.org/arvados.git/lib/controller/rpc"
+	"git.arvados.org/arvados.git/sdk/go/arvados"
+	"git.arvados.org/arvados.git/sdk/go/arvadosclient"
+	"git.arvados.org/arvados.git/sdk/go/auth"
+	"git.arvados.org/arvados.git/sdk/go/ctxlog"
+	"git.arvados.org/arvados.git/sdk/go/keepclient"
+	check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&IntegrationSuite{})
+
+type testCluster struct {
+	booter        boot.Booter
+	config        arvados.Config
+	controllerURL *url.URL
+}
+
+type IntegrationSuite struct {
+	testClusters map[string]*testCluster
+}
+
+func (s *IntegrationSuite) SetUpSuite(c *check.C) {
+	if forceLegacyAPI14 {
+		c.Skip("heavy integration tests don't run with forceLegacyAPI14")
+		return
+	}
+
+	cwd, _ := os.Getwd()
+	s.testClusters = map[string]*testCluster{
+		"z1111": nil,
+		"z2222": nil,
+		"z3333": nil,
+	}
+	port := map[string]string{}
+	for id := range s.testClusters {
+		port[id] = func() string {
+			ln, err := net.Listen("tcp", "localhost:0")
+			c.Assert(err, check.IsNil)
+			ln.Close()
+			_, port, err := net.SplitHostPort(ln.Addr().String())
+			c.Assert(err, check.IsNil)
+			return port
+		}()
+	}
+	for id := range s.testClusters {
+		yaml := `Clusters:
+  ` + id + `:
+    Services:
+      Controller:
+        ExternalURL: https://localhost:` + port[id] + `
+    TLS:
+      Insecure: true
+    Login:
+      LoginCluster: z1111
+    RemoteClusters:
+      z1111:
+        Host: localhost:` + port["z1111"] + `
+        Scheme: https
+        Insecure: true
+      z2222:
+        Host: localhost:` + port["z2222"] + `
+        Scheme: https
+        Insecure: true
+      z3333:
+        Host: localhost:` + port["z3333"] + `
+        Scheme: https
+        Insecure: true
+`
+		loader := config.NewLoader(bytes.NewBufferString(yaml), ctxlog.TestLogger(c))
+		loader.Path = "-"
+		loader.SkipLegacy = true
+		loader.SkipAPICalls = true
+		cfg, err := loader.Load()
+		c.Assert(err, check.IsNil)
+		s.testClusters[id] = &testCluster{
+			booter: boot.Booter{
+				SourcePath:           filepath.Join(cwd, "..", ".."),
+				LibPath:              filepath.Join(cwd, "..", "..", "tmp"),
+				ClusterType:          "test",
+				ListenHost:           "localhost",
+				ControllerAddr:       ":0",
+				OwnTemporaryDatabase: true,
+				Stderr:               ctxlog.LogWriter(c.Log),
+			},
+			config: *cfg,
+		}
+		s.testClusters[id].booter.Start(context.Background(), &s.testClusters[id].config)
+		c.Logf("%v", &s.testClusters[id].config)
+	}
+	for _, tc := range s.testClusters {
+		au, ok := tc.booter.WaitReady()
+		c.Assert(ok, check.Equals, true)
+		u := url.URL(*au)
+		tc.controllerURL = &u
+	}
+}
+
+func (s *IntegrationSuite) TearDownSuite(c *check.C) {
+	for _, c := range s.testClusters {
+		c.booter.Stop()
+	}
+}
+
+func (s *IntegrationSuite) conn(clusterID string) (*rpc.Conn, context.Context, *arvados.Client, *keepclient.KeepClient) {
+	cl := s.testClusters[clusterID].config.Clusters[clusterID]
+	conn := rpc.NewConn(clusterID, s.testClusters[clusterID].controllerURL, true, rpc.PassthroughTokenProvider)
+	rootctx := auth.NewContext(context.Background(), auth.NewCredentials(cl.SystemRootToken))
+	ac, err := arvados.NewClientFromConfig(&cl)
+	if err != nil {
+		panic(err)
+	}
+	ac.AuthToken = cl.SystemRootToken
+	arv, err := arvadosclient.New(ac)
+	if err != nil {
+		panic(err)
+	}
+	kc := keepclient.New(arv)
+	return conn, rootctx, ac, kc
+}
+
+func (s *IntegrationSuite) TestLoopDetection(c *check.C) {
+	conn1, rootctx1, _, _ := s.conn("z1111")
+	conn3, rootctx3, ac3, kc3 := s.conn("z3333")
+
+	_, err := conn1.CollectionGet(rootctx1, arvados.GetOptions{UUID: "1f4b0bc7583c2a7f9102c395f4ffc5e3+45"})
+	c.Check(err, check.ErrorMatches, `.*404 Not Found.*`)
+
+	var coll3 arvados.Collection
+	fs3, err := coll3.FileSystem(ac3, kc3)
+	if err != nil {
+		c.Error(err)
+	}
+	f, err := fs3.OpenFile("foo", os.O_CREATE|os.O_RDWR, 0777)
+	f.Write([]byte("foo"))
+	f.Close()
+	mtxt, err := fs3.MarshalManifest(".")
+	coll3, err = conn3.CollectionCreate(rootctx3, arvados.CreateOptions{Attrs: map[string]interface{}{
+		"manifest_text": mtxt,
+	}})
+	coll, err := conn1.CollectionGet(rootctx1, arvados.GetOptions{UUID: "1f4b0bc7583c2a7f9102c395f4ffc5e3+45"})
+	c.Check(err, check.IsNil)
+	c.Check(coll.PortableDataHash, check.Equals, "1f4b0bc7583c2a7f9102c395f4ffc5e3+45")
+}
diff --git a/sdk/go/auth/auth.go b/sdk/go/auth/auth.go
index c2f6a0e8f..b6a85e05e 100644
--- a/sdk/go/auth/auth.go
+++ b/sdk/go/auth/auth.go
@@ -16,8 +16,8 @@ type Credentials struct {
 	Tokens []string
 }
 
-func NewCredentials() *Credentials {
-	return &Credentials{Tokens: []string{}}
+func NewCredentials(tokens ...string) *Credentials {
+	return &Credentials{Tokens: tokens}
 }
 
 func NewContext(ctx context.Context, c *Credentials) context.Context {

commit 1a8d5e88202046dbfe7f2114bf30ee5970c505be
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 09:42:53 2020 -0500

    15954: Add write-to-log-func shim.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/sdk/go/ctxlog/log.go b/sdk/go/ctxlog/log.go
index a17ad8d83..acbb11a36 100644
--- a/sdk/go/ctxlog/log.go
+++ b/sdk/go/ctxlog/log.go
@@ -60,6 +60,12 @@ func TestLogger(c interface{ Log(...interface{}) }) *logrus.Logger {
 	return logger
 }
 
+// LogWriter returns an io.Writer that writes to the given log func,
+// which is typically (*check.C).Log().
+func LogWriter(log func(...interface{})) io.Writer {
+	return &logWriter{log}
+}
+
 // SetLevel sets the current logging level. See logrus for level
 // names.
 func SetLevel(level string) {

commit c483ba94df5f80396101dda756e702f280942ca9
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 09:31:26 2020 -0500

    15954: Fix templating for workbench1 proxy.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/sdk/python/tests/run_test_server.py b/sdk/python/tests/run_test_server.py
index 9519c2b72..147a26426 100644
--- a/sdk/python/tests/run_test_server.py
+++ b/sdk/python/tests/run_test_server.py
@@ -630,7 +630,7 @@ def run_nginx():
     conffile = os.path.join(TEST_TMPDIR, 'nginx.conf')
     with open(conffile, 'w') as f:
         f.write(re.sub(
-            r'{{([A-Z]+)}}',
+            r'{{([A-Z]+[A-Z0-9]+)}}',
             lambda match: str(nginxconf.get(match.group(1))),
             open(conftemplatefile).read()))
 

commit 4dc3ab33afc13fa05926cb090141c34e3fb82ee7
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 09:30:22 2020 -0500

    15954: Clean environment.
    
    Undo run-tests.sh magic.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index 04f6838b7..d8a915b18 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -17,6 +17,7 @@ import (
 	"os"
 	"os/exec"
 	"os/signal"
+	"os/user"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -192,6 +193,7 @@ func (boot *Booter) run(cfg *arvados.Config) error {
 	boot.configfile = conffile.Name()
 
 	boot.environ = os.Environ()
+	boot.cleanEnv()
 	boot.setEnv("ARVADOS_CONFIG", boot.configfile)
 	boot.setEnv("RAILS_ENV", boot.ClusterType)
 	boot.prependEnv("PATH", filepath.Join(boot.LibPath, "bin")+":")
@@ -343,6 +345,29 @@ func (boot *Booter) prependEnv(key, prepend string) {
 	boot.environ = append(boot.environ, key+"="+prepend)
 }
 
+var cleanEnvPrefixes = []string{
+	"GEM_HOME=",
+	"GEM_PATH=",
+	"ARVADOS_",
+}
+
+func (boot *Booter) cleanEnv() {
+	var cleaned []string
+	for _, s := range boot.environ {
+		drop := false
+		for _, p := range cleanEnvPrefixes {
+			if strings.HasPrefix(s, p) {
+				drop = true
+				break
+			}
+		}
+		if !drop {
+			cleaned = append(cleaned, s)
+		}
+	}
+	boot.environ = cleaned
+}
+
 func (boot *Booter) setEnv(key, val string) {
 	for i, s := range boot.environ {
 		if strings.HasPrefix(s, key+"=") {
@@ -360,7 +385,9 @@ func (boot *Booter) installGoProgram(ctx context.Context, srcpath string) error
 }
 
 func (boot *Booter) setupRubyEnv() error {
-	buf, err := exec.Command("gem", "env", "gempath").Output() // /var/lib/arvados/.gem/ruby/2.5.0/bin:...
+	cmd := exec.Command("gem", "env", "gempath")
+	cmd.Env = boot.environ
+	buf, err := cmd.Output() // /var/lib/arvados/.gem/ruby/2.5.0/bin:...
 	if err != nil || len(buf) == 0 {
 		return fmt.Errorf("gem env gempath: %v", err)
 	}
@@ -368,6 +395,12 @@ func (boot *Booter) setupRubyEnv() error {
 	boot.prependEnv("PATH", gempath+"/bin:")
 	boot.setEnv("GEM_HOME", gempath)
 	boot.setEnv("GEM_PATH", gempath)
+	// Passenger install doesn't work unless $HOME is ~user
+	u, err := user.Current()
+	if err != nil {
+		return err
+	}
+	boot.setEnv("HOME", u.HomeDir)
 	return nil
 }
 

commit d12c72e462cd200a2e90fab77762faa6a0c49398
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Wed Feb 19 09:30:00 2020 -0500

    15954: Return controller URL when ready.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index cd2582d03..04f6838b7 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -103,8 +103,8 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
 
 	boot.Start(ctx, cfg)
 	defer boot.Stop()
-	if boot.WaitReady() {
-		fmt.Fprintln(stdout, boot.cluster.Services.Controller.ExternalURL)
+	if url, ok := boot.WaitReady(); ok {
+		fmt.Fprintln(stdout, url)
 		<-ctx.Done() // wait for signal
 		return 0
 	} else {
@@ -305,11 +305,11 @@ func (boot *Booter) Stop() {
 	<-boot.done
 }
 
-func (boot *Booter) WaitReady() bool {
+func (boot *Booter) WaitReady() (*arvados.URL, bool) {
 	for waiting := true; waiting; {
 		time.Sleep(time.Second)
 		if boot.ctx.Err() != nil {
-			return false
+			return nil, false
 		}
 		if boot.healthChecker == nil {
 			// not set up yet
@@ -329,7 +329,8 @@ func (boot *Booter) WaitReady() bool {
 			}
 		}
 	}
-	return true
+	u := boot.cluster.Services.Controller.ExternalURL
+	return &u, true
 }
 
 func (boot *Booter) prependEnv(key, prepend string) {

commit ee9a3015a9bd5779f9866224cef7cce9b3b8e96b
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Tue Feb 18 21:10:09 2020 -0500

    15954: Pass config instead of loader.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/lib/boot/cmd.go b/lib/boot/cmd.go
index 6cf44837c..cd2582d03 100644
--- a/lib/boot/cmd.go
+++ b/lib/boot/cmd.go
@@ -95,7 +95,13 @@ func (bootCommand) RunCommand(prog string, args []string, stdin io.Reader, stdou
 		return 2
 	}
 
-	boot.Start(ctx, loader)
+	loader.SkipAPICalls = true
+	cfg, err := loader.Load()
+	if err != nil {
+		return 1
+	}
+
+	boot.Start(ctx, cfg)
 	defer boot.Stop()
 	if boot.WaitReady() {
 		fmt.Fprintln(stdout, boot.cluster.Services.Controller.ExternalURL)
@@ -133,11 +139,11 @@ type Booter struct {
 	goMutex       sync.Mutex
 }
 
-func (boot *Booter) Start(ctx context.Context, loader *config.Loader) {
+func (boot *Booter) Start(ctx context.Context, cfg *arvados.Config) {
 	boot.ctx, boot.cancel = context.WithCancel(ctx)
 	boot.done = make(chan struct{})
 	go func() {
-		err := boot.run(loader)
+		err := boot.run(cfg)
 		if err != nil {
 			fmt.Fprintln(boot.Stderr, err)
 		}
@@ -145,7 +151,7 @@ func (boot *Booter) Start(ctx context.Context, loader *config.Loader) {
 	}()
 }
 
-func (boot *Booter) run(loader *config.Loader) error {
+func (boot *Booter) run(cfg *arvados.Config) error {
 	cwd, err := os.Getwd()
 	if err != nil {
 		return err
@@ -164,12 +170,6 @@ func (boot *Booter) run(loader *config.Loader) error {
 	}
 	defer os.RemoveAll(boot.tempdir)
 
-	loader.SkipAPICalls = true
-	cfg, err := loader.Load()
-	if err != nil {
-		return err
-	}
-
 	// Fill in any missing config keys, and write the resulting
 	// config in the temp dir for child services to use.
 	err = boot.autofillConfig(cfg, boot.logger)

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list