[ARVADOS] updated: 1.3.0-3237-g5846dac43

Git user git at public.arvados.org
Tue Sep 29 19:06:14 UTC 2020


Summary of changes:
 .../app/controllers/application_controller.rb      |    2 +-
 .../app/views/work_units/_show_component.html.erb  |    8 +-
 doc/_includes/_install_ruby_and_bundler.liquid     |   10 +-
 doc/admin/upgrading.html.textile.liquid            |   15 +-
 doc/admin/user-management-cli.html.textile.liquid  |   46 +
 doc/api/methods/links.html.textile.liquid          |   22 +-
 lib/cloud/cloudtest/tester.go                      |    3 +-
 lib/config/config.default.yml                      |   14 +
 lib/config/export.go                               |    1 +
 lib/config/generated_config.go                     |   14 +
 lib/controller/federation/login_test.go            |    2 -
 lib/controller/forecast/controller_test.go         |   44 +-
 lib/controller/localdb/login.go                    |   21 +-
 lib/crunchrun/logging.go                           |    3 +-
 lib/install/deps.go                                |    5 +
 sdk/R/DESCRIPTION                                  |    6 +-
 sdk/R/R/Arvados.R                                  | 4821 +++++++-------------
 sdk/R/R/ArvadosFile.R                              |    2 -
 sdk/R/R/Collection.R                               |    5 -
 sdk/R/R/CollectionTree.R                           |    4 -
 sdk/R/R/HttpParser.R                               |    5 +-
 sdk/R/R/HttpRequest.R                              |    4 +-
 sdk/R/R/RESTService.R                              |   15 +-
 sdk/R/R/Subcollection.R                            |    2 -
 sdk/R/R/autoGenAPI.R                               |   12 +-
 sdk/R/README.Rmd                                   |    2 +-
 sdk/R/tests/testthat/test-ArvadosFile.R            |   12 +-
 sdk/R/tests/testthat/test-Collection.R             |   22 +-
 sdk/R/tests/testthat/test-CollectionTree.R         |   22 +-
 sdk/R/tests/testthat/test-HttpParser.R             |    8 +-
 sdk/R/tests/testthat/test-HttpRequest.R            |   14 +-
 sdk/R/tests/testthat/test-RESTService.R            |   54 +-
 sdk/R/tests/testthat/test-Subcollection.R          |   28 +-
 sdk/cwl/arvados_cwl/__init__.py                    |    4 +
 sdk/cwl/arvados_cwl/arvcontainer.py                |    5 +-
 sdk/cwl/arvados_cwl/executor.py                    |    2 +
 sdk/cwl/tests/test_submit.py                       |   33 +-
 sdk/dev-jobs.dockerfile                            |    6 +-
 sdk/go/arvados/config.go                           |    1 +
 sdk/go/arvados/fs_base.go                          |    3 +-
 sdk/go/arvados/fs_collection.go                    |   20 +-
 sdk/go/health/handler_test.go                      |    3 +-
 sdk/go/httpserver/logger.go                        |    3 +-
 sdk/go/keepclient/keepclient.go                    |    5 +-
 sdk/python/arvados/commands/run.py                 |    2 +-
 .../arvados/v1/collections_controller.rb           |   13 +-
 .../app/controllers/arvados/v1/users_controller.rb |    2 +-
 services/api/app/models/arvados_model.rb           |    7 +-
 services/api/app/models/database_seeds.rb          |   21 +-
 .../views/user_notifier/account_is_setup.text.erb  |   15 +-
 .../20200914203202_public_favorites_project.rb     |   23 +
 services/api/db/structure.sql                      |    3 +-
 services/api/lib/current_api_client.rb             |   33 +
 services/api/test/fixtures/groups.yml              |    7 +
 services/api/test/fixtures/links.yml               |   14 +
 services/api/test/fixtures/logs.yml                |   17 +-
 .../arvados/v1/collections_controller_test.rb      |   10 +
 .../functional/arvados/v1/users_controller_test.rb |   17 +
 services/api/test/unit/log_test.rb                 |   35 +-
 services/api/test/unit/permission_test.rb          |   20 +
 services/api/test/unit/user_notifier_test.rb       |   18 +
 services/keep-web/s3.go                            |    3 +
 services/keep-web/s3_test.go                       |   16 +
 tools/arvbox/bin/arvbox                            |  272 +-
 tools/arvbox/lib/arvbox/docker/Dockerfile.base     |  171 +-
 tools/arvbox/lib/arvbox/docker/Dockerfile.demo     |    9 +-
 tools/arvbox/lib/arvbox/docker/Dockerfile.dev      |    8 +-
 tools/arvbox/lib/arvbox/docker/api-setup.sh        |   32 +-
 tools/arvbox/lib/arvbox/docker/cluster-config.sh   |   97 +-
 tools/arvbox/lib/arvbox/docker/common.sh           |   32 +-
 tools/arvbox/lib/arvbox/docker/createusers.sh      |   22 +-
 tools/arvbox/lib/arvbox/docker/devenv.sh           |    3 +-
 tools/arvbox/lib/arvbox/docker/go-setup.sh         |    8 +-
 tools/arvbox/lib/arvbox/docker/keep-setup.sh       |   20 +-
 tools/arvbox/lib/arvbox/docker/runit/2             |    2 +-
 tools/arvbox/lib/arvbox/docker/runsu.sh            |    6 +-
 .../lib/arvbox/docker/service/api/run-service      |    6 +-
 .../docker/service/arv-git-httpd/run-service       |    2 +-
 .../lib/arvbox/docker/service/certificate/run      |    8 +-
 .../lib/arvbox/docker/service/controller/run       |    2 +-
 .../service/crunch-dispatch-local/run-service      |    2 +-
 .../lib/arvbox/docker/service/gitolite/run-service |   34 +-
 .../arvbox/docker/service/keepproxy/run-service    |    8 +-
 tools/arvbox/lib/arvbox/docker/service/nginx/run   |    6 +-
 .../arvbox/lib/arvbox/docker/service/postgres/run  |    3 +-
 .../lib/arvbox/docker/service/postgres/run-service |    3 +-
 .../lib/arvbox/docker/service/ready/run-service    |    8 +-
 .../lib/arvbox/docker/service/sdk/run-service      |   14 -
 tools/arvbox/lib/arvbox/docker/service/vm/run      |    4 +-
 .../lib/arvbox/docker/service/vm/run-service       |    4 +-
 .../lib/arvbox/docker/service/websockets/run       |    2 +-
 .../arvbox/lib/arvbox/docker/service/workbench/run |    8 +-
 .../arvbox/docker/service/workbench/run-service    |    6 +-
 .../arvbox/docker/service/workbench2/run-service   |    2 +-
 tools/arvbox/lib/arvbox/docker/waitforpostgres.sh  |    2 +-
 95 files changed, 2535 insertions(+), 3880 deletions(-)
 create mode 100644 services/api/db/migrate/20200914203202_public_favorites_project.rb

       via  5846dac43b981975bf8d99c393f95e4df2a7135e (commit)
       via  9065e5d5afed21f0ce775ab8460e06c762b8eede (commit)
       via  9d3a2d4fcff119b03d2e08ad85917157718c13c9 (commit)
       via  9157ec5393fce29c7f590fce69c67dcc9b73c4e2 (commit)
       via  8e8c00654cd0fddf209619da5bb466a58d45596a (commit)
       via  b8ba3b96b02a1d95f82231e480528c8d4388523f (commit)
       via  3a55fcf94b21b1787200c4f097b54a2dcc9ed771 (commit)
       via  8bc01b789403674e8cb9a0a633bbd27301c1c545 (commit)
       via  82f68baf6fc1eb6e52133354a60d4fea84412178 (commit)
       via  6c2ce5d60f40cc58bc0c7b05f551d6d00806672b (commit)
       via  0f270e0afe5cc3bd01af43d6406efbb60479fbf7 (commit)
       via  cef00a8331c41690e17f3ca0c7a1a51c06ca1cb7 (commit)
       via  5ba3cdd24b371422d7a2de97d452b8b6537ac0ec (commit)
       via  4a2b3c38abb28679835201ff98853b0d8879ab5e (commit)
       via  9bca41a9ba41fe4c03f24b32b2c484941793f529 (commit)
       via  76773b0a65a05c2a6356e53f939b17a5e5fa1f21 (commit)
       via  59a265f9b4ed03552711457484ae8a28ae972b26 (commit)
       via  1348641c7bdd8b3f8a03577b13349aa1c1de5be1 (commit)
       via  2b5431b453c81536dd3ba487ffc201540ab72876 (commit)
       via  ee2d76e5ca4b3da4869d0db9fd68212a781deba0 (commit)
       via  161999468e2c6e823fa488c667353d138d8f155d (commit)
       via  78ea5727119d2c29d14fd395f2297b3d0db17405 (commit)
       via  72c368cb5016dab37554756fcbb6e30e17357126 (commit)
       via  4053029e959bc5857f95542b9da464351289a35c (commit)
       via  6ae66e2b611eeab0697d822bbdaa2dccbd1f3c77 (commit)
       via  4e636294758928a3477da4d4d746677388dab69b (commit)
       via  9ce48534a58022505aac8fb0879a4d5fbf5ef156 (commit)
       via  c037735e0529c4ff605d90cdae5079200e258270 (commit)
       via  58ac679391b0fef4b8dcdc00f90c08cdded6e705 (commit)
       via  10e3554400dfae1d8e6fe58cd78f46b0a60f86be (commit)
       via  cf07c5549bb73b9fdefee7dd266f627dd4d62b47 (commit)
       via  22d03e114e25c7076185fba36a912766c49a9ed4 (commit)
       via  0c9f79dd67d7abce9b533d0dc90693619a9fc6b9 (commit)
       via  cfb21c7d76b0961afb920a1c4ec0b2d29f1b21d3 (commit)
      from  0c302f311fb85bbb53f7a8132e1654f94de96a02 (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 5846dac43b981975bf8d99c393f95e4df2a7135e
Author: Nico Cesar <nico at nicocesar.com>
Date:   Tue Sep 29 14:58:48 2020 -0400

    circular dependencies, trying to get a real connection
    
    refs #16462
    
    Arvados-DCO-1.1-Signed-off-by: Nico Cesar <nico at curii.com>

diff --git a/lib/controller/forecast/controller_test.go b/lib/controller/forecast/controller_test.go
index 6f0a81d9e..e0be2705f 100644
--- a/lib/controller/forecast/controller_test.go
+++ b/lib/controller/forecast/controller_test.go
@@ -6,9 +6,12 @@ package forecast
 
 import (
 	"context"
+	"os"
+	"path/filepath"
 	"testing"
+	"time"
 
-	"git.arvados.org/arvados.git/lib/config"
+	"git.arvados.org/arvados.git/lib/controller/localdb"
 	"git.arvados.org/arvados.git/sdk/go/arvados"
 	"git.arvados.org/arvados.git/sdk/go/arvadostest"
 	"git.arvados.org/arvados.git/sdk/go/ctxlog"
@@ -30,14 +33,38 @@ type ForecastSuite struct {
 	rollback func()
 }
 
+func integrationTestCluster() *arvados.Cluster {
+	cfg, err := arvados.GetConfig(filepath.Join(os.Getenv("WORKSPACE"), "tmp", "arvados.yml"))
+	if err != nil {
+		panic(err)
+	}
+	cc, err := cfg.GetCluster("zzzzz")
+	if err != nil {
+		panic(err)
+	}
+	return cc
+}
+
 func (s *ForecastSuite) SetUpTest(c *check.C) {
-	cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
-	c.Assert(err, check.IsNil)
-	cluster, err := cfg.GetCluster("")
-	c.Assert(err, check.IsNil)
-	s.ctx, s.rollback = arvadostest.TransactionContext(c, arvadostest.DB(c, cluster))
-	s.stub = &arvadostest.APIStub{}
-	s.ctrl = New(cluster, s.stub)
+	s.ctx = context.Background()
+	s.ctx = ctxlog.Context(s.ctx, ctxlog.New(os.Stderr, "json", "debug"))
+	cluster := &arvados.Cluster{
+		ClusterID:  "zzzzz",
+		PostgreSQL: integrationTestCluster().PostgreSQL,
+		//ForceLegacyAPI14: forceLegacyAPI14,
+	}
+	cluster.API.RequestTimeout = arvados.Duration(5 * time.Minute)
+	cluster.TLS.Insecure = true
+	arvadostest.SetServiceURL(&cluster.Services.RailsAPI, "https://"+os.Getenv("ARVADOS_TEST_API_HOST"))
+	arvadostest.SetServiceURL(&cluster.Services.Controller, "http://localhost:/")
+	//s.handler = newHandler(s.ctx, s.cluster, "", prometheus.NewRegistry())
+
+	//cfg, err := config.NewLoader(nil, ctxlog.TestLogger(c)).Load()
+	//c.Assert(err, check.IsNil)
+	//s.ctx, s.rollback = arvadostest.TransactionContext(c, arvadostest.DB(c, cluster))
+	//s.stub = &arvadostest.APIStub{}
+
+	s.ctrl = New(cluster, localdb.NewConn(cluster))
 }
 
 func (s *ForecastSuite) TearDownTest(c *check.C) {
@@ -56,6 +83,7 @@ func (s *ForecastSuite) TestDatapoints(c *check.C) {
 	// zzzzz-xvhdp-p1i7h1gy5z1ft4p is hasher_root from services/api/test/fixtures/container_requests.yml
 	// if we have a better way to address fixture content in controller we should replace this hardcoded value
 	resp, err := s.ctrl.ForecastDatapoints(s.ctx, arvados.GetOptions{UUID: "zzzzz-xvhdp-p1i7h1gy5z1ft4p"})
+	c.Error(s.ctrl.parent.ContainerRequestGet(context.Background(), arvados.GetOptions{UUID: "zzzzz-xvhdp-p1i7h1gy5z1ft4p"}))
 	c.Check(err, check.IsNil)
 	c.Check(len(resp.Datapoints), check.Equals, 3)
 	//c.Check(s.stub.Calls(s.stub.UserList), check.HasLen, 1)

commit 9065e5d5afed21f0ce775ab8460e06c762b8eede
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 28 14:43:05 2020 -0400

    16913: Add upgrade note about LoginCluster
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/doc/admin/upgrading.html.textile.liquid b/doc/admin/upgrading.html.textile.liquid
index 1eb2468c3..de700d559 100644
--- a/doc/admin/upgrading.html.textile.liquid
+++ b/doc/admin/upgrading.html.textile.liquid
@@ -35,10 +35,14 @@ TODO: extract this information based on git commit messages and generate changel
 <div class="releasenotes">
 </notextile>
 
-h2(#master). development master (as of 2020-09-22)
+h2(#master). development master (as of 2020-09-28)
 
 "Upgrading from 2.0.0":#v2_0_0
 
+h3. LoginCluster conflicts with other Login providers
+
+A satellite cluster that delegates its user login to a central user database must only have `Login.LoginCluster` set, or it will return an error.  This is a change in behavior, previously it would return an error if another login provider was _not_ configured, even though the provider would never be used.
+
 h3. Minimum supported Ruby version is now 2.5
 
 The minimum supported Ruby version is now 2.5.  If you are running Arvados on Debian 9 or Ubuntu 16.04, you may need to switch to using RVM or upgrade your OS.  See "Install Ruby and Bundler":../install/ruby.html for more information.

commit 9d3a2d4fcff119b03d2e08ad85917157718c13c9
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 28 14:28:18 2020 -0400

    16913: Treat LoginCluster as a distinct login method.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/lib/controller/federation/login_test.go b/lib/controller/federation/login_test.go
index ad91bcf80..007f5df8b 100644
--- a/lib/controller/federation/login_test.go
+++ b/lib/controller/federation/login_test.go
@@ -43,8 +43,6 @@ func (s *LoginSuite) TestDeferToLoginCluster(c *check.C) {
 func (s *LoginSuite) TestLogout(c *check.C) {
 	s.cluster.Services.Workbench1.ExternalURL = arvados.URL{Scheme: "https", Host: "workbench1.example.com"}
 	s.cluster.Services.Workbench2.ExternalURL = arvados.URL{Scheme: "https", Host: "workbench2.example.com"}
-	s.cluster.Login.Google.Enable = true
-	s.cluster.Login.Google.ClientID = "zzzzzzzzzzzzzz"
 	s.addHTTPRemote(c, "zhome", &arvadostest.APIStub{})
 	s.cluster.Login.LoginCluster = "zhome"
 	// s.fed is already set by SetUpTest, but we need to
diff --git a/lib/controller/localdb/login.go b/lib/controller/localdb/login.go
index 126741484..bbed47c73 100644
--- a/lib/controller/localdb/login.go
+++ b/lib/controller/localdb/login.go
@@ -34,10 +34,11 @@ func chooseLoginController(cluster *arvados.Cluster, railsProxy *railsProxy) log
 	wantPAM := cluster.Login.PAM.Enable
 	wantLDAP := cluster.Login.LDAP.Enable
 	wantTest := cluster.Login.Test.Enable
+	wantLoginCluster := cluster.Login.LoginCluster != "" && cluster.Login.LoginCluster != cluster.ClusterID
 	switch {
-	case 1 != countTrue(wantGoogle, wantOpenIDConnect, wantSSO, wantPAM, wantLDAP, wantTest):
+	case 1 != countTrue(wantGoogle, wantOpenIDConnect, wantSSO, wantPAM, wantLDAP, wantTest, wantLoginCluster):
 		return errorLoginController{
-			error: errors.New("configuration problem: exactly one of Login.Google, Login.OpenIDConnect, Login.SSO, Login.PAM, Login.LDAP, and Login.Test must be enabled"),
+			error: errors.New("configuration problem: exactly one of Login.Google, Login.OpenIDConnect, Login.SSO, Login.PAM, Login.LDAP, Login.Test, or Login.LoginCluster must be set"),
 		}
 	case wantGoogle:
 		return &oidcLoginController{
@@ -69,6 +70,8 @@ func chooseLoginController(cluster *arvados.Cluster, railsProxy *railsProxy) log
 		return &ldapLoginController{Cluster: cluster, RailsProxy: railsProxy}
 	case wantTest:
 		return &testLoginController{Cluster: cluster, RailsProxy: railsProxy}
+	case wantLoginCluster:
+		return &federatedLoginController{Cluster: cluster}
 	default:
 		return errorLoginController{
 			error: errors.New("BUG: missing case in login controller setup switch"),
@@ -106,6 +109,20 @@ func (ctrl errorLoginController) UserAuthenticate(context.Context, arvados.UserA
 	return arvados.APIClientAuthorization{}, ctrl.error
 }
 
+type federatedLoginController struct {
+	Cluster *arvados.Cluster
+}
+
+func (ctrl federatedLoginController) Login(context.Context, arvados.LoginOptions) (arvados.LoginResponse, error) {
+	return arvados.LoginResponse{}, httpserver.ErrorWithStatus(errors.New("Should have been redirected to login cluster"), http.StatusBadRequest)
+}
+func (ctrl federatedLoginController) Logout(_ context.Context, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
+	return noopLogout(ctrl.Cluster, opts)
+}
+func (ctrl federatedLoginController) UserAuthenticate(context.Context, arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) {
+	return arvados.APIClientAuthorization{}, httpserver.ErrorWithStatus(errors.New("username/password authentication is not available"), http.StatusBadRequest)
+}
+
 func noopLogout(cluster *arvados.Cluster, opts arvados.LogoutOptions) (arvados.LogoutResponse, error) {
 	target := opts.ReturnTo
 	if target == "" {

commit 9157ec5393fce29c7f590fce69c67dcc9b73c4e2
Author: Ward Vandewege <ward at curii.com>
Date:   Sun Sep 27 22:16:48 2020 -0400

    Fix more golint warnings.
    
    No issue #
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/lib/crunchrun/logging.go b/lib/crunchrun/logging.go
index d5de184e5..febfb1404 100644
--- a/lib/crunchrun/logging.go
+++ b/lib/crunchrun/logging.go
@@ -368,9 +368,8 @@ func (arvlog *ArvLogWriter) rateLimit(line []byte, now time.Time) (bool, []byte)
 		// instead of the log message that exceeded the limit.
 		message += " A complete log is still being written to Keep, and will be available when the job finishes."
 		return true, []byte(message)
-	} else {
-		return arvlog.logThrottleIsOpen, line
 	}
+	return arvlog.logThrottleIsOpen, line
 }
 
 // load the rate limit discovery config parameters
diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go
index 5e57fed3b..aa75fee7c 100644
--- a/sdk/go/arvados/fs_base.go
+++ b/sdk/go/arvados/fs_base.go
@@ -598,9 +598,8 @@ func (fs *fileSystem) remove(name string, recursive bool) error {
 func (fs *fileSystem) Sync() error {
 	if syncer, ok := fs.root.(syncer); ok {
 		return syncer.Sync()
-	} else {
-		return ErrInvalidOperation
 	}
+	return ErrInvalidOperation
 }
 
 func (fs *fileSystem) Flush(string, bool) error {
diff --git a/sdk/go/arvados/fs_collection.go b/sdk/go/arvados/fs_collection.go
index 060b57b49..d4429f5d7 100644
--- a/sdk/go/arvados/fs_collection.go
+++ b/sdk/go/arvados/fs_collection.go
@@ -109,16 +109,15 @@ func (fs *collectionFileSystem) newNode(name string, perm os.FileMode, modTime t
 				inodes: make(map[string]inode),
 			},
 		}, nil
-	} else {
-		return &filenode{
-			fs: fs,
-			fileinfo: fileinfo{
-				name:    name,
-				mode:    perm & ^os.ModeDir,
-				modTime: modTime,
-			},
-		}, nil
 	}
+	return &filenode{
+		fs: fs,
+		fileinfo: fileinfo{
+			name:    name,
+			mode:    perm & ^os.ModeDir,
+			modTime: modTime,
+		},
+	}, nil
 }
 
 func (fs *collectionFileSystem) Child(name string, replace func(inode) (inode, error)) (inode, error) {
@@ -802,9 +801,8 @@ func (dn *dirnode) commitBlock(ctx context.Context, refs []fnSegmentRef, bufsize
 	}()
 	if sync {
 		return <-errs
-	} else {
-		return nil
 	}
+	return nil
 }
 
 type flushOpts struct {
diff --git a/sdk/go/health/handler_test.go b/sdk/go/health/handler_test.go
index c9f6a0b67..097e292d3 100644
--- a/sdk/go/health/handler_test.go
+++ b/sdk/go/health/handler_test.go
@@ -81,9 +81,8 @@ func (s *Suite) TestPingOverride(c *check.C) {
 				ok = !ok
 				if ok {
 					return nil
-				} else {
-					return errors.New("good error")
 				}
+				return errors.New("good error")
 			},
 		},
 	}
diff --git a/sdk/go/httpserver/logger.go b/sdk/go/httpserver/logger.go
index 59981e3e5..5336488df 100644
--- a/sdk/go/httpserver/logger.go
+++ b/sdk/go/httpserver/logger.go
@@ -64,9 +64,8 @@ func rewrapResponseWriter(w http.ResponseWriter, wrapped http.ResponseWriter) ht
 			http.ResponseWriter
 			http.Hijacker
 		}{w, hijacker}
-	} else {
-		return w
 	}
+	return w
 }
 
 func Logger(req *http.Request) logrus.FieldLogger {

commit 8e8c00654cd0fddf209619da5bb466a58d45596a
Author: Ward Vandewege <ward at curii.com>
Date:   Sat Sep 26 22:09:06 2020 -0400

    Fix more golint warnings.
    
    No issue #
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/lib/cloud/cloudtest/tester.go b/lib/cloud/cloudtest/tester.go
index 087aceffa..9fd7c9e74 100644
--- a/lib/cloud/cloudtest/tester.go
+++ b/lib/cloud/cloudtest/tester.go
@@ -150,9 +150,8 @@ func (t *tester) Run() bool {
 			if time.Now().After(bootDeadline) {
 				t.Logger.Error("timed out")
 				return false
-			} else {
-				t.sleepSyncInterval()
 			}
+			t.sleepSyncInterval()
 		}
 		t.Logger.WithField("Instance", t.testInstance.ID()).Info("new instance appeared")
 		t.showLoginInfo()
diff --git a/sdk/go/keepclient/keepclient.go b/sdk/go/keepclient/keepclient.go
index b18d7e046..13f8f9577 100644
--- a/sdk/go/keepclient/keepclient.go
+++ b/sdk/go/keepclient/keepclient.go
@@ -290,10 +290,9 @@ func (kc *KeepClient) getOrHead(method string, locator string, header http.Heade
 					Hash:   md5.New(),
 					Check:  locator[0:32],
 				}, expectLength, url, resp.Header, nil
-			} else {
-				resp.Body.Close()
-				return nil, expectLength, url, resp.Header, nil
 			}
+			resp.Body.Close()
+			return nil, expectLength, url, resp.Header, nil
 		}
 		serversToTry = retryList
 	}

commit b8ba3b96b02a1d95f82231e480528c8d4388523f
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Sep 25 18:04:29 2020 -0400

    16874: Fix test.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/api/test/functional/arvados/v1/users_controller_test.rb b/services/api/test/functional/arvados/v1/users_controller_test.rb
index ea5d5b143..e0f7b8970 100644
--- a/services/api/test/functional/arvados/v1/users_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/users_controller_test.rb
@@ -609,6 +609,23 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
   test "setup user with send notification param true and verify email" do
     authorize_with :admin
 
+    Rails.configuration.Users.UserSetupMailText = %{
+<% if not @user.full_name.empty? -%>
+<%= @user.full_name %>,
+<% else -%>
+Hi there,
+<% end -%>
+
+Your Arvados shell account has been set up. Please visit the virtual machines page <% if Rails.configuration.Services.Workbench1.ExternalURL %>at
+
+<%= Rails.configuration.Services.Workbench1.ExternalURL %><%= "/" if !Rails.configuration.Services.Workbench1.ExternalURL.to_s.end_with?("/") %>users/<%= @user.uuid%>/virtual_machines <% else %><% end %>
+
+for connection instructions.
+
+Thanks,
+The Arvados team.
+}
+
     post :setup, params: {
       send_notification_email: 'true',
       user: {

commit 3a55fcf94b21b1787200c4f097b54a2dcc9ed771
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Sep 25 17:17:06 2020 -0400

    16874: Content of account_is_setup.text.erb uses Users.UserSetupMailText
    
    The most straightforward solution seems to be for UserSetupMailText to
    still be an erb template and is evaluated in the same environment as
    as before, but it gets the code from the config file.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/lib/config/config.default.yml b/lib/config/config.default.yml
index 15e7c7c06..d0338e8c8 100644
--- a/lib/config/config.default.yml
+++ b/lib/config/config.default.yml
@@ -287,6 +287,20 @@ Clusters:
       # address is used.
       PreferDomainForUsername: ""
 
+      UserSetupMailText: |
+        <% if not @user.full_name.empty? -%>
+        <%= @user.full_name %>,
+        <% else -%>
+        Hi there,
+        <% end -%>
+
+        Your Arvados account has been set up.  You can log in at
+
+        <%= Rails.configuration.Services.Workbench1.ExternalURL %>
+
+        Thanks,
+        Your Arvados administrator.
+
     AuditLogs:
       # Time to keep audit logs, in seconds. (An audit log is a row added
       # to the "logs" table in the PostgreSQL database each time an
diff --git a/lib/config/export.go b/lib/config/export.go
index 6ab69d21f..81c6767a1 100644
--- a/lib/config/export.go
+++ b/lib/config/export.go
@@ -214,6 +214,7 @@ var whitelist = map[string]bool{
 	"Users.PreferDomainForUsername":                false,
 	"Users.UserNotifierEmailFrom":                  false,
 	"Users.UserProfileNotificationAddress":         false,
+	"Users.UserSetupMailText":                      false,
 	"Volumes":                                      true,
 	"Volumes.*":                                    true,
 	"Volumes.*.*":                                  false,
diff --git a/lib/config/generated_config.go b/lib/config/generated_config.go
index 7ed332151..88d71eb0a 100644
--- a/lib/config/generated_config.go
+++ b/lib/config/generated_config.go
@@ -293,6 +293,20 @@ Clusters:
       # address is used.
       PreferDomainForUsername: ""
 
+      UserSetupMailText: |
+        <% if not @user.full_name.empty? -%>
+        <%= @user.full_name %>,
+        <% else -%>
+        Hi there,
+        <% end -%>
+
+        Your Arvados account has been set up.  You can log in at
+
+        <%= Rails.configuration.Services.Workbench1.ExternalURL %>
+
+        Thanks,
+        Your Arvados administrator.
+
     AuditLogs:
       # Time to keep audit logs, in seconds. (An audit log is a row added
       # to the "logs" table in the PostgreSQL database each time an
diff --git a/sdk/go/arvados/config.go b/sdk/go/arvados/config.go
index 394e30a73..00438bf34 100644
--- a/sdk/go/arvados/config.go
+++ b/sdk/go/arvados/config.go
@@ -219,6 +219,7 @@ type Cluster struct {
 		UserNotifierEmailFrom                 string
 		UserProfileNotificationAddress        string
 		PreferDomainForUsername               string
+		UserSetupMailText                     string
 	}
 	Volumes   map[string]Volume
 	Workbench struct {
diff --git a/services/api/app/controllers/arvados/v1/users_controller.rb b/services/api/app/controllers/arvados/v1/users_controller.rb
index cd23706d0..76e8da0c7 100644
--- a/services/api/app/controllers/arvados/v1/users_controller.rb
+++ b/services/api/app/controllers/arvados/v1/users_controller.rb
@@ -135,7 +135,7 @@ class Arvados::V1::UsersController < ApplicationController
                               vm_uuid: params[:vm_uuid])
 
     # setup succeeded. send email to user
-    if params[:send_notification_email]
+    if params[:send_notification_email] && !Rails.configuration.Users.UserSetupMailText.empty?
       begin
         UserNotifier.account_is_setup(@object).deliver_now
       rescue => e
diff --git a/services/api/app/views/user_notifier/account_is_setup.text.erb b/services/api/app/views/user_notifier/account_is_setup.text.erb
index 50d164bfa..352ee7754 100644
--- a/services/api/app/views/user_notifier/account_is_setup.text.erb
+++ b/services/api/app/views/user_notifier/account_is_setup.text.erb
@@ -2,17 +2,4 @@
 
 SPDX-License-Identifier: AGPL-3.0 %>
 
-<% if not @user.full_name.empty? -%>
-<%= @user.full_name %>,
-<% else -%>
-Hi there,
-<% end -%>
-
-Your Arvados shell account has been set up. Please visit the virtual machines page <% if Rails.configuration.Services.Workbench1.ExternalURL %>at
-
-  <%= Rails.configuration.Services.Workbench1.ExternalURL %><%= "/" if !Rails.configuration.Services.Workbench1.ExternalURL.to_s.end_with?("/") %>users/<%= @user.uuid%>/virtual_machines <% else %><% end %>
-
-for connection instructions.
-
-Thanks,
-The Arvados team.
+<%= ERB.new(Rails.configuration.Users.UserSetupMailText, 0, "-").result(binding) %>
diff --git a/services/api/test/unit/user_notifier_test.rb b/services/api/test/unit/user_notifier_test.rb
index da6c7fdb8..c288786c1 100644
--- a/services/api/test/unit/user_notifier_test.rb
+++ b/services/api/test/unit/user_notifier_test.rb
@@ -9,6 +9,24 @@ class UserNotifierTest < ActionMailer::TestCase
   # Send the email, then test that it got queued
   test "account is setup" do
     user = users :active
+
+    Rails.configuration.Users.UserSetupMailText = %{
+<% if not @user.full_name.empty? -%>
+<%= @user.full_name %>,
+<% else -%>
+Hi there,
+<% end -%>
+
+Your Arvados shell account has been set up. Please visit the virtual machines page <% if Rails.configuration.Services.Workbench1.ExternalURL %>at
+
+<%= Rails.configuration.Services.Workbench1.ExternalURL %><%= "/" if !Rails.configuration.Services.Workbench1.ExternalURL.to_s.end_with?("/") %>users/<%= @user.uuid%>/virtual_machines <% else %><% end %>
+
+for connection instructions.
+
+Thanks,
+The Arvados team.
+}
+
     email = UserNotifier.account_is_setup user
 
     assert_not_nil email

commit 8bc01b789403674e8cb9a0a633bbd27301c1c545
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Sep 25 11:46:36 2020 -0400

    16825: Document deleting token at the CLI
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/doc/admin/user-management-cli.html.textile.liquid b/doc/admin/user-management-cli.html.textile.liquid
index 689217660..8cebf02cd 100644
--- a/doc/admin/user-management-cli.html.textile.liquid
+++ b/doc/admin/user-management-cli.html.textile.liquid
@@ -85,6 +85,52 @@ To get the token string, combine the values of @uuid@ and @api_token@ in the for
 ARVADOS_API_TOKEN=v2/zzzzz-gj3su-yyyyyyyyyyyyyyy/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 </pre>
 
+h3(#delete-token). Delete a token
+
+If you need to revoke a token, for example the token is leaked to an unauthorized party, you can delete the token at the command line.
+
+1. First, determine the token UUID.  If it is a "v2" format token (starts with "v2/") then the token UUID is middle section between the two slashes.   For example:
+
+<pre>
+v2/zzzzz-gj3su-yyyyyyyyyyyyyyy/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+</pre>
+
+the UUID is "zzzzz-gj3su-yyyyyyyyyyyyyyy" and you can skip to the next step.
+
+If you have a "bare" token (only the secret part) then, as an admin, you need to query the token to get the uuid:
+
+<pre>
+$ ARVADOS_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx arv api_client_authorization current
+{
+ "href":"/api_client_authorizations/x33hz-gj3su-fk8nbj4byptz6ma",
+ "kind":"arvados#apiClientAuthorization",
+ "etag":"77wktnitqeelbgb4riv84zi2q",
+ "uuid":"zzzzz-gj3su-yyyyyyyyyyyyyyy",
+ "owner_uuid":"zzzzz-tpzed-j8w1ymjsn4vf4v4",
+ "created_at":"2020-09-25T15:19:48.606984000Z",
+ "modified_by_client_uuid":null,
+ "modified_by_user_uuid":null,
+ "modified_at":null,
+ "user_id":3,
+ "api_client_id":1,
+ "api_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ "created_by_ip_address":null,
+ "default_owner_uuid":null,
+ "expires_at":null,
+ "last_used_at":null,
+ "last_used_by_ip_address":null,
+ "scopes":[
+  "all"
+ ]
+}
+</pre>
+
+2. Now use the token to delete itself:
+
+<pre>
+$ ARVADOS_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx arv api_client_authorization delete --uuid zzzzz-gj3su-yyyyyyyyyyyyyyy
+</pre>
+
 h2. Adding Permissions
 
 h3. VM login

commit 82f68baf6fc1eb6e52133354a60d4fea84412178
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Sep 25 11:07:02 2020 -0400

    Recommend installing R package from https refs #16885
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/R/README.Rmd b/sdk/R/README.Rmd
index c1d6c7cf4..63bf55373 100644
--- a/sdk/R/README.Rmd
+++ b/sdk/R/README.Rmd
@@ -14,7 +14,7 @@ knitr::opts_chunk$set(eval=FALSE)
 ```
 
 ```{r}
-install.packages("ArvadosR", repos=c("http://r.arvados.org", getOption("repos")["CRAN"]), dependencies=TRUE)
+install.packages("ArvadosR", repos=c("https://r.arvados.org", getOption("repos")["CRAN"]), dependencies=TRUE)
 ```
 
 Note: on Linux, you may have to install supporting packages.

commit 6c2ce5d60f40cc58bc0c7b05f551d6d00806672b
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Wed Sep 23 17:50:14 2020 -0400

    16827: Don't append '/' to requests with query params.  Bump version
    
    Also remove package-cross loading with "source" that generated warnings.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/R/DESCRIPTION b/sdk/R/DESCRIPTION
index 878a70901..75ac892b4 100644
--- a/sdk/R/DESCRIPTION
+++ b/sdk/R/DESCRIPTION
@@ -1,9 +1,9 @@
 Package: ArvadosR
 Type: Package
 Title: Arvados R SDK
-Version: 0.0.5
-Authors at R: person("Fuad", "Muhic", role = c("aut", "cre"), email = "fmuhic at capeannenterprises.com")
-Maintainer: Ward Vandewege <wvandewege at veritasgenetics.com>
+Version: 0.0.6
+Authors at R: c(person("Fuad", "Muhic", role = c("aut", "ctr"), email = "fmuhic at capeannenterprises.com"),
+             person("Peter", "Amstutz", role = c("cre"), email = "peter.amstutz at curii.com"))
 Description: This is the Arvados R SDK
 URL: http://doc.arvados.org
 License: Apache-2.0
diff --git a/sdk/R/R/ArvadosFile.R b/sdk/R/R/ArvadosFile.R
index 70bb4450e..fb1d3b335 100644
--- a/sdk/R/R/ArvadosFile.R
+++ b/sdk/R/R/ArvadosFile.R
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-source("./R/util.R")
-
 #' ArvadosFile
 #'
 #' ArvadosFile class represents a file inside Arvados collection.
diff --git a/sdk/R/R/Collection.R b/sdk/R/R/Collection.R
index 8869d7be6..144083654 100644
--- a/sdk/R/R/Collection.R
+++ b/sdk/R/R/Collection.R
@@ -2,11 +2,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-source("./R/Subcollection.R")
-source("./R/ArvadosFile.R")
-source("./R/RESTService.R")
-source("./R/util.R")
-
 #' Collection
 #'
 #' Collection class provides interface for working with Arvados collections.
diff --git a/sdk/R/R/CollectionTree.R b/sdk/R/R/CollectionTree.R
index 5f7a29455..e01e7e8de 100644
--- a/sdk/R/R/CollectionTree.R
+++ b/sdk/R/R/CollectionTree.R
@@ -2,10 +2,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-source("./R/Subcollection.R")
-source("./R/ArvadosFile.R")
-source("./R/util.R")
-
 CollectionTree <- R6::R6Class(
     "CollectionTree",
     public = list(
diff --git a/sdk/R/R/HttpRequest.R b/sdk/R/R/HttpRequest.R
index 07defca90..18b36f968 100644
--- a/sdk/R/R/HttpRequest.R
+++ b/sdk/R/R/HttpRequest.R
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-source("./R/util.R")
-
 HttpRequest <- R6::R6Class(
 
     "HttrRequest",
@@ -54,7 +52,7 @@ HttpRequest <- R6::R6Class(
             {
                 query <- paste0(names(query), "=", query, collapse = "&")
 
-                return(paste0("/?", query))
+                return(paste0("?", query))
             }
 
             return("")
diff --git a/sdk/R/R/Subcollection.R b/sdk/R/R/Subcollection.R
index 17a9ef3ee..981bd687a 100644
--- a/sdk/R/R/Subcollection.R
+++ b/sdk/R/R/Subcollection.R
@@ -2,8 +2,6 @@
 #
 # SPDX-License-Identifier: Apache-2.0
 
-source("./R/util.R")
-
 #' Subcollection
 #'
 #' Subcollection class represents a folder inside Arvados collection.
diff --git a/sdk/R/tests/testthat/test-HttpRequest.R b/sdk/R/tests/testthat/test-HttpRequest.R
index eb58d033b..c1b6f1039 100644
--- a/sdk/R/tests/testthat/test-HttpRequest.R
+++ b/sdk/R/tests/testthat/test-HttpRequest.R
@@ -20,7 +20,7 @@ test_that("createQuery generates and encodes query portion of http", {
     queryParams$limit <- 20
     queryParams$offset <- 50
     expect_that(http$createQuery(queryParams),
-                equals(paste0("/?filters=%5B%5B%22color%22%2C%22%3D%22%2C%22red",
+                equals(paste0("?filters=%5B%5B%22color%22%2C%22%3D%22%2C%22red",
                               "%22%5D%5D&limit=20&offset=50")))
 })
 

commit 0f270e0afe5cc3bd01af43d6406efbb60479fbf7
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Wed Sep 23 16:40:55 2020 -0400

    16827: Update the generated API to Arvados 2.0
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/R/R/Arvados.R b/sdk/R/R/Arvados.R
index 744cb3c29..528a60665 100644
--- a/sdk/R/R/Arvados.R
+++ b/sdk/R/R/Arvados.R
@@ -1,130 +1,60 @@
-#' users.get
-#' 
-#' users.get is a method defined in Arvados class.
-#' 
-#' @usage arv$users.get(uuid)
-#' @param uuid The UUID of the User in question.
-#' @return User object.
-#' @name users.get
-NULL
-
-#' users.create
-#' 
-#' users.create is a method defined in Arvados class.
-#' 
-#' @usage arv$users.create(user, ensure_unique_name = "false")
-#' @param user User object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return User object.
-#' @name users.create
-NULL
-
-#' users.update
-#' 
-#' users.update is a method defined in Arvados class.
-#' 
-#' @usage arv$users.update(user, uuid)
-#' @param user User object.
-#' @param uuid The UUID of the User in question.
-#' @return User object.
-#' @name users.update
-NULL
-
-#' users.delete
-#' 
-#' users.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$users.delete(uuid)
-#' @param uuid The UUID of the User in question.
-#' @return User object.
-#' @name users.delete
-NULL
-
-#' users.current
-#' 
-#' users.current is a method defined in Arvados class.
-#' 
-#' @usage arv$users.current(NULL)
-#' @return User object.
-#' @name users.current
-NULL
-
-#' users.system
-#' 
-#' users.system is a method defined in Arvados class.
-#' 
-#' @usage arv$users.system(NULL)
-#' @return User object.
-#' @name users.system
-NULL
-
-#' users.activate
-#' 
-#' users.activate is a method defined in Arvados class.
-#' 
-#' @usage arv$users.activate(uuid)
-#' @param uuid 
-#' @return User object.
-#' @name users.activate
-NULL
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: Apache-2.0
 
-#' users.setup
+#' api_clients.get
 #' 
-#' users.setup is a method defined in Arvados class.
+#' api_clients.get is a method defined in Arvados class.
 #' 
-#' @usage arv$users.setup(user = NULL, openid_prefix = NULL,
-#' 	repo_name = NULL, vm_uuid = NULL, send_notification_email = "false")
-#' @param user 
-#' @param openid_prefix 
-#' @param repo_name 
-#' @param vm_uuid 
-#' @param send_notification_email 
-#' @return User object.
-#' @name users.setup
+#' @usage arv$api_clients.get(uuid)
+#' @param uuid The UUID of the ApiClient in question.
+#' @return ApiClient object.
+#' @name api_clients.get
 NULL
 
-#' users.unsetup
+#' api_clients.create
 #' 
-#' users.unsetup is a method defined in Arvados class.
+#' api_clients.create is a method defined in Arvados class.
 #' 
-#' @usage arv$users.unsetup(uuid)
-#' @param uuid 
-#' @return User object.
-#' @name users.unsetup
+#' @usage arv$api_clients.create(apiclient,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param apiClient ApiClient object.
+#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return ApiClient object.
+#' @name api_clients.create
 NULL
 
-#' users.update_uuid
+#' api_clients.update
 #' 
-#' users.update_uuid is a method defined in Arvados class.
+#' api_clients.update is a method defined in Arvados class.
 #' 
-#' @usage arv$users.update_uuid(uuid, new_uuid)
-#' @param uuid 
-#' @param new_uuid 
-#' @return User object.
-#' @name users.update_uuid
+#' @usage arv$api_clients.update(apiclient,
+#' 	uuid)
+#' @param apiClient ApiClient object.
+#' @param uuid The UUID of the ApiClient in question.
+#' @return ApiClient object.
+#' @name api_clients.update
 NULL
 
-#' users.merge
+#' api_clients.delete
 #' 
-#' users.merge is a method defined in Arvados class.
+#' api_clients.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$users.merge(new_owner_uuid,
-#' 	new_user_token, redirect_to_new_user = NULL)
-#' @param new_owner_uuid 
-#' @param new_user_token 
-#' @param redirect_to_new_user 
-#' @return User object.
-#' @name users.merge
+#' @usage arv$api_clients.delete(uuid)
+#' @param uuid The UUID of the ApiClient in question.
+#' @return ApiClient object.
+#' @name api_clients.delete
 NULL
 
-#' users.list
+#' api_clients.list
 #' 
-#' users.list is a method defined in Arvados class.
+#' api_clients.list is a method defined in Arvados class.
 #' 
-#' @usage arv$users.list(filters = NULL,
+#' @usage arv$api_clients.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -133,8 +63,10 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return UserList object.
-#' @name users.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return ApiClientList object.
+#' @name api_clients.list
 NULL
 
 #' api_client_authorizations.get
@@ -152,9 +84,10 @@ NULL
 #' api_client_authorizations.create is a method defined in Arvados class.
 #' 
 #' @usage arv$api_client_authorizations.create(apiclientauthorization,
-#' 	ensure_unique_name = "false")
+#' 	ensure_unique_name = "false", cluster_id = NULL)
 #' @param apiClientAuthorization ApiClientAuthorization object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
 #' @return ApiClientAuthorization object.
 #' @name api_client_authorizations.create
 NULL
@@ -209,7 +142,7 @@ NULL
 #' @usage arv$api_client_authorizations.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -218,111 +151,173 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
 #' @return ApiClientAuthorizationList object.
 #' @name api_client_authorizations.list
 NULL
 
-#' containers.get
+#' authorized_keys.get
 #' 
-#' containers.get is a method defined in Arvados class.
+#' authorized_keys.get is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.get(uuid)
-#' @param uuid The UUID of the Container in question.
-#' @return Container object.
-#' @name containers.get
+#' @usage arv$authorized_keys.get(uuid)
+#' @param uuid The UUID of the AuthorizedKey in question.
+#' @return AuthorizedKey object.
+#' @name authorized_keys.get
 NULL
 
-#' containers.create
+#' authorized_keys.create
 #' 
-#' containers.create is a method defined in Arvados class.
+#' authorized_keys.create is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.create(container,
-#' 	ensure_unique_name = "false")
-#' @param container Container object.
+#' @usage arv$authorized_keys.create(authorizedkey,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param authorizedKey AuthorizedKey object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Container object.
-#' @name containers.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return AuthorizedKey object.
+#' @name authorized_keys.create
 NULL
 
-#' containers.update
+#' authorized_keys.update
 #' 
-#' containers.update is a method defined in Arvados class.
+#' authorized_keys.update is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.update(container,
+#' @usage arv$authorized_keys.update(authorizedkey,
 #' 	uuid)
-#' @param container Container object.
-#' @param uuid The UUID of the Container in question.
-#' @return Container object.
-#' @name containers.update
+#' @param authorizedKey AuthorizedKey object.
+#' @param uuid The UUID of the AuthorizedKey in question.
+#' @return AuthorizedKey object.
+#' @name authorized_keys.update
 NULL
 
-#' containers.delete
+#' authorized_keys.delete
 #' 
-#' containers.delete is a method defined in Arvados class.
+#' authorized_keys.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.delete(uuid)
-#' @param uuid The UUID of the Container in question.
-#' @return Container object.
-#' @name containers.delete
+#' @usage arv$authorized_keys.delete(uuid)
+#' @param uuid The UUID of the AuthorizedKey in question.
+#' @return AuthorizedKey object.
+#' @name authorized_keys.delete
 NULL
 
-#' containers.auth
+#' authorized_keys.list
 #' 
-#' containers.auth is a method defined in Arvados class.
+#' authorized_keys.list is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.auth(uuid)
-#' @param uuid 
-#' @return Container object.
-#' @name containers.auth
+#' @usage arv$authorized_keys.list(filters = NULL,
+#' 	where = NULL, order = NULL, select = NULL,
+#' 	distinct = NULL, limit = "100", offset = "0",
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
+#' @param filters 
+#' @param where 
+#' @param order 
+#' @param select 
+#' @param distinct 
+#' @param limit 
+#' @param offset 
+#' @param count 
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return AuthorizedKeyList object.
+#' @name authorized_keys.list
 NULL
 
-#' containers.lock
+#' collections.get
 #' 
-#' containers.lock is a method defined in Arvados class.
+#' collections.get is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.lock(uuid)
-#' @param uuid 
-#' @return Container object.
-#' @name containers.lock
+#' @usage arv$collections.get(uuid)
+#' @param uuid The UUID of the Collection in question.
+#' @return Collection object.
+#' @name collections.get
 NULL
 
-#' containers.unlock
+#' collections.create
 #' 
-#' containers.unlock is a method defined in Arvados class.
+#' collections.create is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.unlock(uuid)
-#' @param uuid 
-#' @return Container object.
-#' @name containers.unlock
+#' @usage arv$collections.create(collection,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param collection Collection object.
+#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Collection object.
+#' @name collections.create
 NULL
 
-#' containers.secret_mounts
+#' collections.update
 #' 
-#' containers.secret_mounts is a method defined in Arvados class.
+#' collections.update is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.secret_mounts(uuid)
-#' @param uuid 
-#' @return Container object.
-#' @name containers.secret_mounts
+#' @usage arv$collections.update(collection,
+#' 	uuid)
+#' @param collection Collection object.
+#' @param uuid The UUID of the Collection in question.
+#' @return Collection object.
+#' @name collections.update
 NULL
 
-#' containers.current
+#' collections.delete
 #' 
-#' containers.current is a method defined in Arvados class.
+#' collections.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.current(NULL)
-#' @return Container object.
-#' @name containers.current
+#' @usage arv$collections.delete(uuid)
+#' @param uuid The UUID of the Collection in question.
+#' @return Collection object.
+#' @name collections.delete
 NULL
 
-#' containers.list
+#' collections.provenance
 #' 
-#' containers.list is a method defined in Arvados class.
+#' collections.provenance is a method defined in Arvados class.
 #' 
-#' @usage arv$containers.list(filters = NULL,
+#' @usage arv$collections.provenance(uuid)
+#' @param uuid 
+#' @return Collection object.
+#' @name collections.provenance
+NULL
+
+#' collections.used_by
+#' 
+#' collections.used_by is a method defined in Arvados class.
+#' 
+#' @usage arv$collections.used_by(uuid)
+#' @param uuid 
+#' @return Collection object.
+#' @name collections.used_by
+NULL
+
+#' collections.trash
+#' 
+#' collections.trash is a method defined in Arvados class.
+#' 
+#' @usage arv$collections.trash(uuid)
+#' @param uuid 
+#' @return Collection object.
+#' @name collections.trash
+NULL
+
+#' collections.untrash
+#' 
+#' collections.untrash is a method defined in Arvados class.
+#' 
+#' @usage arv$collections.untrash(uuid)
+#' @param uuid 
+#' @return Collection object.
+#' @name collections.untrash
+NULL
+
+#' collections.list
+#' 
+#' collections.list is a method defined in Arvados class.
+#' 
+#' @usage arv$collections.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL,
+#' 	include_trash = NULL, include_old_versions = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -331,62 +326,116 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return ContainerList object.
-#' @name containers.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @param include_trash Include collections whose is_trashed attribute is true.
+#' @param include_old_versions Include past collection versions.
+#' @return CollectionList object.
+#' @name collections.list
 NULL
 
-#' api_clients.get
+#' containers.get
 #' 
-#' api_clients.get is a method defined in Arvados class.
+#' containers.get is a method defined in Arvados class.
 #' 
-#' @usage arv$api_clients.get(uuid)
-#' @param uuid The UUID of the ApiClient in question.
-#' @return ApiClient object.
-#' @name api_clients.get
+#' @usage arv$containers.get(uuid)
+#' @param uuid The UUID of the Container in question.
+#' @return Container object.
+#' @name containers.get
 NULL
 
-#' api_clients.create
+#' containers.create
 #' 
-#' api_clients.create is a method defined in Arvados class.
+#' containers.create is a method defined in Arvados class.
 #' 
-#' @usage arv$api_clients.create(apiclient,
-#' 	ensure_unique_name = "false")
-#' @param apiClient ApiClient object.
+#' @usage arv$containers.create(container,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param container Container object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return ApiClient object.
-#' @name api_clients.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Container object.
+#' @name containers.create
 NULL
 
-#' api_clients.update
+#' containers.update
 #' 
-#' api_clients.update is a method defined in Arvados class.
+#' containers.update is a method defined in Arvados class.
 #' 
-#' @usage arv$api_clients.update(apiclient,
+#' @usage arv$containers.update(container,
 #' 	uuid)
-#' @param apiClient ApiClient object.
-#' @param uuid The UUID of the ApiClient in question.
-#' @return ApiClient object.
-#' @name api_clients.update
+#' @param container Container object.
+#' @param uuid The UUID of the Container in question.
+#' @return Container object.
+#' @name containers.update
 NULL
 
-#' api_clients.delete
+#' containers.delete
 #' 
-#' api_clients.delete is a method defined in Arvados class.
+#' containers.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$api_clients.delete(uuid)
-#' @param uuid The UUID of the ApiClient in question.
-#' @return ApiClient object.
-#' @name api_clients.delete
+#' @usage arv$containers.delete(uuid)
+#' @param uuid The UUID of the Container in question.
+#' @return Container object.
+#' @name containers.delete
 NULL
 
-#' api_clients.list
+#' containers.auth
 #' 
-#' api_clients.list is a method defined in Arvados class.
+#' containers.auth is a method defined in Arvados class.
 #' 
-#' @usage arv$api_clients.list(filters = NULL,
+#' @usage arv$containers.auth(uuid)
+#' @param uuid 
+#' @return Container object.
+#' @name containers.auth
+NULL
+
+#' containers.lock
+#' 
+#' containers.lock is a method defined in Arvados class.
+#' 
+#' @usage arv$containers.lock(uuid)
+#' @param uuid 
+#' @return Container object.
+#' @name containers.lock
+NULL
+
+#' containers.unlock
+#' 
+#' containers.unlock is a method defined in Arvados class.
+#' 
+#' @usage arv$containers.unlock(uuid)
+#' @param uuid 
+#' @return Container object.
+#' @name containers.unlock
+NULL
+
+#' containers.secret_mounts
+#' 
+#' containers.secret_mounts is a method defined in Arvados class.
+#' 
+#' @usage arv$containers.secret_mounts(uuid)
+#' @param uuid 
+#' @return Container object.
+#' @name containers.secret_mounts
+NULL
+
+#' containers.current
+#' 
+#' containers.current is a method defined in Arvados class.
+#' 
+#' @usage arv$containers.current(NULL)
+#' @return Container object.
+#' @name containers.current
+NULL
+
+#' containers.list
+#' 
+#' containers.list is a method defined in Arvados class.
+#' 
+#' @usage arv$containers.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -395,8 +444,10 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return ApiClientList object.
-#' @name api_clients.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return ContainerList object.
+#' @name containers.list
 NULL
 
 #' container_requests.get
@@ -414,9 +465,10 @@ NULL
 #' container_requests.create is a method defined in Arvados class.
 #' 
 #' @usage arv$container_requests.create(containerrequest,
-#' 	ensure_unique_name = "false")
+#' 	ensure_unique_name = "false", cluster_id = NULL)
 #' @param containerRequest ContainerRequest object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
 #' @return ContainerRequest object.
 #' @name container_requests.create
 NULL
@@ -450,7 +502,8 @@ NULL
 #' @usage arv$container_requests.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL,
+#' 	include_trash = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -459,62 +512,96 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @param include_trash Include container requests whose owner project is trashed.
 #' @return ContainerRequestList object.
 #' @name container_requests.list
 NULL
 
-#' authorized_keys.get
+#' groups.get
 #' 
-#' authorized_keys.get is a method defined in Arvados class.
+#' groups.get is a method defined in Arvados class.
 #' 
-#' @usage arv$authorized_keys.get(uuid)
-#' @param uuid The UUID of the AuthorizedKey in question.
-#' @return AuthorizedKey object.
-#' @name authorized_keys.get
+#' @usage arv$groups.get(uuid)
+#' @param uuid The UUID of the Group in question.
+#' @return Group object.
+#' @name groups.get
 NULL
 
-#' authorized_keys.create
+#' groups.create
 #' 
-#' authorized_keys.create is a method defined in Arvados class.
+#' groups.create is a method defined in Arvados class.
 #' 
-#' @usage arv$authorized_keys.create(authorizedkey,
-#' 	ensure_unique_name = "false")
-#' @param authorizedKey AuthorizedKey object.
+#' @usage arv$groups.create(group, ensure_unique_name = "false",
+#' 	cluster_id = NULL, async = "false")
+#' @param group Group object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return AuthorizedKey object.
-#' @name authorized_keys.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @param async defer permissions update
+#' @return Group object.
+#' @name groups.create
 NULL
 
-#' authorized_keys.update
+#' groups.update
 #' 
-#' authorized_keys.update is a method defined in Arvados class.
+#' groups.update is a method defined in Arvados class.
 #' 
-#' @usage arv$authorized_keys.update(authorizedkey,
-#' 	uuid)
-#' @param authorizedKey AuthorizedKey object.
-#' @param uuid The UUID of the AuthorizedKey in question.
-#' @return AuthorizedKey object.
-#' @name authorized_keys.update
+#' @usage arv$groups.update(group, uuid,
+#' 	async = "false")
+#' @param group Group object.
+#' @param uuid The UUID of the Group in question.
+#' @param async defer permissions update
+#' @return Group object.
+#' @name groups.update
 NULL
 
-#' authorized_keys.delete
+#' groups.delete
 #' 
-#' authorized_keys.delete is a method defined in Arvados class.
+#' groups.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$authorized_keys.delete(uuid)
-#' @param uuid The UUID of the AuthorizedKey in question.
-#' @return AuthorizedKey object.
-#' @name authorized_keys.delete
+#' @usage arv$groups.delete(uuid)
+#' @param uuid The UUID of the Group in question.
+#' @return Group object.
+#' @name groups.delete
 NULL
 
-#' authorized_keys.list
+#' groups.contents
 #' 
-#' authorized_keys.list is a method defined in Arvados class.
+#' groups.contents is a method defined in Arvados class.
 #' 
-#' @usage arv$authorized_keys.list(filters = NULL,
+#' @usage arv$groups.contents(filters = NULL,
+#' 	where = NULL, order = NULL, distinct = NULL,
+#' 	limit = "100", offset = "0", count = "exact",
+#' 	cluster_id = NULL, bypass_federation = NULL,
+#' 	include_trash = NULL, uuid = NULL, recursive = NULL,
+#' 	include = NULL)
+#' @param filters 
+#' @param where 
+#' @param order 
+#' @param distinct 
+#' @param limit 
+#' @param offset 
+#' @param count 
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @param include_trash Include items whose is_trashed attribute is true.
+#' @param uuid 
+#' @param recursive Include contents from child groups recursively.
+#' @param include Include objects referred to by listed field in "included" (only owner_uuid)
+#' @return Group object.
+#' @name groups.contents
+NULL
+
+#' groups.shared
+#' 
+#' groups.shared is a method defined in Arvados class.
+#' 
+#' @usage arv$groups.shared(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL,
+#' 	include_trash = NULL, include = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -523,102 +610,120 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return AuthorizedKeyList object.
-#' @name authorized_keys.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @param include_trash Include items whose is_trashed attribute is true.
+#' @param include 
+#' @return Group object.
+#' @name groups.shared
 NULL
 
-#' collections.get
+#' groups.trash
 #' 
-#' collections.get is a method defined in Arvados class.
+#' groups.trash is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.get(uuid)
-#' @param uuid The UUID of the Collection in question.
-#' @return Collection object.
-#' @name collections.get
+#' @usage arv$groups.trash(uuid)
+#' @param uuid 
+#' @return Group object.
+#' @name groups.trash
 NULL
 
-#' collections.create
+#' groups.untrash
 #' 
-#' collections.create is a method defined in Arvados class.
+#' groups.untrash is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.create(collection,
-#' 	ensure_unique_name = "false")
-#' @param collection Collection object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Collection object.
-#' @name collections.create
+#' @usage arv$groups.untrash(uuid)
+#' @param uuid 
+#' @return Group object.
+#' @name groups.untrash
 NULL
 
-#' collections.update
+#' groups.list
 #' 
-#' collections.update is a method defined in Arvados class.
+#' groups.list is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.update(collection,
-#' 	uuid)
-#' @param collection Collection object.
-#' @param uuid The UUID of the Collection in question.
-#' @return Collection object.
-#' @name collections.update
+#' @usage arv$groups.list(filters = NULL,
+#' 	where = NULL, order = NULL, select = NULL,
+#' 	distinct = NULL, limit = "100", offset = "0",
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL,
+#' 	include_trash = NULL)
+#' @param filters 
+#' @param where 
+#' @param order 
+#' @param select 
+#' @param distinct 
+#' @param limit 
+#' @param offset 
+#' @param count 
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @param include_trash Include items whose is_trashed attribute is true.
+#' @return GroupList object.
+#' @name groups.list
 NULL
 
-#' collections.delete
+#' keep_services.get
 #' 
-#' collections.delete is a method defined in Arvados class.
+#' keep_services.get is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.delete(uuid)
-#' @param uuid The UUID of the Collection in question.
-#' @return Collection object.
-#' @name collections.delete
+#' @usage arv$keep_services.get(uuid)
+#' @param uuid The UUID of the KeepService in question.
+#' @return KeepService object.
+#' @name keep_services.get
 NULL
 
-#' collections.provenance
+#' keep_services.create
 #' 
-#' collections.provenance is a method defined in Arvados class.
+#' keep_services.create is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.provenance(uuid)
-#' @param uuid 
-#' @return Collection object.
-#' @name collections.provenance
+#' @usage arv$keep_services.create(keepservice,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param keepService KeepService object.
+#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return KeepService object.
+#' @name keep_services.create
 NULL
 
-#' collections.used_by
+#' keep_services.update
 #' 
-#' collections.used_by is a method defined in Arvados class.
+#' keep_services.update is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.used_by(uuid)
-#' @param uuid 
-#' @return Collection object.
-#' @name collections.used_by
+#' @usage arv$keep_services.update(keepservice,
+#' 	uuid)
+#' @param keepService KeepService object.
+#' @param uuid The UUID of the KeepService in question.
+#' @return KeepService object.
+#' @name keep_services.update
 NULL
 
-#' collections.trash
+#' keep_services.delete
 #' 
-#' collections.trash is a method defined in Arvados class.
+#' keep_services.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.trash(uuid)
-#' @param uuid 
-#' @return Collection object.
-#' @name collections.trash
+#' @usage arv$keep_services.delete(uuid)
+#' @param uuid The UUID of the KeepService in question.
+#' @return KeepService object.
+#' @name keep_services.delete
 NULL
 
-#' collections.untrash
+#' keep_services.accessible
 #' 
-#' collections.untrash is a method defined in Arvados class.
+#' keep_services.accessible is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.untrash(uuid)
-#' @param uuid 
-#' @return Collection object.
-#' @name collections.untrash
+#' @usage arv$keep_services.accessible(NULL)
+#' @return KeepService object.
+#' @name keep_services.accessible
 NULL
 
-#' collections.list
+#' keep_services.list
 #' 
-#' collections.list is a method defined in Arvados class.
+#' keep_services.list is a method defined in Arvados class.
 #' 
-#' @usage arv$collections.list(filters = NULL,
+#' @usage arv$keep_services.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact", include_trash = NULL)
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -627,61 +732,64 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @param include_trash Include collections whose is_trashed attribute is true.
-#' @return CollectionList object.
-#' @name collections.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return KeepServiceList object.
+#' @name keep_services.list
 NULL
 
-#' humans.get
+#' links.get
 #' 
-#' humans.get is a method defined in Arvados class.
+#' links.get is a method defined in Arvados class.
 #' 
-#' @usage arv$humans.get(uuid)
-#' @param uuid The UUID of the Human in question.
-#' @return Human object.
-#' @name humans.get
+#' @usage arv$links.get(uuid)
+#' @param uuid The UUID of the Link in question.
+#' @return Link object.
+#' @name links.get
 NULL
 
-#' humans.create
+#' links.create
 #' 
-#' humans.create is a method defined in Arvados class.
+#' links.create is a method defined in Arvados class.
 #' 
-#' @usage arv$humans.create(human, ensure_unique_name = "false")
-#' @param human Human object.
+#' @usage arv$links.create(link, ensure_unique_name = "false",
+#' 	cluster_id = NULL)
+#' @param link Link object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Human object.
-#' @name humans.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Link object.
+#' @name links.create
 NULL
 
-#' humans.update
+#' links.update
 #' 
-#' humans.update is a method defined in Arvados class.
+#' links.update is a method defined in Arvados class.
 #' 
-#' @usage arv$humans.update(human, uuid)
-#' @param human Human object.
-#' @param uuid The UUID of the Human in question.
-#' @return Human object.
-#' @name humans.update
+#' @usage arv$links.update(link, uuid)
+#' @param link Link object.
+#' @param uuid The UUID of the Link in question.
+#' @return Link object.
+#' @name links.update
 NULL
 
-#' humans.delete
+#' links.delete
 #' 
-#' humans.delete is a method defined in Arvados class.
+#' links.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$humans.delete(uuid)
-#' @param uuid The UUID of the Human in question.
-#' @return Human object.
-#' @name humans.delete
+#' @usage arv$links.delete(uuid)
+#' @param uuid The UUID of the Link in question.
+#' @return Link object.
+#' @name links.delete
 NULL
 
-#' humans.list
+#' links.list
 #' 
-#' humans.list is a method defined in Arvados class.
+#' links.list is a method defined in Arvados class.
 #' 
-#' @usage arv$humans.list(filters = NULL,
+#' @usage arv$links.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -690,60 +798,74 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return HumanList object.
-#' @name humans.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return LinkList object.
+#' @name links.list
+NULL
+
+#' links.get_permissions
+#' 
+#' links.get_permissions is a method defined in Arvados class.
+#' 
+#' @usage arv$links.get_permissions(uuid)
+#' @param uuid 
+#' @return Link object.
+#' @name links.get_permissions
 NULL
 
-#' job_tasks.get
+#' logs.get
 #' 
-#' job_tasks.get is a method defined in Arvados class.
+#' logs.get is a method defined in Arvados class.
 #' 
-#' @usage arv$job_tasks.get(uuid)
-#' @param uuid The UUID of the JobTask in question.
-#' @return JobTask object.
-#' @name job_tasks.get
+#' @usage arv$logs.get(uuid)
+#' @param uuid The UUID of the Log in question.
+#' @return Log object.
+#' @name logs.get
 NULL
 
-#' job_tasks.create
+#' logs.create
 #' 
-#' job_tasks.create is a method defined in Arvados class.
+#' logs.create is a method defined in Arvados class.
 #' 
-#' @usage arv$job_tasks.create(jobtask, ensure_unique_name = "false")
-#' @param jobTask JobTask object.
+#' @usage arv$logs.create(log, ensure_unique_name = "false",
+#' 	cluster_id = NULL)
+#' @param log Log object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return JobTask object.
-#' @name job_tasks.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Log object.
+#' @name logs.create
 NULL
 
-#' job_tasks.update
+#' logs.update
 #' 
-#' job_tasks.update is a method defined in Arvados class.
+#' logs.update is a method defined in Arvados class.
 #' 
-#' @usage arv$job_tasks.update(jobtask, uuid)
-#' @param jobTask JobTask object.
-#' @param uuid The UUID of the JobTask in question.
-#' @return JobTask object.
-#' @name job_tasks.update
+#' @usage arv$logs.update(log, uuid)
+#' @param log Log object.
+#' @param uuid The UUID of the Log in question.
+#' @return Log object.
+#' @name logs.update
 NULL
 
-#' job_tasks.delete
+#' logs.delete
 #' 
-#' job_tasks.delete is a method defined in Arvados class.
+#' logs.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$job_tasks.delete(uuid)
-#' @param uuid The UUID of the JobTask in question.
-#' @return JobTask object.
-#' @name job_tasks.delete
+#' @usage arv$logs.delete(uuid)
+#' @param uuid The UUID of the Log in question.
+#' @return Log object.
+#' @name logs.delete
 NULL
 
-#' job_tasks.list
+#' logs.list
 #' 
-#' job_tasks.list is a method defined in Arvados class.
+#' logs.list is a method defined in Arvados class.
 #' 
-#' @usage arv$job_tasks.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' @usage arv$logs.list(filters = NULL, where = NULL,
+#' 	order = NULL, select = NULL, distinct = NULL,
+#' 	limit = "100", offset = "0", count = "exact",
+#' 	cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -752,196 +874,145 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return JobTaskList object.
-#' @name job_tasks.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return LogList object.
+#' @name logs.list
 NULL
 
-#' jobs.get
+#' users.get
 #' 
-#' jobs.get is a method defined in Arvados class.
+#' users.get is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.get(uuid)
-#' @param uuid The UUID of the Job in question.
-#' @return Job object.
-#' @name jobs.get
+#' @usage arv$users.get(uuid)
+#' @param uuid The UUID of the User in question.
+#' @return User object.
+#' @name users.get
 NULL
 
-#' jobs.create
+#' users.create
 #' 
-#' jobs.create is a method defined in Arvados class.
+#' users.create is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.create(job, ensure_unique_name = "false",
-#' 	find_or_create = "false", filters = NULL,
-#' 	minimum_script_version = NULL, exclude_script_versions = NULL)
-#' @param job Job object.
+#' @usage arv$users.create(user, ensure_unique_name = "false",
+#' 	cluster_id = NULL)
+#' @param user User object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @param find_or_create 
-#' @param filters 
-#' @param minimum_script_version 
-#' @param exclude_script_versions 
-#' @return Job object.
-#' @name jobs.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return User object.
+#' @name users.create
 NULL
 
-#' jobs.update
+#' users.update
 #' 
-#' jobs.update is a method defined in Arvados class.
+#' users.update is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.update(job, uuid)
-#' @param job Job object.
-#' @param uuid The UUID of the Job in question.
-#' @return Job object.
-#' @name jobs.update
+#' @usage arv$users.update(user, uuid, bypass_federation = NULL)
+#' @param user User object.
+#' @param uuid The UUID of the User in question.
+#' @param bypass_federation 
+#' @return User object.
+#' @name users.update
 NULL
 
-#' jobs.delete
+#' users.delete
 #' 
-#' jobs.delete is a method defined in Arvados class.
+#' users.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.delete(uuid)
-#' @param uuid The UUID of the Job in question.
-#' @return Job object.
-#' @name jobs.delete
+#' @usage arv$users.delete(uuid)
+#' @param uuid The UUID of the User in question.
+#' @return User object.
+#' @name users.delete
 NULL
 
-#' jobs.queue
+#' users.current
 #' 
-#' jobs.queue is a method defined in Arvados class.
+#' users.current is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.queue(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return Job object.
-#' @name jobs.queue
+#' @usage arv$users.current(NULL)
+#' @return User object.
+#' @name users.current
 NULL
 
-#' jobs.queue_size
+#' users.system
 #' 
-#' jobs.queue_size is a method defined in Arvados class.
+#' users.system is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.queue_size(NULL)
-#' @return Job object.
-#' @name jobs.queue_size
+#' @usage arv$users.system(NULL)
+#' @return User object.
+#' @name users.system
 NULL
 
-#' jobs.cancel
+#' users.activate
 #' 
-#' jobs.cancel is a method defined in Arvados class.
+#' users.activate is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.cancel(uuid)
+#' @usage arv$users.activate(uuid)
 #' @param uuid 
-#' @return Job object.
-#' @name jobs.cancel
+#' @return User object.
+#' @name users.activate
 NULL
 
-#' jobs.lock
+#' users.setup
 #' 
-#' jobs.lock is a method defined in Arvados class.
+#' users.setup is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.lock(uuid)
+#' @usage arv$users.setup(uuid = NULL, user = NULL,
+#' 	repo_name = NULL, vm_uuid = NULL, send_notification_email = "false")
 #' @param uuid 
-#' @return Job object.
-#' @name jobs.lock
+#' @param user 
+#' @param repo_name 
+#' @param vm_uuid 
+#' @param send_notification_email 
+#' @return User object.
+#' @name users.setup
 NULL
 
-#' jobs.list
+#' users.unsetup
 #' 
-#' jobs.list is a method defined in Arvados class.
+#' users.unsetup is a method defined in Arvados class.
 #' 
-#' @usage arv$jobs.list(filters = NULL, where = NULL,
-#' 	order = NULL, select = NULL, distinct = NULL,
-#' 	limit = "100", offset = "0", count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return JobList object.
-#' @name jobs.list
+#' @usage arv$users.unsetup(uuid)
+#' @param uuid 
+#' @return User object.
+#' @name users.unsetup
 NULL
 
-#' keep_disks.get
+#' users.update_uuid
 #' 
-#' keep_disks.get is a method defined in Arvados class.
+#' users.update_uuid is a method defined in Arvados class.
 #' 
-#' @usage arv$keep_disks.get(uuid)
-#' @param uuid The UUID of the KeepDisk in question.
-#' @return KeepDisk object.
-#' @name keep_disks.get
+#' @usage arv$users.update_uuid(uuid, new_uuid)
+#' @param uuid 
+#' @param new_uuid 
+#' @return User object.
+#' @name users.update_uuid
 NULL
 
-#' keep_disks.create
+#' users.merge
 #' 
-#' keep_disks.create is a method defined in Arvados class.
+#' users.merge is a method defined in Arvados class.
 #' 
-#' @usage arv$keep_disks.create(keepdisk,
-#' 	ensure_unique_name = "false")
-#' @param keepDisk KeepDisk object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return KeepDisk object.
-#' @name keep_disks.create
-NULL
-
-#' keep_disks.update
-#' 
-#' keep_disks.update is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_disks.update(keepdisk,
-#' 	uuid)
-#' @param keepDisk KeepDisk object.
-#' @param uuid The UUID of the KeepDisk in question.
-#' @return KeepDisk object.
-#' @name keep_disks.update
-NULL
-
-#' keep_disks.delete
-#' 
-#' keep_disks.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_disks.delete(uuid)
-#' @param uuid The UUID of the KeepDisk in question.
-#' @return KeepDisk object.
-#' @name keep_disks.delete
-NULL
-
-#' keep_disks.ping
-#' 
-#' keep_disks.ping is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_disks.ping(uuid = NULL,
-#' 	ping_secret, node_uuid = NULL, filesystem_uuid = NULL,
-#' 	service_host = NULL, service_port, service_ssl_flag)
-#' @param uuid 
-#' @param ping_secret 
-#' @param node_uuid 
-#' @param filesystem_uuid 
-#' @param service_host 
-#' @param service_port 
-#' @param service_ssl_flag 
-#' @return KeepDisk object.
-#' @name keep_disks.ping
+#' @usage arv$users.merge(new_owner_uuid,
+#' 	new_user_token = NULL, redirect_to_new_user = NULL,
+#' 	old_user_uuid = NULL, new_user_uuid = NULL)
+#' @param new_owner_uuid 
+#' @param new_user_token 
+#' @param redirect_to_new_user 
+#' @param old_user_uuid 
+#' @param new_user_uuid 
+#' @return User object.
+#' @name users.merge
 NULL
 
-#' keep_disks.list
+#' users.list
 #' 
-#' keep_disks.list is a method defined in Arvados class.
+#' users.list is a method defined in Arvados class.
 #' 
-#' @usage arv$keep_disks.list(filters = NULL,
+#' @usage arv$users.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -950,74 +1021,74 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return KeepDiskList object.
-#' @name keep_disks.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return UserList object.
+#' @name users.list
 NULL
 
-#' nodes.get
+#' repositories.get
 #' 
-#' nodes.get is a method defined in Arvados class.
+#' repositories.get is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.get(uuid)
-#' @param uuid The UUID of the Node in question.
-#' @return Node object.
-#' @name nodes.get
+#' @usage arv$repositories.get(uuid)
+#' @param uuid The UUID of the Repository in question.
+#' @return Repository object.
+#' @name repositories.get
 NULL
 
-#' nodes.create
+#' repositories.create
 #' 
-#' nodes.create is a method defined in Arvados class.
+#' repositories.create is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.create(node, ensure_unique_name = "false",
-#' 	assign_slot = NULL)
-#' @param node Node object.
+#' @usage arv$repositories.create(repository,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param repository Repository object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @param assign_slot assign slot and hostname
-#' @return Node object.
-#' @name nodes.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Repository object.
+#' @name repositories.create
 NULL
 
-#' nodes.update
+#' repositories.update
 #' 
-#' nodes.update is a method defined in Arvados class.
+#' repositories.update is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.update(node, uuid, assign_slot = NULL)
-#' @param node Node object.
-#' @param uuid The UUID of the Node in question.
-#' @param assign_slot assign slot and hostname
-#' @return Node object.
-#' @name nodes.update
+#' @usage arv$repositories.update(repository,
+#' 	uuid)
+#' @param repository Repository object.
+#' @param uuid The UUID of the Repository in question.
+#' @return Repository object.
+#' @name repositories.update
 NULL
 
-#' nodes.delete
+#' repositories.delete
 #' 
-#' nodes.delete is a method defined in Arvados class.
+#' repositories.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.delete(uuid)
-#' @param uuid The UUID of the Node in question.
-#' @return Node object.
-#' @name nodes.delete
+#' @usage arv$repositories.delete(uuid)
+#' @param uuid The UUID of the Repository in question.
+#' @return Repository object.
+#' @name repositories.delete
 NULL
 
-#' nodes.ping
+#' repositories.get_all_permissions
 #' 
-#' nodes.ping is a method defined in Arvados class.
+#' repositories.get_all_permissions is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.ping(uuid, ping_secret)
-#' @param uuid 
-#' @param ping_secret 
-#' @return Node object.
-#' @name nodes.ping
+#' @usage arv$repositories.get_all_permissions(NULL)
+#' @return Repository object.
+#' @name repositories.get_all_permissions
 NULL
 
-#' nodes.list
+#' repositories.list
 #' 
-#' nodes.list is a method defined in Arvados class.
+#' repositories.list is a method defined in Arvados class.
 #' 
-#' @usage arv$nodes.list(filters = NULL,
+#' @usage arv$repositories.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -1026,143 +1097,84 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return NodeList object.
-#' @name nodes.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return RepositoryList object.
+#' @name repositories.list
 NULL
 
-#' links.get
+#' virtual_machines.get
 #' 
-#' links.get is a method defined in Arvados class.
+#' virtual_machines.get is a method defined in Arvados class.
 #' 
-#' @usage arv$links.get(uuid)
-#' @param uuid The UUID of the Link in question.
-#' @return Link object.
-#' @name links.get
+#' @usage arv$virtual_machines.get(uuid)
+#' @param uuid The UUID of the VirtualMachine in question.
+#' @return VirtualMachine object.
+#' @name virtual_machines.get
 NULL
 
-#' links.create
+#' virtual_machines.create
 #' 
-#' links.create is a method defined in Arvados class.
+#' virtual_machines.create is a method defined in Arvados class.
 #' 
-#' @usage arv$links.create(link, ensure_unique_name = "false")
-#' @param link Link object.
+#' @usage arv$virtual_machines.create(virtualmachine,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param virtualMachine VirtualMachine object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Link object.
-#' @name links.create
-NULL
-
-#' links.update
-#' 
-#' links.update is a method defined in Arvados class.
-#' 
-#' @usage arv$links.update(link, uuid)
-#' @param link Link object.
-#' @param uuid The UUID of the Link in question.
-#' @return Link object.
-#' @name links.update
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return VirtualMachine object.
+#' @name virtual_machines.create
 NULL
 
-#' links.delete
+#' virtual_machines.update
 #' 
-#' links.delete is a method defined in Arvados class.
+#' virtual_machines.update is a method defined in Arvados class.
 #' 
-#' @usage arv$links.delete(uuid)
-#' @param uuid The UUID of the Link in question.
-#' @return Link object.
-#' @name links.delete
+#' @usage arv$virtual_machines.update(virtualmachine,
+#' 	uuid)
+#' @param virtualMachine VirtualMachine object.
+#' @param uuid The UUID of the VirtualMachine in question.
+#' @return VirtualMachine object.
+#' @name virtual_machines.update
 NULL
 
-#' links.list
+#' virtual_machines.delete
 #' 
-#' links.list is a method defined in Arvados class.
+#' virtual_machines.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$links.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return LinkList object.
-#' @name links.list
+#' @usage arv$virtual_machines.delete(uuid)
+#' @param uuid The UUID of the VirtualMachine in question.
+#' @return VirtualMachine object.
+#' @name virtual_machines.delete
 NULL
 
-#' links.get_permissions
+#' virtual_machines.logins
 #' 
-#' links.get_permissions is a method defined in Arvados class.
+#' virtual_machines.logins is a method defined in Arvados class.
 #' 
-#' @usage arv$links.get_permissions(uuid)
+#' @usage arv$virtual_machines.logins(uuid)
 #' @param uuid 
-#' @return Link object.
-#' @name links.get_permissions
-NULL
-
-#' keep_services.get
-#' 
-#' keep_services.get is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_services.get(uuid)
-#' @param uuid The UUID of the KeepService in question.
-#' @return KeepService object.
-#' @name keep_services.get
-NULL
-
-#' keep_services.create
-#' 
-#' keep_services.create is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_services.create(keepservice,
-#' 	ensure_unique_name = "false")
-#' @param keepService KeepService object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return KeepService object.
-#' @name keep_services.create
-NULL
-
-#' keep_services.update
-#' 
-#' keep_services.update is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_services.update(keepservice,
-#' 	uuid)
-#' @param keepService KeepService object.
-#' @param uuid The UUID of the KeepService in question.
-#' @return KeepService object.
-#' @name keep_services.update
-NULL
-
-#' keep_services.delete
-#' 
-#' keep_services.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$keep_services.delete(uuid)
-#' @param uuid The UUID of the KeepService in question.
-#' @return KeepService object.
-#' @name keep_services.delete
+#' @return VirtualMachine object.
+#' @name virtual_machines.logins
 NULL
 
-#' keep_services.accessible
+#' virtual_machines.get_all_logins
 #' 
-#' keep_services.accessible is a method defined in Arvados class.
+#' virtual_machines.get_all_logins is a method defined in Arvados class.
 #' 
-#' @usage arv$keep_services.accessible(NULL)
-#' @return KeepService object.
-#' @name keep_services.accessible
+#' @usage arv$virtual_machines.get_all_logins(NULL)
+#' @return VirtualMachine object.
+#' @name virtual_machines.get_all_logins
 NULL
 
-#' keep_services.list
+#' virtual_machines.list
 #' 
-#' keep_services.list is a method defined in Arvados class.
+#' virtual_machines.list is a method defined in Arvados class.
 #' 
-#' @usage arv$keep_services.list(filters = NULL,
+#' @usage arv$virtual_machines.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -1171,62 +1183,65 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return KeepServiceList object.
-#' @name keep_services.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return VirtualMachineList object.
+#' @name virtual_machines.list
 NULL
 
-#' pipeline_templates.get
+#' workflows.get
 #' 
-#' pipeline_templates.get is a method defined in Arvados class.
+#' workflows.get is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_templates.get(uuid)
-#' @param uuid The UUID of the PipelineTemplate in question.
-#' @return PipelineTemplate object.
-#' @name pipeline_templates.get
+#' @usage arv$workflows.get(uuid)
+#' @param uuid The UUID of the Workflow in question.
+#' @return Workflow object.
+#' @name workflows.get
 NULL
 
-#' pipeline_templates.create
+#' workflows.create
 #' 
-#' pipeline_templates.create is a method defined in Arvados class.
+#' workflows.create is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_templates.create(pipelinetemplate,
-#' 	ensure_unique_name = "false")
-#' @param pipelineTemplate PipelineTemplate object.
+#' @usage arv$workflows.create(workflow,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param workflow Workflow object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return PipelineTemplate object.
-#' @name pipeline_templates.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return Workflow object.
+#' @name workflows.create
 NULL
 
-#' pipeline_templates.update
+#' workflows.update
 #' 
-#' pipeline_templates.update is a method defined in Arvados class.
+#' workflows.update is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_templates.update(pipelinetemplate,
+#' @usage arv$workflows.update(workflow,
 #' 	uuid)
-#' @param pipelineTemplate PipelineTemplate object.
-#' @param uuid The UUID of the PipelineTemplate in question.
-#' @return PipelineTemplate object.
-#' @name pipeline_templates.update
+#' @param workflow Workflow object.
+#' @param uuid The UUID of the Workflow in question.
+#' @return Workflow object.
+#' @name workflows.update
 NULL
 
-#' pipeline_templates.delete
+#' workflows.delete
 #' 
-#' pipeline_templates.delete is a method defined in Arvados class.
+#' workflows.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_templates.delete(uuid)
-#' @param uuid The UUID of the PipelineTemplate in question.
-#' @return PipelineTemplate object.
-#' @name pipeline_templates.delete
+#' @usage arv$workflows.delete(uuid)
+#' @param uuid The UUID of the Workflow in question.
+#' @return Workflow object.
+#' @name workflows.delete
 NULL
 
-#' pipeline_templates.list
+#' workflows.list
 #' 
-#' pipeline_templates.list is a method defined in Arvados class.
+#' workflows.list is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_templates.list(filters = NULL,
+#' @usage arv$workflows.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -1235,209 +1250,83 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return PipelineTemplateList object.
-#' @name pipeline_templates.list
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return WorkflowList object.
+#' @name workflows.list
 NULL
 
-#' pipeline_instances.get
+#' user_agreements.get
 #' 
-#' pipeline_instances.get is a method defined in Arvados class.
+#' user_agreements.get is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_instances.get(uuid)
-#' @param uuid The UUID of the PipelineInstance in question.
-#' @return PipelineInstance object.
-#' @name pipeline_instances.get
+#' @usage arv$user_agreements.get(uuid)
+#' @param uuid The UUID of the UserAgreement in question.
+#' @return UserAgreement object.
+#' @name user_agreements.get
 NULL
 
-#' pipeline_instances.create
+#' user_agreements.create
 #' 
-#' pipeline_instances.create is a method defined in Arvados class.
+#' user_agreements.create is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_instances.create(pipelineinstance,
-#' 	ensure_unique_name = "false")
-#' @param pipelineInstance PipelineInstance object.
+#' @usage arv$user_agreements.create(useragreement,
+#' 	ensure_unique_name = "false", cluster_id = NULL)
+#' @param userAgreement UserAgreement object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return PipelineInstance object.
-#' @name pipeline_instances.create
+#' @param cluster_id Create object on a remote federated cluster instead of the current one.
+#' @return UserAgreement object.
+#' @name user_agreements.create
 NULL
 
-#' pipeline_instances.update
+#' user_agreements.update
 #' 
-#' pipeline_instances.update is a method defined in Arvados class.
+#' user_agreements.update is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_instances.update(pipelineinstance,
+#' @usage arv$user_agreements.update(useragreement,
 #' 	uuid)
-#' @param pipelineInstance PipelineInstance object.
-#' @param uuid The UUID of the PipelineInstance in question.
-#' @return PipelineInstance object.
-#' @name pipeline_instances.update
+#' @param userAgreement UserAgreement object.
+#' @param uuid The UUID of the UserAgreement in question.
+#' @return UserAgreement object.
+#' @name user_agreements.update
 NULL
 
-#' pipeline_instances.delete
+#' user_agreements.delete
 #' 
-#' pipeline_instances.delete is a method defined in Arvados class.
+#' user_agreements.delete is a method defined in Arvados class.
 #' 
-#' @usage arv$pipeline_instances.delete(uuid)
-#' @param uuid The UUID of the PipelineInstance in question.
-#' @return PipelineInstance object.
-#' @name pipeline_instances.delete
-NULL
-
-#' pipeline_instances.cancel
-#' 
-#' pipeline_instances.cancel is a method defined in Arvados class.
-#' 
-#' @usage arv$pipeline_instances.cancel(uuid)
-#' @param uuid 
-#' @return PipelineInstance object.
-#' @name pipeline_instances.cancel
-NULL
-
-#' pipeline_instances.list
-#' 
-#' pipeline_instances.list is a method defined in Arvados class.
-#' 
-#' @usage arv$pipeline_instances.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return PipelineInstanceList object.
-#' @name pipeline_instances.list
-NULL
-
-#' repositories.get
-#' 
-#' repositories.get is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.get(uuid)
-#' @param uuid The UUID of the Repository in question.
-#' @return Repository object.
-#' @name repositories.get
-NULL
-
-#' repositories.create
-#' 
-#' repositories.create is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.create(repository,
-#' 	ensure_unique_name = "false")
-#' @param repository Repository object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Repository object.
-#' @name repositories.create
-NULL
-
-#' repositories.update
-#' 
-#' repositories.update is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.update(repository,
-#' 	uuid)
-#' @param repository Repository object.
-#' @param uuid The UUID of the Repository in question.
-#' @return Repository object.
-#' @name repositories.update
-NULL
-
-#' repositories.delete
-#' 
-#' repositories.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.delete(uuid)
-#' @param uuid The UUID of the Repository in question.
-#' @return Repository object.
-#' @name repositories.delete
-NULL
-
-#' repositories.get_all_permissions
-#' 
-#' repositories.get_all_permissions is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.get_all_permissions(NULL)
-#' @return Repository object.
-#' @name repositories.get_all_permissions
-NULL
-
-#' repositories.list
-#' 
-#' repositories.list is a method defined in Arvados class.
-#' 
-#' @usage arv$repositories.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return RepositoryList object.
-#' @name repositories.list
-NULL
-
-#' specimens.get
-#' 
-#' specimens.get is a method defined in Arvados class.
-#' 
-#' @usage arv$specimens.get(uuid)
-#' @param uuid The UUID of the Specimen in question.
-#' @return Specimen object.
-#' @name specimens.get
-NULL
-
-#' specimens.create
-#' 
-#' specimens.create is a method defined in Arvados class.
-#' 
-#' @usage arv$specimens.create(specimen,
-#' 	ensure_unique_name = "false")
-#' @param specimen Specimen object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Specimen object.
-#' @name specimens.create
+#' @usage arv$user_agreements.delete(uuid)
+#' @param uuid The UUID of the UserAgreement in question.
+#' @return UserAgreement object.
+#' @name user_agreements.delete
 NULL
 
-#' specimens.update
+#' user_agreements.signatures
 #' 
-#' specimens.update is a method defined in Arvados class.
+#' user_agreements.signatures is a method defined in Arvados class.
 #' 
-#' @usage arv$specimens.update(specimen,
-#' 	uuid)
-#' @param specimen Specimen object.
-#' @param uuid The UUID of the Specimen in question.
-#' @return Specimen object.
-#' @name specimens.update
+#' @usage arv$user_agreements.signatures(NULL)
+#' @return UserAgreement object.
+#' @name user_agreements.signatures
 NULL
 
-#' specimens.delete
+#' user_agreements.sign
 #' 
-#' specimens.delete is a method defined in Arvados class.
+#' user_agreements.sign is a method defined in Arvados class.
 #' 
-#' @usage arv$specimens.delete(uuid)
-#' @param uuid The UUID of the Specimen in question.
-#' @return Specimen object.
-#' @name specimens.delete
+#' @usage arv$user_agreements.sign(NULL)
+#' @return UserAgreement object.
+#' @name user_agreements.sign
 NULL
 
-#' specimens.list
+#' user_agreements.list
 #' 
-#' specimens.list is a method defined in Arvados class.
+#' user_agreements.list is a method defined in Arvados class.
 #' 
-#' @usage arv$specimens.list(filters = NULL,
+#' @usage arv$user_agreements.list(filters = NULL,
 #' 	where = NULL, order = NULL, select = NULL,
 #' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' 	count = "exact", cluster_id = NULL, bypass_federation = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
@@ -1446,1774 +1335,312 @@ NULL
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return SpecimenList object.
-#' @name specimens.list
-NULL
-
-#' logs.get
-#' 
-#' logs.get is a method defined in Arvados class.
-#' 
-#' @usage arv$logs.get(uuid)
-#' @param uuid The UUID of the Log in question.
-#' @return Log object.
-#' @name logs.get
-NULL
-
-#' logs.create
-#' 
-#' logs.create is a method defined in Arvados class.
-#' 
-#' @usage arv$logs.create(log, ensure_unique_name = "false")
-#' @param log Log object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Log object.
-#' @name logs.create
-NULL
-
-#' logs.update
-#' 
-#' logs.update is a method defined in Arvados class.
-#' 
-#' @usage arv$logs.update(log, uuid)
-#' @param log Log object.
-#' @param uuid The UUID of the Log in question.
-#' @return Log object.
-#' @name logs.update
+#' @param cluster_id List objects on a remote federated cluster instead of the current one.
+#' @param bypass_federation bypass federation behavior, list items from local instance database only
+#' @return UserAgreementList object.
+#' @name user_agreements.list
 NULL
 
-#' logs.delete
+#' user_agreements.new
 #' 
-#' logs.delete is a method defined in Arvados class.
+#' user_agreements.new is a method defined in Arvados class.
 #' 
-#' @usage arv$logs.delete(uuid)
-#' @param uuid The UUID of the Log in question.
-#' @return Log object.
-#' @name logs.delete
+#' @usage arv$user_agreements.new(NULL)
+#' @return UserAgreement object.
+#' @name user_agreements.new
 NULL
 
-#' logs.list
+#' configs.get
 #' 
-#' logs.list is a method defined in Arvados class.
+#' configs.get is a method defined in Arvados class.
 #' 
-#' @usage arv$logs.list(filters = NULL, where = NULL,
-#' 	order = NULL, select = NULL, distinct = NULL,
-#' 	limit = "100", offset = "0", count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return LogList object.
-#' @name logs.list
+#' @usage arv$configs.get(NULL)
+#' @return  object.
+#' @name configs.get
 NULL
 
-#' traits.get
+#' project.get
 #' 
-#' traits.get is a method defined in Arvados class.
+#' projects.get is equivalent to groups.get method.
 #' 
-#' @usage arv$traits.get(uuid)
-#' @param uuid The UUID of the Trait in question.
-#' @return Trait object.
-#' @name traits.get
+#' @usage arv$projects.get(uuid)
+#' @param uuid The UUID of the Group in question.
+#' @return Group object.
+#' @name projects.get
 NULL
 
-#' traits.create
+#' project.create
 #' 
-#' traits.create is a method defined in Arvados class.
+#' projects.create wrapps groups.create method by setting group_class attribute to "project".
 #' 
-#' @usage arv$traits.create(trait, ensure_unique_name = "false")
-#' @param trait Trait object.
+#' @usage arv$projects.create(group, ensure_unique_name = "false")
+#' @param group Group object.
 #' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Trait object.
-#' @name traits.create
+#' @return Group object.
+#' @name projects.create
 NULL
 
-#' traits.update
+#' project.update
 #' 
-#' traits.update is a method defined in Arvados class.
+#' projects.update wrapps groups.update method by setting group_class attribute to "project".
 #' 
-#' @usage arv$traits.update(trait, uuid)
-#' @param trait Trait object.
-#' @param uuid The UUID of the Trait in question.
-#' @return Trait object.
-#' @name traits.update
+#' @usage arv$projects.update(group, uuid)
+#' @param group Group object.
+#' @param uuid The UUID of the Group in question.
+#' @return Group object.
+#' @name projects.update
 NULL
 
-#' traits.delete
+#' project.delete
 #' 
-#' traits.delete is a method defined in Arvados class.
+#' projects.delete is equivalent to groups.delete method.
 #' 
-#' @usage arv$traits.delete(uuid)
-#' @param uuid The UUID of the Trait in question.
-#' @return Trait object.
-#' @name traits.delete
+#' @usage arv$project.delete(uuid)
+#' @param uuid The UUID of the Group in question.
+#' @return Group object.
+#' @name projects.delete
 NULL
 
-#' traits.list
+#' project.list
 #' 
-#' traits.list is a method defined in Arvados class.
+#' projects.list wrapps groups.list method by setting group_class attribute to "project".
 #' 
-#' @usage arv$traits.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
+#' @usage arv$projects.list(filters = NULL,
+#' 	where = NULL, order = NULL, distinct = NULL,
+#' 	limit = "100", offset = "0", count = "exact",
+#' 	include_trash = NULL, uuid = NULL, recursive = NULL)
 #' @param filters 
 #' @param where 
 #' @param order 
-#' @param select 
 #' @param distinct 
 #' @param limit 
 #' @param offset 
 #' @param count 
-#' @return TraitList object.
-#' @name traits.list
-NULL
-
-#' virtual_machines.get
-#' 
-#' virtual_machines.get is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.get(uuid)
-#' @param uuid The UUID of the VirtualMachine in question.
-#' @return VirtualMachine object.
-#' @name virtual_machines.get
-NULL
-
-#' virtual_machines.create
-#' 
-#' virtual_machines.create is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.create(virtualmachine,
-#' 	ensure_unique_name = "false")
-#' @param virtualMachine VirtualMachine object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return VirtualMachine object.
-#' @name virtual_machines.create
-NULL
-
-#' virtual_machines.update
-#' 
-#' virtual_machines.update is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.update(virtualmachine,
-#' 	uuid)
-#' @param virtualMachine VirtualMachine object.
-#' @param uuid The UUID of the VirtualMachine in question.
-#' @return VirtualMachine object.
-#' @name virtual_machines.update
+#' @param include_trash Include items whose is_trashed attribute is true.
+#' @param uuid 
+#' @param recursive Include contents from child groups recursively.
+#' @return Group object.
+#' @name projects.list
 NULL
 
-#' virtual_machines.delete
-#' 
-#' virtual_machines.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.delete(uuid)
-#' @param uuid The UUID of the VirtualMachine in question.
-#' @return VirtualMachine object.
-#' @name virtual_machines.delete
-NULL
-
-#' virtual_machines.logins
-#' 
-#' virtual_machines.logins is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.logins(uuid)
-#' @param uuid 
-#' @return VirtualMachine object.
-#' @name virtual_machines.logins
-NULL
-
-#' virtual_machines.get_all_logins
-#' 
-#' virtual_machines.get_all_logins is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.get_all_logins(NULL)
-#' @return VirtualMachine object.
-#' @name virtual_machines.get_all_logins
-NULL
-
-#' virtual_machines.list
-#' 
-#' virtual_machines.list is a method defined in Arvados class.
-#' 
-#' @usage arv$virtual_machines.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return VirtualMachineList object.
-#' @name virtual_machines.list
-NULL
-
-#' workflows.get
-#' 
-#' workflows.get is a method defined in Arvados class.
-#' 
-#' @usage arv$workflows.get(uuid)
-#' @param uuid The UUID of the Workflow in question.
-#' @return Workflow object.
-#' @name workflows.get
-NULL
-
-#' workflows.create
-#' 
-#' workflows.create is a method defined in Arvados class.
-#' 
-#' @usage arv$workflows.create(workflow,
-#' 	ensure_unique_name = "false")
-#' @param workflow Workflow object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Workflow object.
-#' @name workflows.create
-NULL
-
-#' workflows.update
-#' 
-#' workflows.update is a method defined in Arvados class.
-#' 
-#' @usage arv$workflows.update(workflow,
-#' 	uuid)
-#' @param workflow Workflow object.
-#' @param uuid The UUID of the Workflow in question.
-#' @return Workflow object.
-#' @name workflows.update
-NULL
-
-#' workflows.delete
-#' 
-#' workflows.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$workflows.delete(uuid)
-#' @param uuid The UUID of the Workflow in question.
-#' @return Workflow object.
-#' @name workflows.delete
-NULL
-
-#' workflows.list
-#' 
-#' workflows.list is a method defined in Arvados class.
-#' 
-#' @usage arv$workflows.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return WorkflowList object.
-#' @name workflows.list
-NULL
-
-#' groups.get
-#' 
-#' groups.get is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.get(uuid)
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name groups.get
-NULL
-
-#' groups.create
-#' 
-#' groups.create is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.create(group, ensure_unique_name = "false")
-#' @param group Group object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Group object.
-#' @name groups.create
-NULL
-
-#' groups.update
-#' 
-#' groups.update is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.update(group, uuid)
-#' @param group Group object.
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name groups.update
-NULL
-
-#' groups.delete
-#' 
-#' groups.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.delete(uuid)
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name groups.delete
-NULL
-
-#' groups.contents
-#' 
-#' groups.contents is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.contents(filters = NULL,
-#' 	where = NULL, order = NULL, distinct = NULL,
-#' 	limit = "100", offset = "0", count = "exact",
-#' 	include_trash = NULL, uuid = NULL, recursive = NULL)
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @param include_trash Include items whose is_trashed attribute is true.
-#' @param uuid 
-#' @param recursive Include contents from child groups recursively.
-#' @return Group object.
-#' @name groups.contents
-NULL
-
-#' groups.trash
-#' 
-#' groups.trash is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.trash(uuid)
-#' @param uuid 
-#' @return Group object.
-#' @name groups.trash
-NULL
-
-#' groups.untrash
-#' 
-#' groups.untrash is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.untrash(uuid)
-#' @param uuid 
-#' @return Group object.
-#' @name groups.untrash
-NULL
-
-#' groups.list
-#' 
-#' groups.list is a method defined in Arvados class.
-#' 
-#' @usage arv$groups.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact", include_trash = NULL)
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @param include_trash Include items whose is_trashed attribute is true.
-#' @return GroupList object.
-#' @name groups.list
-NULL
-
-#' user_agreements.get
-#' 
-#' user_agreements.get is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.get(uuid)
-#' @param uuid The UUID of the UserAgreement in question.
-#' @return UserAgreement object.
-#' @name user_agreements.get
-NULL
-
-#' user_agreements.create
-#' 
-#' user_agreements.create is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.create(useragreement,
-#' 	ensure_unique_name = "false")
-#' @param userAgreement UserAgreement object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return UserAgreement object.
-#' @name user_agreements.create
-NULL
-
-#' user_agreements.update
-#' 
-#' user_agreements.update is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.update(useragreement,
-#' 	uuid)
-#' @param userAgreement UserAgreement object.
-#' @param uuid The UUID of the UserAgreement in question.
-#' @return UserAgreement object.
-#' @name user_agreements.update
-NULL
-
-#' user_agreements.delete
-#' 
-#' user_agreements.delete is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.delete(uuid)
-#' @param uuid The UUID of the UserAgreement in question.
-#' @return UserAgreement object.
-#' @name user_agreements.delete
-NULL
-
-#' user_agreements.signatures
-#' 
-#' user_agreements.signatures is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.signatures(NULL)
-#' @return UserAgreement object.
-#' @name user_agreements.signatures
-NULL
-
-#' user_agreements.sign
-#' 
-#' user_agreements.sign is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.sign(NULL)
-#' @return UserAgreement object.
-#' @name user_agreements.sign
-NULL
-
-#' user_agreements.list
-#' 
-#' user_agreements.list is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.list(filters = NULL,
-#' 	where = NULL, order = NULL, select = NULL,
-#' 	distinct = NULL, limit = "100", offset = "0",
-#' 	count = "exact")
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param select 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @return UserAgreementList object.
-#' @name user_agreements.list
-NULL
-
-#' user_agreements.new
-#' 
-#' user_agreements.new is a method defined in Arvados class.
-#' 
-#' @usage arv$user_agreements.new(NULL)
-#' @return UserAgreement object.
-#' @name user_agreements.new
-NULL
-
-#' project.get
-#' 
-#' projects.get is equivalent to groups.get method.
-#' 
-#' @usage arv$projects.get(uuid)
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name projects.get
-NULL
-
-#' project.create
-#' 
-#' projects.create wrapps groups.create method by setting group_class attribute to "project".
-#' 
-#' @usage arv$projects.create(group, ensure_unique_name = "false")
-#' @param group Group object.
-#' @param ensure_unique_name Adjust name to ensure uniqueness instead of returning an error on (owner_uuid, name) collision.
-#' @return Group object.
-#' @name projects.create
-NULL
-
-#' project.update
-#' 
-#' projects.update wrapps groups.update method by setting group_class attribute to "project".
-#' 
-#' @usage arv$projects.update(group, uuid)
-#' @param group Group object.
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name projects.update
-NULL
-
-#' project.delete
-#' 
-#' projects.delete is equivalent to groups.delete method.
-#' 
-#' @usage arv$project.delete(uuid)
-#' @param uuid The UUID of the Group in question.
-#' @return Group object.
-#' @name projects.delete
-NULL
-
-#' project.list
-#' 
-#' projects.list wrapps groups.list method by setting group_class attribute to "project".
-#' 
-#' @usage arv$projects.list(filters = NULL,
-#' 	where = NULL, order = NULL, distinct = NULL,
-#' 	limit = "100", offset = "0", count = "exact",
-#' 	include_trash = NULL, uuid = NULL, recursive = NULL)
-#' @param filters 
-#' @param where 
-#' @param order 
-#' @param distinct 
-#' @param limit 
-#' @param offset 
-#' @param count 
-#' @param include_trash Include items whose is_trashed attribute is true.
-#' @param uuid 
-#' @param recursive Include contents from child groups recursively.
-#' @return Group object.
-#' @name projects.list
-NULL
-
-#' Arvados
-#'
-#' Arvados class gives users ability to access Arvados REST API.
-#'
-#' @section Usage:
-#' \preformatted{arv = Arvados$new(authToken = NULL, hostName = NULL, numRetries = 0)}
-#'
-#' @section Arguments:
-#' \describe{
-#' 	\item{authToken}{Authentification token. If not specified ARVADOS_API_TOKEN environment variable will be used.}
-#' 	\item{hostName}{Host name. If not specified ARVADOS_API_HOST environment variable will be used.}
-#' 	\item{numRetries}{Number which specifies how many times to retry failed service requests.}
-#' }
-#'
-#' @section Methods:
-#' \describe{
-#' 	\item{}{\code{\link{api_client_authorizations.create}}}
-#' 	\item{}{\code{\link{api_client_authorizations.create_system_auth}}}
-#' 	\item{}{\code{\link{api_client_authorizations.current}}}
-#' 	\item{}{\code{\link{api_client_authorizations.delete}}}
-#' 	\item{}{\code{\link{api_client_authorizations.get}}}
-#' 	\item{}{\code{\link{api_client_authorizations.list}}}
-#' 	\item{}{\code{\link{api_client_authorizations.update}}}
-#' 	\item{}{\code{\link{api_clients.create}}}
-#' 	\item{}{\code{\link{api_clients.delete}}}
-#' 	\item{}{\code{\link{api_clients.get}}}
-#' 	\item{}{\code{\link{api_clients.list}}}
-#' 	\item{}{\code{\link{api_clients.update}}}
-#' 	\item{}{\code{\link{authorized_keys.create}}}
-#' 	\item{}{\code{\link{authorized_keys.delete}}}
-#' 	\item{}{\code{\link{authorized_keys.get}}}
-#' 	\item{}{\code{\link{authorized_keys.list}}}
-#' 	\item{}{\code{\link{authorized_keys.update}}}
-#' 	\item{}{\code{\link{collections.create}}}
-#' 	\item{}{\code{\link{collections.delete}}}
-#' 	\item{}{\code{\link{collections.get}}}
-#' 	\item{}{\code{\link{collections.list}}}
-#' 	\item{}{\code{\link{collections.provenance}}}
-#' 	\item{}{\code{\link{collections.trash}}}
-#' 	\item{}{\code{\link{collections.untrash}}}
-#' 	\item{}{\code{\link{collections.update}}}
-#' 	\item{}{\code{\link{collections.used_by}}}
-#' 	\item{}{\code{\link{container_requests.create}}}
-#' 	\item{}{\code{\link{container_requests.delete}}}
-#' 	\item{}{\code{\link{container_requests.get}}}
-#' 	\item{}{\code{\link{container_requests.list}}}
-#' 	\item{}{\code{\link{container_requests.update}}}
-#' 	\item{}{\code{\link{containers.auth}}}
-#' 	\item{}{\code{\link{containers.create}}}
-#' 	\item{}{\code{\link{containers.current}}}
-#' 	\item{}{\code{\link{containers.delete}}}
-#' 	\item{}{\code{\link{containers.get}}}
-#' 	\item{}{\code{\link{containers.list}}}
-#' 	\item{}{\code{\link{containers.lock}}}
-#' 	\item{}{\code{\link{containers.secret_mounts}}}
-#' 	\item{}{\code{\link{containers.unlock}}}
-#' 	\item{}{\code{\link{containers.update}}}
-#' 	\item{}{\code{\link{groups.contents}}}
-#' 	\item{}{\code{\link{groups.create}}}
-#' 	\item{}{\code{\link{groups.delete}}}
-#' 	\item{}{\code{\link{groups.get}}}
-#' 	\item{}{\code{\link{groups.list}}}
-#' 	\item{}{\code{\link{groups.trash}}}
-#' 	\item{}{\code{\link{groups.untrash}}}
-#' 	\item{}{\code{\link{groups.update}}}
-#' 	\item{}{\code{\link{humans.create}}}
-#' 	\item{}{\code{\link{humans.delete}}}
-#' 	\item{}{\code{\link{humans.get}}}
-#' 	\item{}{\code{\link{humans.list}}}
-#' 	\item{}{\code{\link{humans.update}}}
-#' 	\item{}{\code{\link{jobs.cancel}}}
-#' 	\item{}{\code{\link{jobs.create}}}
-#' 	\item{}{\code{\link{jobs.delete}}}
-#' 	\item{}{\code{\link{jobs.get}}}
-#' 	\item{}{\code{\link{jobs.list}}}
-#' 	\item{}{\code{\link{jobs.lock}}}
-#' 	\item{}{\code{\link{jobs.queue}}}
-#' 	\item{}{\code{\link{jobs.queue_size}}}
-#' 	\item{}{\code{\link{jobs.update}}}
-#' 	\item{}{\code{\link{job_tasks.create}}}
-#' 	\item{}{\code{\link{job_tasks.delete}}}
-#' 	\item{}{\code{\link{job_tasks.get}}}
-#' 	\item{}{\code{\link{job_tasks.list}}}
-#' 	\item{}{\code{\link{job_tasks.update}}}
-#' 	\item{}{\code{\link{keep_disks.create}}}
-#' 	\item{}{\code{\link{keep_disks.delete}}}
-#' 	\item{}{\code{\link{keep_disks.get}}}
-#' 	\item{}{\code{\link{keep_disks.list}}}
-#' 	\item{}{\code{\link{keep_disks.ping}}}
-#' 	\item{}{\code{\link{keep_disks.update}}}
-#' 	\item{}{\code{\link{keep_services.accessible}}}
-#' 	\item{}{\code{\link{keep_services.create}}}
-#' 	\item{}{\code{\link{keep_services.delete}}}
-#' 	\item{}{\code{\link{keep_services.get}}}
-#' 	\item{}{\code{\link{keep_services.list}}}
-#' 	\item{}{\code{\link{keep_services.update}}}
-#' 	\item{}{\code{\link{links.create}}}
-#' 	\item{}{\code{\link{links.delete}}}
-#' 	\item{}{\code{\link{links.get}}}
-#' 	\item{}{\code{\link{links.get_permissions}}}
-#' 	\item{}{\code{\link{links.list}}}
-#' 	\item{}{\code{\link{links.update}}}
-#' 	\item{}{\code{\link{logs.create}}}
-#' 	\item{}{\code{\link{logs.delete}}}
-#' 	\item{}{\code{\link{logs.get}}}
-#' 	\item{}{\code{\link{logs.list}}}
-#' 	\item{}{\code{\link{logs.update}}}
-#' 	\item{}{\code{\link{nodes.create}}}
-#' 	\item{}{\code{\link{nodes.delete}}}
-#' 	\item{}{\code{\link{nodes.get}}}
-#' 	\item{}{\code{\link{nodes.list}}}
-#' 	\item{}{\code{\link{nodes.ping}}}
-#' 	\item{}{\code{\link{nodes.update}}}
-#' 	\item{}{\code{\link{pipeline_instances.cancel}}}
-#' 	\item{}{\code{\link{pipeline_instances.create}}}
-#' 	\item{}{\code{\link{pipeline_instances.delete}}}
-#' 	\item{}{\code{\link{pipeline_instances.get}}}
-#' 	\item{}{\code{\link{pipeline_instances.list}}}
-#' 	\item{}{\code{\link{pipeline_instances.update}}}
-#' 	\item{}{\code{\link{pipeline_templates.create}}}
-#' 	\item{}{\code{\link{pipeline_templates.delete}}}
-#' 	\item{}{\code{\link{pipeline_templates.get}}}
-#' 	\item{}{\code{\link{pipeline_templates.list}}}
-#' 	\item{}{\code{\link{pipeline_templates.update}}}
-#' 	\item{}{\code{\link{projects.create}}}
-#' 	\item{}{\code{\link{projects.delete}}}
-#' 	\item{}{\code{\link{projects.get}}}
-#' 	\item{}{\code{\link{projects.list}}}
-#' 	\item{}{\code{\link{projects.update}}}
-#' 	\item{}{\code{\link{repositories.create}}}
-#' 	\item{}{\code{\link{repositories.delete}}}
-#' 	\item{}{\code{\link{repositories.get}}}
-#' 	\item{}{\code{\link{repositories.get_all_permissions}}}
-#' 	\item{}{\code{\link{repositories.list}}}
-#' 	\item{}{\code{\link{repositories.update}}}
-#' 	\item{}{\code{\link{specimens.create}}}
-#' 	\item{}{\code{\link{specimens.delete}}}
-#' 	\item{}{\code{\link{specimens.get}}}
-#' 	\item{}{\code{\link{specimens.list}}}
-#' 	\item{}{\code{\link{specimens.update}}}
-#' 	\item{}{\code{\link{traits.create}}}
-#' 	\item{}{\code{\link{traits.delete}}}
-#' 	\item{}{\code{\link{traits.get}}}
-#' 	\item{}{\code{\link{traits.list}}}
-#' 	\item{}{\code{\link{traits.update}}}
-#' 	\item{}{\code{\link{user_agreements.create}}}
-#' 	\item{}{\code{\link{user_agreements.delete}}}
-#' 	\item{}{\code{\link{user_agreements.get}}}
-#' 	\item{}{\code{\link{user_agreements.list}}}
-#' 	\item{}{\code{\link{user_agreements.new}}}
-#' 	\item{}{\code{\link{user_agreements.sign}}}
-#' 	\item{}{\code{\link{user_agreements.signatures}}}
-#' 	\item{}{\code{\link{user_agreements.update}}}
-#' 	\item{}{\code{\link{users.activate}}}
-#' 	\item{}{\code{\link{users.create}}}
-#' 	\item{}{\code{\link{users.current}}}
-#' 	\item{}{\code{\link{users.delete}}}
-#' 	\item{}{\code{\link{users.get}}}
-#' 	\item{}{\code{\link{users.list}}}
-#' 	\item{}{\code{\link{users.merge}}}
-#' 	\item{}{\code{\link{users.setup}}}
-#' 	\item{}{\code{\link{users.system}}}
-#' 	\item{}{\code{\link{users.unsetup}}}
-#' 	\item{}{\code{\link{users.update}}}
-#' 	\item{}{\code{\link{users.update_uuid}}}
-#' 	\item{}{\code{\link{virtual_machines.create}}}
-#' 	\item{}{\code{\link{virtual_machines.delete}}}
-#' 	\item{}{\code{\link{virtual_machines.get}}}
-#' 	\item{}{\code{\link{virtual_machines.get_all_logins}}}
-#' 	\item{}{\code{\link{virtual_machines.list}}}
-#' 	\item{}{\code{\link{virtual_machines.logins}}}
-#' 	\item{}{\code{\link{virtual_machines.update}}}
-#' 	\item{}{\code{\link{workflows.create}}}
-#' 	\item{}{\code{\link{workflows.delete}}}
-#' 	\item{}{\code{\link{workflows.get}}}
-#' 	\item{}{\code{\link{workflows.list}}}
-#' 	\item{}{\code{\link{workflows.update}}}
-#' }
-#'
-#' @name Arvados
-#' @examples
-#' \dontrun{
-#' arv <- Arvados$new("your Arvados token", "example.arvadosapi.com")
-#'
-#' collection <- arv$collections.get("uuid")
-#'
-#' collectionList <- arv$collections.list(list(list("name", "like", "Test%")))
-#' collectionList <- listAll(arv$collections.list, list(list("name", "like", "Test%")))
-#'
-#' deletedCollection <- arv$collections.delete("uuid")
-#'
-#' updatedCollection <- arv$collections.update(list(name = "New name", description = "New description"),
-#'                                             "uuid")
-#'
-#' createdCollection <- arv$collections.create(list(name = "Example",
-#'                                                  description = "This is a test collection"))
-#' }
-NULL
-
-#' @export
-Arvados <- R6::R6Class(
-
-	"Arvados",
-
-	public = list(
-
-		initialize = function(authToken = NULL, hostName = NULL, numRetries = 0)
-		{
-			if(!is.null(hostName))
-				Sys.setenv(ARVADOS_API_HOST = hostName)
-
-			if(!is.null(authToken))
-				Sys.setenv(ARVADOS_API_TOKEN = authToken)
-
-			hostName <- Sys.getenv("ARVADOS_API_HOST")
-			token    <- Sys.getenv("ARVADOS_API_TOKEN")
-
-			if(hostName == "" | token == "")
-				stop(paste("Please provide host name and authentification token",
-						   "or set ARVADOS_API_HOST and ARVADOS_API_TOKEN",
-						   "environment variables."))
-
-			private$token <- token
-			private$host  <- paste0("https://", hostName, "/arvados/v1/")
-			private$numRetries <- numRetries
-			private$REST <- RESTService$new(token, hostName,
-			                                HttpRequest$new(), HttpParser$new(),
-			                                numRetries)
-
-		},
-
-		projects.get = function(uuid)
-		{
-			self$groups.get(uuid)
-		},
-
-		projects.create = function(group, ensure_unique_name = "false")
-		{
-			group <- c("group_class" = "project", group)
-			self$groups.create(group, ensure_unique_name)
-		},
-
-		projects.update = function(group, uuid)
-		{
-			group <- c("group_class" = "project", group)
-			self$groups.update(group, uuid)
-		},
-
-		projects.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact",
-			include_trash = NULL)
-		{
-			filters[[length(filters) + 1]] <- list("group_class", "=", "project")
-			self$groups.list(filters, where, order, select, distinct,
-			                 limit, offset, count, include_trash)
-		},
-
-		projects.delete = function(uuid)
-		{
-			self$groups.delete(uuid)
-		},
-
-		users.get = function(uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.create = function(user, ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("users")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(user) > 0)
-				body <- jsonlite::toJSON(list(user = user), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.update = function(user, uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(user) > 0)
-				body <- jsonlite::toJSON(list(user = user), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.delete = function(uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.current = function()
-		{
-			endPoint <- stringr::str_interp("users/current")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.system = function()
-		{
-			endPoint <- stringr::str_interp("users/system")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.activate = function(uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}/activate")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.setup = function(user = NULL, openid_prefix = NULL,
-			repo_name = NULL, vm_uuid = NULL, send_notification_email = "false")
-		{
-			endPoint <- stringr::str_interp("users/setup")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(user = user, openid_prefix = openid_prefix,
-							  repo_name = repo_name, vm_uuid = vm_uuid,
-							  send_notification_email = send_notification_email)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.unsetup = function(uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}/unsetup")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.update_uuid = function(uuid, new_uuid)
-		{
-			endPoint <- stringr::str_interp("users/${uuid}/update_uuid")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(new_uuid = new_uuid)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.merge = function(new_owner_uuid, new_user_token,
-			redirect_to_new_user = NULL)
-		{
-			endPoint <- stringr::str_interp("users/merge")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(new_owner_uuid = new_owner_uuid,
-							  new_user_token = new_user_token, redirect_to_new_user = redirect_to_new_user)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		users.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
-		{
-			endPoint <- stringr::str_interp("users")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.get = function(uuid)
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.create = function(apiclientauthorization,
-			ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(apiclientauthorization) > 0)
-				body <- jsonlite::toJSON(list(apiclientauthorization = apiclientauthorization), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.update = function(apiclientauthorization, uuid)
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(apiclientauthorization) > 0)
-				body <- jsonlite::toJSON(list(apiclientauthorization = apiclientauthorization), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.delete = function(uuid)
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.create_system_auth = function(api_client_id = NULL, scopes = NULL)
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations/create_system_auth")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(api_client_id = api_client_id,
-							  scopes = scopes)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.current = function()
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations/current")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_client_authorizations.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
-		{
-			endPoint <- stringr::str_interp("api_client_authorizations")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.get = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.create = function(container, ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("containers")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(container) > 0)
-				body <- jsonlite::toJSON(list(container = container), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.update = function(container, uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(container) > 0)
-				body <- jsonlite::toJSON(list(container = container), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.delete = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.auth = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}/auth")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.lock = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}/lock")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.unlock = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}/unlock")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.secret_mounts = function(uuid)
-		{
-			endPoint <- stringr::str_interp("containers/${uuid}/secret_mounts")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.current = function()
-		{
-			endPoint <- stringr::str_interp("containers/current")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		containers.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
-		{
-			endPoint <- stringr::str_interp("containers")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_clients.get = function(uuid)
-		{
-			endPoint <- stringr::str_interp("api_clients/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_clients.create = function(apiclient, ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("api_clients")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(apiclient) > 0)
-				body <- jsonlite::toJSON(list(apiclient = apiclient), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_clients.update = function(apiclient, uuid)
-		{
-			endPoint <- stringr::str_interp("api_clients/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(apiclient) > 0)
-				body <- jsonlite::toJSON(list(apiclient = apiclient), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		api_clients.delete = function(uuid)
-		{
-			endPoint <- stringr::str_interp("api_clients/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+#' Arvados
+#'
+#' Arvados class gives users ability to access Arvados REST API.
+#'
+#' @section Usage:
+#' \preformatted{arv = Arvados$new(authToken = NULL, hostName = NULL, numRetries = 0)}
+#'
+#' @section Arguments:
+#' \describe{
+#' 	\item{authToken}{Authentification token. If not specified ARVADOS_API_TOKEN environment variable will be used.}
+#' 	\item{hostName}{Host name. If not specified ARVADOS_API_HOST environment variable will be used.}
+#' 	\item{numRetries}{Number which specifies how many times to retry failed service requests.}
+#' }
+#'
+#' @section Methods:
+#' \describe{
+#' 	\item{}{\code{\link{api_client_authorizations.create}}}
+#' 	\item{}{\code{\link{api_client_authorizations.create_system_auth}}}
+#' 	\item{}{\code{\link{api_client_authorizations.current}}}
+#' 	\item{}{\code{\link{api_client_authorizations.delete}}}
+#' 	\item{}{\code{\link{api_client_authorizations.get}}}
+#' 	\item{}{\code{\link{api_client_authorizations.list}}}
+#' 	\item{}{\code{\link{api_client_authorizations.update}}}
+#' 	\item{}{\code{\link{api_clients.create}}}
+#' 	\item{}{\code{\link{api_clients.delete}}}
+#' 	\item{}{\code{\link{api_clients.get}}}
+#' 	\item{}{\code{\link{api_clients.list}}}
+#' 	\item{}{\code{\link{api_clients.update}}}
+#' 	\item{}{\code{\link{authorized_keys.create}}}
+#' 	\item{}{\code{\link{authorized_keys.delete}}}
+#' 	\item{}{\code{\link{authorized_keys.get}}}
+#' 	\item{}{\code{\link{authorized_keys.list}}}
+#' 	\item{}{\code{\link{authorized_keys.update}}}
+#' 	\item{}{\code{\link{collections.create}}}
+#' 	\item{}{\code{\link{collections.delete}}}
+#' 	\item{}{\code{\link{collections.get}}}
+#' 	\item{}{\code{\link{collections.list}}}
+#' 	\item{}{\code{\link{collections.provenance}}}
+#' 	\item{}{\code{\link{collections.trash}}}
+#' 	\item{}{\code{\link{collections.untrash}}}
+#' 	\item{}{\code{\link{collections.update}}}
+#' 	\item{}{\code{\link{collections.used_by}}}
+#' 	\item{}{\code{\link{configs.get}}}
+#' 	\item{}{\code{\link{container_requests.create}}}
+#' 	\item{}{\code{\link{container_requests.delete}}}
+#' 	\item{}{\code{\link{container_requests.get}}}
+#' 	\item{}{\code{\link{container_requests.list}}}
+#' 	\item{}{\code{\link{container_requests.update}}}
+#' 	\item{}{\code{\link{containers.auth}}}
+#' 	\item{}{\code{\link{containers.create}}}
+#' 	\item{}{\code{\link{containers.current}}}
+#' 	\item{}{\code{\link{containers.delete}}}
+#' 	\item{}{\code{\link{containers.get}}}
+#' 	\item{}{\code{\link{containers.list}}}
+#' 	\item{}{\code{\link{containers.lock}}}
+#' 	\item{}{\code{\link{containers.secret_mounts}}}
+#' 	\item{}{\code{\link{containers.unlock}}}
+#' 	\item{}{\code{\link{containers.update}}}
+#' 	\item{}{\code{\link{groups.contents}}}
+#' 	\item{}{\code{\link{groups.create}}}
+#' 	\item{}{\code{\link{groups.delete}}}
+#' 	\item{}{\code{\link{groups.get}}}
+#' 	\item{}{\code{\link{groups.list}}}
+#' 	\item{}{\code{\link{groups.shared}}}
+#' 	\item{}{\code{\link{groups.trash}}}
+#' 	\item{}{\code{\link{groups.untrash}}}
+#' 	\item{}{\code{\link{groups.update}}}
+#' 	\item{}{\code{\link{keep_services.accessible}}}
+#' 	\item{}{\code{\link{keep_services.create}}}
+#' 	\item{}{\code{\link{keep_services.delete}}}
+#' 	\item{}{\code{\link{keep_services.get}}}
+#' 	\item{}{\code{\link{keep_services.list}}}
+#' 	\item{}{\code{\link{keep_services.update}}}
+#' 	\item{}{\code{\link{links.create}}}
+#' 	\item{}{\code{\link{links.delete}}}
+#' 	\item{}{\code{\link{links.get}}}
+#' 	\item{}{\code{\link{links.get_permissions}}}
+#' 	\item{}{\code{\link{links.list}}}
+#' 	\item{}{\code{\link{links.update}}}
+#' 	\item{}{\code{\link{logs.create}}}
+#' 	\item{}{\code{\link{logs.delete}}}
+#' 	\item{}{\code{\link{logs.get}}}
+#' 	\item{}{\code{\link{logs.list}}}
+#' 	\item{}{\code{\link{logs.update}}}
+#' 	\item{}{\code{\link{projects.create}}}
+#' 	\item{}{\code{\link{projects.delete}}}
+#' 	\item{}{\code{\link{projects.get}}}
+#' 	\item{}{\code{\link{projects.list}}}
+#' 	\item{}{\code{\link{projects.update}}}
+#' 	\item{}{\code{\link{repositories.create}}}
+#' 	\item{}{\code{\link{repositories.delete}}}
+#' 	\item{}{\code{\link{repositories.get}}}
+#' 	\item{}{\code{\link{repositories.get_all_permissions}}}
+#' 	\item{}{\code{\link{repositories.list}}}
+#' 	\item{}{\code{\link{repositories.update}}}
+#' 	\item{}{\code{\link{user_agreements.create}}}
+#' 	\item{}{\code{\link{user_agreements.delete}}}
+#' 	\item{}{\code{\link{user_agreements.get}}}
+#' 	\item{}{\code{\link{user_agreements.list}}}
+#' 	\item{}{\code{\link{user_agreements.new}}}
+#' 	\item{}{\code{\link{user_agreements.sign}}}
+#' 	\item{}{\code{\link{user_agreements.signatures}}}
+#' 	\item{}{\code{\link{user_agreements.update}}}
+#' 	\item{}{\code{\link{users.activate}}}
+#' 	\item{}{\code{\link{users.create}}}
+#' 	\item{}{\code{\link{users.current}}}
+#' 	\item{}{\code{\link{users.delete}}}
+#' 	\item{}{\code{\link{users.get}}}
+#' 	\item{}{\code{\link{users.list}}}
+#' 	\item{}{\code{\link{users.merge}}}
+#' 	\item{}{\code{\link{users.setup}}}
+#' 	\item{}{\code{\link{users.system}}}
+#' 	\item{}{\code{\link{users.unsetup}}}
+#' 	\item{}{\code{\link{users.update}}}
+#' 	\item{}{\code{\link{users.update_uuid}}}
+#' 	\item{}{\code{\link{virtual_machines.create}}}
+#' 	\item{}{\code{\link{virtual_machines.delete}}}
+#' 	\item{}{\code{\link{virtual_machines.get}}}
+#' 	\item{}{\code{\link{virtual_machines.get_all_logins}}}
+#' 	\item{}{\code{\link{virtual_machines.list}}}
+#' 	\item{}{\code{\link{virtual_machines.logins}}}
+#' 	\item{}{\code{\link{virtual_machines.update}}}
+#' 	\item{}{\code{\link{workflows.create}}}
+#' 	\item{}{\code{\link{workflows.delete}}}
+#' 	\item{}{\code{\link{workflows.get}}}
+#' 	\item{}{\code{\link{workflows.list}}}
+#' 	\item{}{\code{\link{workflows.update}}}
+#' }
+#'
+#' @name Arvados
+#' @examples
+#' \dontrun{
+#' arv <- Arvados$new("your Arvados token", "example.arvadosapi.com")
+#'
+#' collection <- arv$collections.get("uuid")
+#'
+#' collectionList <- arv$collections.list(list(list("name", "like", "Test%")))
+#' collectionList <- listAll(arv$collections.list, list(list("name", "like", "Test%")))
+#'
+#' deletedCollection <- arv$collections.delete("uuid")
+#'
+#' updatedCollection <- arv$collections.update(list(name = "New name", description = "New description"),
+#'                                             "uuid")
+#'
+#' createdCollection <- arv$collections.create(list(name = "Example",
+#'                                                  description = "This is a test collection"))
+#' }
+NULL
 
-		api_clients.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
-		{
-			endPoint <- stringr::str_interp("api_clients")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+#' @export
+Arvados <- R6::R6Class(
 
-		container_requests.get = function(uuid)
-		{
-			endPoint <- stringr::str_interp("container_requests/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+	"Arvados",
 
-		container_requests.create = function(containerrequest,
-			ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("container_requests")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(containerrequest) > 0)
-				body <- jsonlite::toJSON(list(containerrequest = containerrequest), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+	public = list(
 
-		container_requests.update = function(containerrequest, uuid)
+		initialize = function(authToken = NULL, hostName = NULL, numRetries = 0)
 		{
-			endPoint <- stringr::str_interp("container_requests/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(containerrequest) > 0)
-				body <- jsonlite::toJSON(list(containerrequest = containerrequest), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+			if(!is.null(hostName))
+				Sys.setenv(ARVADOS_API_HOST = hostName)
 
-		container_requests.delete = function(uuid)
-		{
-			endPoint <- stringr::str_interp("container_requests/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
+			if(!is.null(authToken))
+				Sys.setenv(ARVADOS_API_TOKEN = authToken)
+
+			hostName <- Sys.getenv("ARVADOS_API_HOST")
+			token    <- Sys.getenv("ARVADOS_API_TOKEN")
+
+			if(hostName == "" | token == "")
+				stop(paste("Please provide host name and authentification token",
+						   "or set ARVADOS_API_HOST and ARVADOS_API_TOKEN",
+						   "environment variables."))
+
+			private$token <- token
+			private$host  <- paste0("https://", hostName, "/arvados/v1/")
+			private$numRetries <- numRetries
+			private$REST <- RESTService$new(token, hostName,
+			                                HttpRequest$new(), HttpParser$new(),
+			                                numRetries)
 
-		container_requests.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
-		{
-			endPoint <- stringr::str_interp("container_requests")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
 		},
 
-		authorized_keys.get = function(uuid)
+		projects.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
+			self$groups.get(uuid)
 		},
 
-		authorized_keys.create = function(authorizedkey,
-			ensure_unique_name = "false")
+		projects.create = function(group, ensure_unique_name = "false")
 		{
-			endPoint <- stringr::str_interp("authorized_keys")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(authorizedkey) > 0)
-				body <- jsonlite::toJSON(list(authorizedkey = authorizedkey), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
+			group <- c("group_class" = "project", group)
+			self$groups.create(group, ensure_unique_name)
 		},
 
-		authorized_keys.update = function(authorizedkey, uuid)
+		projects.update = function(group, uuid)
 		{
-			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(authorizedkey) > 0)
-				body <- jsonlite::toJSON(list(authorizedkey = authorizedkey), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
+			group <- c("group_class" = "project", group)
+			self$groups.update(group, uuid)
 		},
 
-		authorized_keys.delete = function(uuid)
+		projects.list = function(filters = NULL, where = NULL,
+			order = NULL, select = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			include_trash = NULL)
 		{
-			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
+			filters[[length(filters) + 1]] <- list("group_class", "=", "project")
+			self$groups.list(filters, where, order, select, distinct,
+			                 limit, offset, count, include_trash)
 		},
 
-		authorized_keys.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
-		{
-			endPoint <- stringr::str_interp("authorized_keys")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
+		projects.delete = function(uuid)
+		{
+			self$groups.delete(uuid)
 		},
 
-		collections.get = function(uuid)
+		api_clients.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}")
+			endPoint <- stringr::str_interp("api_clients/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3229,16 +1656,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.create = function(collection, ensure_unique_name = "false")
+		api_clients.create = function(apiclient,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("collections")
+			endPoint <- stringr::str_interp("api_clients")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(collection) > 0)
-				body <- jsonlite::toJSON(list(collection = collection), 
+			if(length(apiclient) > 0)
+				body <- jsonlite::toJSON(list(apiclient = apiclient), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3253,16 +1682,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.update = function(collection, uuid)
+		api_clients.update = function(apiclient, uuid)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}")
+			endPoint <- stringr::str_interp("api_clients/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(collection) > 0)
-				body <- jsonlite::toJSON(list(collection = collection), 
+			if(length(apiclient) > 0)
+				body <- jsonlite::toJSON(list(apiclient = apiclient), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3277,11 +1706,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.delete = function(uuid)
+		api_clients.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}")
+			endPoint <- stringr::str_interp("api_clients/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3297,13 +1726,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.provenance = function(uuid)
+		api_clients.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}/provenance")
+			endPoint <- stringr::str_interp("api_clients")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(filters = filters, where = where,
+							  order = order, select = select, distinct = distinct,
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -3317,11 +1752,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.used_by = function(uuid)
+		api_client_authorizations.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}/used_by")
+			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3337,15 +1772,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.trash = function(uuid)
+		api_client_authorizations.create = function(apiclientauthorization,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}/trash")
+			endPoint <- stringr::str_interp("api_client_authorizations")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			body <- NULL
+			if(length(apiclientauthorization) > 0)
+				body <- jsonlite::toJSON(list(apiclientauthorization = apiclientauthorization), 
+				                         auto_unbox = TRUE)
+			else
+				body <- NULL
 			
 			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
@@ -3357,43 +1798,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		collections.untrash = function(uuid)
+		api_client_authorizations.update = function(apiclientauthorization, uuid)
 		{
-			endPoint <- stringr::str_interp("collections/${uuid}/untrash")
+			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		collections.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact", include_trash = NULL)
-		{
-			endPoint <- stringr::str_interp("collections")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count,
-							  include_trash = include_trash)
-			
-			body <- NULL
+			if(length(apiclientauthorization) > 0)
+				body <- jsonlite::toJSON(list(apiclientauthorization = apiclientauthorization), 
+				                         auto_unbox = TRUE)
+			else
+				body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("PUT", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -3403,17 +1822,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		humans.get = function(uuid)
+		api_client_authorizations.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("humans/${uuid}")
+			endPoint <- stringr::str_interp("api_client_authorizations/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("DELETE", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -3423,19 +1842,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		humans.create = function(human, ensure_unique_name = "false")
+		api_client_authorizations.create_system_auth = function(api_client_id = NULL, scopes = NULL)
 		{
-			endPoint <- stringr::str_interp("humans")
+			endPoint <- stringr::str_interp("api_client_authorizations/create_system_auth")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(api_client_id = api_client_id,
+							  scopes = scopes)
 			
-			if(length(human) > 0)
-				body <- jsonlite::toJSON(list(human = human), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
 			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
@@ -3447,41 +1863,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		humans.update = function(human, uuid)
-		{
-			endPoint <- stringr::str_interp("humans/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(human) > 0)
-				body <- jsonlite::toJSON(list(human = human), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		humans.delete = function(uuid)
+		api_client_authorizations.current = function()
 		{
-			endPoint <- stringr::str_interp("humans/${uuid}")
+			endPoint <- stringr::str_interp("api_client_authorizations/current")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -3491,17 +1883,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		humans.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		api_client_authorizations.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("humans")
+			endPoint <- stringr::str_interp("api_client_authorizations")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -3515,11 +1909,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		job_tasks.get = function(uuid)
+		authorized_keys.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("job_tasks/${uuid}")
+			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3535,16 +1929,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		job_tasks.create = function(jobtask, ensure_unique_name = "false")
+		authorized_keys.create = function(authorizedkey,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("job_tasks")
+			endPoint <- stringr::str_interp("authorized_keys")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(jobtask) > 0)
-				body <- jsonlite::toJSON(list(jobtask = jobtask), 
+			if(length(authorizedkey) > 0)
+				body <- jsonlite::toJSON(list(authorizedkey = authorizedkey), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3559,16 +1955,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		job_tasks.update = function(jobtask, uuid)
+		authorized_keys.update = function(authorizedkey, uuid)
 		{
-			endPoint <- stringr::str_interp("job_tasks/${uuid}")
+			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(jobtask) > 0)
-				body <- jsonlite::toJSON(list(jobtask = jobtask), 
+			if(length(authorizedkey) > 0)
+				body <- jsonlite::toJSON(list(authorizedkey = authorizedkey), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3583,11 +1979,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		job_tasks.delete = function(uuid)
+		authorized_keys.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("job_tasks/${uuid}")
+			endPoint <- stringr::str_interp("authorized_keys/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3603,18 +1999,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		job_tasks.list = function(filters = NULL,
+		authorized_keys.list = function(filters = NULL,
 			where = NULL, order = NULL, select = NULL,
 			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("job_tasks")
+			endPoint <- stringr::str_interp("authorized_keys")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -3628,11 +2025,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.get = function(uuid)
+		collections.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/${uuid}")
+			endPoint <- stringr::str_interp("collections/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3648,21 +2045,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.create = function(job, ensure_unique_name = "false",
-			find_or_create = "false", filters = NULL,
-			minimum_script_version = NULL, exclude_script_versions = NULL)
+		collections.create = function(collection,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("jobs")
+			endPoint <- stringr::str_interp("collections")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(ensure_unique_name = ensure_unique_name,
-							  find_or_create = find_or_create, filters = filters,
-							  minimum_script_version = minimum_script_version,
-							  exclude_script_versions = exclude_script_versions)
+							  cluster_id = cluster_id)
 			
-			if(length(job) > 0)
-				body <- jsonlite::toJSON(list(job = job), 
+			if(length(collection) > 0)
+				body <- jsonlite::toJSON(list(collection = collection), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3677,16 +2071,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.update = function(job, uuid)
+		collections.update = function(collection, uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/${uuid}")
+			endPoint <- stringr::str_interp("collections/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(job) > 0)
-				body <- jsonlite::toJSON(list(job = job), 
+			if(length(collection) > 0)
+				body <- jsonlite::toJSON(list(collection = collection), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3701,11 +2095,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.delete = function(uuid)
+		collections.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/${uuid}")
+			endPoint <- stringr::str_interp("collections/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3721,17 +2115,13 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.queue = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		collections.provenance = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/queue")
+			endPoint <- stringr::str_interp("collections/${uuid}/provenance")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
@@ -3745,11 +2135,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.queue_size = function()
+		collections.used_by = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/queue_size")
+			endPoint <- stringr::str_interp("collections/${uuid}/used_by")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3765,11 +2155,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.cancel = function(uuid)
+		collections.trash = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/${uuid}/cancel")
+			endPoint <- stringr::str_interp("collections/${uuid}/trash")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3785,11 +2175,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.lock = function(uuid)
+		collections.untrash = function(uuid)
 		{
-			endPoint <- stringr::str_interp("jobs/${uuid}/lock")
+			endPoint <- stringr::str_interp("collections/${uuid}/untrash")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3805,17 +2195,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		jobs.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		collections.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL,
+			include_trash = NULL, include_old_versions = NULL)
 		{
-			endPoint <- stringr::str_interp("jobs")
+			endPoint <- stringr::str_interp("collections")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation,
+							  include_trash = include_trash, include_old_versions = include_old_versions)
 			
 			body <- NULL
 			
@@ -3829,11 +2223,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_disks.get = function(uuid)
+		containers.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("keep_disks/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3849,16 +2243,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_disks.create = function(keepdisk, ensure_unique_name = "false")
+		containers.create = function(container, ensure_unique_name = "false",
+			cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("keep_disks")
+			endPoint <- stringr::str_interp("containers")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(keepdisk) > 0)
-				body <- jsonlite::toJSON(list(keepdisk = keepdisk), 
+			if(length(container) > 0)
+				body <- jsonlite::toJSON(list(container = container), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3873,16 +2269,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_disks.update = function(keepdisk, uuid)
+		containers.update = function(container, uuid)
 		{
-			endPoint <- stringr::str_interp("keep_disks/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(keepdisk) > 0)
-				body <- jsonlite::toJSON(list(keepdisk = keepdisk), 
+			if(length(container) > 0)
+				body <- jsonlite::toJSON(list(container = container), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -3897,11 +2293,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_disks.delete = function(uuid)
+		containers.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("keep_disks/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -3917,43 +2313,13 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_disks.ping = function(uuid = NULL, ping_secret,
-			node_uuid = NULL, filesystem_uuid = NULL,
-			service_host = NULL, service_port, service_ssl_flag)
-		{
-			endPoint <- stringr::str_interp("keep_disks/ping")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(uuid = uuid, ping_secret = ping_secret,
-							  node_uuid = node_uuid, filesystem_uuid = filesystem_uuid,
-							  service_host = service_host, service_port = service_port,
-							  service_ssl_flag = service_ssl_flag)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		keep_disks.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+		containers.auth = function(uuid)
 		{
-			endPoint <- stringr::str_interp("keep_disks")
+			endPoint <- stringr::str_interp("containers/${uuid}/auth")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
@@ -3967,42 +2333,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		nodes.get = function(uuid)
+		containers.lock = function(uuid)
 		{
-			endPoint <- stringr::str_interp("nodes/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}/lock")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		nodes.create = function(node, ensure_unique_name = "false",
-			assign_slot = NULL)
-		{
-			endPoint <- stringr::str_interp("nodes")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name,
-							  assign_slot = assign_slot)
-			
-			if(length(node) > 0)
-				body <- jsonlite::toJSON(list(node = node), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
 			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
@@ -4013,21 +2353,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		nodes.update = function(node, uuid, assign_slot = NULL)
+		containers.unlock = function(uuid)
 		{
-			endPoint <- stringr::str_interp("nodes/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}/unlock")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(assign_slot = assign_slot)
+			queryArgs <- NULL
 			
-			if(length(node) > 0)
-				body <- jsonlite::toJSON(list(node = node), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
-			response <- private$REST$http$exec("PUT", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4037,17 +2373,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		nodes.delete = function(uuid)
+		containers.secret_mounts = function(uuid)
 		{
-			endPoint <- stringr::str_interp("nodes/${uuid}")
+			endPoint <- stringr::str_interp("containers/${uuid}/secret_mounts")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4057,17 +2393,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		nodes.ping = function(uuid, ping_secret)
+		containers.current = function()
 		{
-			endPoint <- stringr::str_interp("nodes/${uuid}/ping")
+			endPoint <- stringr::str_interp("containers/current")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ping_secret = ping_secret)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("POST", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4077,17 +2413,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		nodes.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		containers.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("nodes")
+			endPoint <- stringr::str_interp("containers")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -4101,11 +2439,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		links.get = function(uuid)
+		container_requests.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("links/${uuid}")
+			endPoint <- stringr::str_interp("container_requests/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4121,16 +2459,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		links.create = function(link, ensure_unique_name = "false")
+		container_requests.create = function(containerrequest,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("links")
+			endPoint <- stringr::str_interp("container_requests")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(link) > 0)
-				body <- jsonlite::toJSON(list(link = link), 
+			if(length(containerrequest) > 0)
+				body <- jsonlite::toJSON(list(containerrequest = containerrequest), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4145,16 +2485,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		links.update = function(link, uuid)
+		container_requests.update = function(containerrequest, uuid)
 		{
-			endPoint <- stringr::str_interp("links/${uuid}")
+			endPoint <- stringr::str_interp("container_requests/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(link) > 0)
-				body <- jsonlite::toJSON(list(link = link), 
+			if(length(containerrequest) > 0)
+				body <- jsonlite::toJSON(list(containerrequest = containerrequest), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4169,11 +2509,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		links.delete = function(uuid)
+		container_requests.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("links/${uuid}")
+			endPoint <- stringr::str_interp("container_requests/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4189,37 +2529,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		links.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		container_requests.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL,
+			include_trash = NULL)
 		{
-			endPoint <- stringr::str_interp("links")
+			endPoint <- stringr::str_interp("container_requests")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
-			
-			body <- NULL
-			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		links.get_permissions = function(uuid)
-		{
-			endPoint <- stringr::str_interp("permissions/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation,
+							  include_trash = include_trash)
 			
 			body <- NULL
 			
@@ -4233,11 +2557,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.get = function(uuid)
+		groups.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("keep_services/${uuid}")
+			endPoint <- stringr::str_interp("groups/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4253,17 +2577,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.create = function(keepservice,
-			ensure_unique_name = "false")
+		groups.create = function(group, ensure_unique_name = "false",
+			cluster_id = NULL, async = "false")
 		{
-			endPoint <- stringr::str_interp("keep_services")
+			endPoint <- stringr::str_interp("groups")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id, async = async)
 			
-			if(length(keepservice) > 0)
-				body <- jsonlite::toJSON(list(keepservice = keepservice), 
+			if(length(group) > 0)
+				body <- jsonlite::toJSON(list(group = group), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4278,16 +2603,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.update = function(keepservice, uuid)
+		groups.update = function(group, uuid, async = "false")
 		{
-			endPoint <- stringr::str_interp("keep_services/${uuid}")
+			endPoint <- stringr::str_interp("groups/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(async = async)
 			
-			if(length(keepservice) > 0)
-				body <- jsonlite::toJSON(list(keepservice = keepservice), 
+			if(length(group) > 0)
+				body <- jsonlite::toJSON(list(group = group), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4302,11 +2627,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.delete = function(uuid)
+		groups.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("keep_services/${uuid}")
+			endPoint <- stringr::str_interp("groups/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4322,13 +2647,22 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.accessible = function()
+		groups.contents = function(filters = NULL,
+			where = NULL, order = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			cluster_id = NULL, bypass_federation = NULL,
+			include_trash = NULL, uuid = NULL, recursive = NULL,
+			include = NULL)
 		{
-			endPoint <- stringr::str_interp("keep_services/accessible")
+			endPoint <- stringr::str_interp("groups/contents")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(filters = filters, where = where,
+							  order = order, distinct = distinct, limit = limit,
+							  offset = offset, count = count, cluster_id = cluster_id,
+							  bypass_federation = bypass_federation, include_trash = include_trash,
+							  uuid = uuid, recursive = recursive, include = include)
 			
 			body <- NULL
 			
@@ -4342,18 +2676,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		keep_services.list = function(filters = NULL,
+		groups.shared = function(filters = NULL,
 			where = NULL, order = NULL, select = NULL,
 			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+			count = "exact", cluster_id = NULL, bypass_federation = NULL,
+			include_trash = NULL, include = NULL)
 		{
-			endPoint <- stringr::str_interp("keep_services")
+			endPoint <- stringr::str_interp("groups/shared")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation,
+							  include_trash = include_trash, include = include)
 			
 			body <- NULL
 			
@@ -4367,41 +2704,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_templates.get = function(uuid)
+		groups.trash = function(uuid)
 		{
-			endPoint <- stringr::str_interp("pipeline_templates/${uuid}")
+			endPoint <- stringr::str_interp("groups/${uuid}/trash")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		pipeline_templates.create = function(pipelinetemplate,
-			ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("pipeline_templates")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(pipelinetemplate) > 0)
-				body <- jsonlite::toJSON(list(pipelinetemplate = pipelinetemplate), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
 			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
@@ -4412,41 +2724,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_templates.update = function(pipelinetemplate, uuid)
-		{
-			endPoint <- stringr::str_interp("pipeline_templates/${uuid}")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- NULL
-			
-			if(length(pipelinetemplate) > 0)
-				body <- jsonlite::toJSON(list(pipelinetemplate = pipelinetemplate), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("PUT", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		pipeline_templates.delete = function(uuid)
+		groups.untrash = function(uuid)
 		{
-			endPoint <- stringr::str_interp("pipeline_templates/${uuid}")
+			endPoint <- stringr::str_interp("groups/${uuid}/untrash")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4456,18 +2744,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_templates.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+		groups.list = function(filters = NULL, where = NULL,
+			order = NULL, select = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			cluster_id = NULL, bypass_federation = NULL,
+			include_trash = NULL)
 		{
-			endPoint <- stringr::str_interp("pipeline_templates")
+			endPoint <- stringr::str_interp("groups")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation,
+							  include_trash = include_trash)
 			
 			body <- NULL
 			
@@ -4481,11 +2772,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.get = function(uuid)
+		keep_services.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("pipeline_instances/${uuid}")
+			endPoint <- stringr::str_interp("keep_services/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4501,17 +2792,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.create = function(pipelineinstance,
-			ensure_unique_name = "false")
+		keep_services.create = function(keepservice,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("pipeline_instances")
+			endPoint <- stringr::str_interp("keep_services")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(pipelineinstance) > 0)
-				body <- jsonlite::toJSON(list(pipelineinstance = pipelineinstance), 
+			if(length(keepservice) > 0)
+				body <- jsonlite::toJSON(list(keepservice = keepservice), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4526,16 +2818,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.update = function(pipelineinstance, uuid)
+		keep_services.update = function(keepservice, uuid)
 		{
-			endPoint <- stringr::str_interp("pipeline_instances/${uuid}")
+			endPoint <- stringr::str_interp("keep_services/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(pipelineinstance) > 0)
-				body <- jsonlite::toJSON(list(pipelineinstance = pipelineinstance), 
+			if(length(keepservice) > 0)
+				body <- jsonlite::toJSON(list(keepservice = keepservice), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4550,11 +2842,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.delete = function(uuid)
+		keep_services.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("pipeline_instances/${uuid}")
+			endPoint <- stringr::str_interp("keep_services/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4570,17 +2862,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.cancel = function(uuid)
+		keep_services.accessible = function()
 		{
-			endPoint <- stringr::str_interp("pipeline_instances/${uuid}/cancel")
+			endPoint <- stringr::str_interp("keep_services/accessible")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("POST", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4590,18 +2882,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		pipeline_instances.list = function(filters = NULL,
+		keep_services.list = function(filters = NULL,
 			where = NULL, order = NULL, select = NULL,
 			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("pipeline_instances")
+			endPoint <- stringr::str_interp("keep_services")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -4615,11 +2908,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.get = function(uuid)
+		links.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("repositories/${uuid}")
+			endPoint <- stringr::str_interp("links/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4635,16 +2928,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.create = function(repository, ensure_unique_name = "false")
+		links.create = function(link, ensure_unique_name = "false",
+			cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("repositories")
+			endPoint <- stringr::str_interp("links")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(repository) > 0)
-				body <- jsonlite::toJSON(list(repository = repository), 
+			if(length(link) > 0)
+				body <- jsonlite::toJSON(list(link = link), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4659,16 +2954,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.update = function(repository, uuid)
+		links.update = function(link, uuid)
 		{
-			endPoint <- stringr::str_interp("repositories/${uuid}")
+			endPoint <- stringr::str_interp("links/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(repository) > 0)
-				body <- jsonlite::toJSON(list(repository = repository), 
+			if(length(link) > 0)
+				body <- jsonlite::toJSON(list(link = link), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4683,11 +2978,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.delete = function(uuid)
+		links.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("repositories/${uuid}")
+			endPoint <- stringr::str_interp("links/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4703,13 +2998,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.get_all_permissions = function()
+		links.list = function(filters = NULL, where = NULL,
+			order = NULL, select = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("repositories/get_all_permissions")
+			endPoint <- stringr::str_interp("links")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(filters = filters, where = where,
+							  order = order, select = select, distinct = distinct,
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -4723,18 +3024,13 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		repositories.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+		links.get_permissions = function(uuid)
 		{
-			endPoint <- stringr::str_interp("repositories")
+			endPoint <- stringr::str_interp("permissions/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
@@ -4748,11 +3044,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		specimens.get = function(uuid)
+		logs.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("specimens/${uuid}")
+			endPoint <- stringr::str_interp("logs/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4768,16 +3064,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		specimens.create = function(specimen, ensure_unique_name = "false")
+		logs.create = function(log, ensure_unique_name = "false",
+			cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("specimens")
+			endPoint <- stringr::str_interp("logs")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(specimen) > 0)
-				body <- jsonlite::toJSON(list(specimen = specimen), 
+			if(length(log) > 0)
+				body <- jsonlite::toJSON(list(log = log), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4792,16 +3090,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		specimens.update = function(specimen, uuid)
+		logs.update = function(log, uuid)
 		{
-			endPoint <- stringr::str_interp("specimens/${uuid}")
+			endPoint <- stringr::str_interp("logs/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(specimen) > 0)
-				body <- jsonlite::toJSON(list(specimen = specimen), 
+			if(length(log) > 0)
+				body <- jsonlite::toJSON(list(log = log), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4816,11 +3114,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		specimens.delete = function(uuid)
+		logs.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("specimens/${uuid}")
+			endPoint <- stringr::str_interp("logs/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4836,18 +3134,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		specimens.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+		logs.list = function(filters = NULL, where = NULL,
+			order = NULL, select = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("specimens")
+			endPoint <- stringr::str_interp("logs")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -4861,11 +3160,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		logs.get = function(uuid)
+		users.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("logs/${uuid}")
+			endPoint <- stringr::str_interp("users/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -4881,16 +3180,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		logs.create = function(log, ensure_unique_name = "false")
+		users.create = function(user, ensure_unique_name = "false",
+			cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("logs")
+			endPoint <- stringr::str_interp("users")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(log) > 0)
-				body <- jsonlite::toJSON(list(log = log), 
+			if(length(user) > 0)
+				body <- jsonlite::toJSON(list(user = user), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -4905,21 +3206,41 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		logs.update = function(log, uuid)
+		users.update = function(user, uuid, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("logs/${uuid}")
+			endPoint <- stringr::str_interp("users/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(bypass_federation = bypass_federation)
 			
-			if(length(log) > 0)
-				body <- jsonlite::toJSON(list(log = log), 
+			if(length(user) > 0)
+				body <- jsonlite::toJSON(list(user = user), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
 			
-			response <- private$REST$http$exec("PUT", url, headers, body,
+			response <- private$REST$http$exec("PUT", url, headers, body,
+			                                   queryArgs, private$numRetries)
+			resource <- private$REST$httpParser$parseJSONResponse(response)
+			
+			if(!is.null(resource$errors))
+				stop(resource$errors)
+			
+			resource
+		},
+
+		users.delete = function(uuid)
+		{
+			endPoint <- stringr::str_interp("users/${uuid}")
+			url <- paste0(private$host, endPoint)
+			headers <- list(Authorization = paste("Bearer", private$token), 
+			                "Content-Type" = "application/json")
+			queryArgs <- NULL
+			
+			body <- NULL
+			
+			response <- private$REST$http$exec("DELETE", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4929,17 +3250,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		logs.delete = function(uuid)
+		users.current = function()
 		{
-			endPoint <- stringr::str_interp("logs/${uuid}")
+			endPoint <- stringr::str_interp("users/current")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4949,17 +3270,13 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		logs.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		users.system = function()
 		{
-			endPoint <- stringr::str_interp("logs")
+			endPoint <- stringr::str_interp("users/system")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
@@ -4973,17 +3290,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		traits.get = function(uuid)
+		users.activate = function(uuid)
 		{
-			endPoint <- stringr::str_interp("traits/${uuid}")
+			endPoint <- stringr::str_interp("users/${uuid}/activate")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -4993,19 +3310,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		traits.create = function(trait, ensure_unique_name = "false")
+		users.setup = function(uuid = NULL, user = NULL,
+			repo_name = NULL, vm_uuid = NULL, send_notification_email = "false")
 		{
-			endPoint <- stringr::str_interp("traits")
+			endPoint <- stringr::str_interp("users/setup")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(uuid = uuid, user = user,
+							  repo_name = repo_name, vm_uuid = vm_uuid,
+							  send_notification_email = send_notification_email)
 			
-			if(length(trait) > 0)
-				body <- jsonlite::toJSON(list(trait = trait), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
 			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
@@ -5017,21 +3333,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		traits.update = function(trait, uuid)
+		users.unsetup = function(uuid)
 		{
-			endPoint <- stringr::str_interp("traits/${uuid}")
+			endPoint <- stringr::str_interp("users/${uuid}/unsetup")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(trait) > 0)
-				body <- jsonlite::toJSON(list(trait = trait), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
-			response <- private$REST$http$exec("PUT", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5041,17 +3353,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		traits.delete = function(uuid)
+		users.update_uuid = function(uuid, new_uuid)
 		{
-			endPoint <- stringr::str_interp("traits/${uuid}")
+			endPoint <- stringr::str_interp("users/${uuid}/update_uuid")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(new_uuid = new_uuid)
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5061,21 +3373,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		traits.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact")
+		users.merge = function(new_owner_uuid, new_user_token = NULL,
+			redirect_to_new_user = NULL, old_user_uuid = NULL,
+			new_user_uuid = NULL)
 		{
-			endPoint <- stringr::str_interp("traits")
+			endPoint <- stringr::str_interp("users/merge")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- list(new_owner_uuid = new_owner_uuid,
+							  new_user_token = new_user_token, redirect_to_new_user = redirect_to_new_user,
+							  old_user_uuid = old_user_uuid, new_user_uuid = new_user_uuid)
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5085,13 +3397,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.get = function(uuid)
+		users.list = function(filters = NULL, where = NULL,
+			order = NULL, select = NULL, distinct = NULL,
+			limit = "100", offset = "0", count = "exact",
+			cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
+			endPoint <- stringr::str_interp("users")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(filters = filters, where = where,
+							  order = order, select = select, distinct = distinct,
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -5105,22 +3423,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.create = function(virtualmachine,
-			ensure_unique_name = "false")
+		repositories.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("virtual_machines")
+			endPoint <- stringr::str_interp("repositories/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- NULL
 			
-			if(length(virtualmachine) > 0)
-				body <- jsonlite::toJSON(list(virtualmachine = virtualmachine), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
-			response <- private$REST$http$exec("POST", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5130,21 +3443,23 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.update = function(virtualmachine, uuid)
+		repositories.create = function(repository,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
+			endPoint <- stringr::str_interp("repositories")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(virtualmachine) > 0)
-				body <- jsonlite::toJSON(list(virtualmachine = virtualmachine), 
+			if(length(repository) > 0)
+				body <- jsonlite::toJSON(list(repository = repository), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
 			
-			response <- private$REST$http$exec("PUT", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5154,17 +3469,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.delete = function(uuid)
+		repositories.update = function(repository, uuid)
 		{
-			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
+			endPoint <- stringr::str_interp("repositories/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			body <- NULL
+			if(length(repository) > 0)
+				body <- jsonlite::toJSON(list(repository = repository), 
+				                         auto_unbox = TRUE)
+			else
+				body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("PUT", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5174,17 +3493,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.logins = function(uuid)
+		repositories.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("virtual_machines/${uuid}/logins")
+			endPoint <- stringr::str_interp("repositories/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("DELETE", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5194,11 +3513,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.get_all_logins = function()
+		repositories.get_all_permissions = function()
 		{
-			endPoint <- stringr::str_interp("virtual_machines/get_all_logins")
+			endPoint <- stringr::str_interp("repositories/get_all_permissions")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5214,18 +3533,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		virtual_machines.list = function(filters = NULL,
+		repositories.list = function(filters = NULL,
 			where = NULL, order = NULL, select = NULL,
 			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("virtual_machines")
+			endPoint <- stringr::str_interp("repositories")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -5239,11 +3559,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		workflows.get = function(uuid)
+		virtual_machines.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("workflows/${uuid}")
+			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5259,16 +3579,18 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		workflows.create = function(workflow, ensure_unique_name = "false")
+		virtual_machines.create = function(virtualmachine,
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("workflows")
+			endPoint <- stringr::str_interp("virtual_machines")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			if(length(workflow) > 0)
-				body <- jsonlite::toJSON(list(workflow = workflow), 
+			if(length(virtualmachine) > 0)
+				body <- jsonlite::toJSON(list(virtualmachine = virtualmachine), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -5283,16 +3605,16 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		workflows.update = function(workflow, uuid)
+		virtual_machines.update = function(virtualmachine, uuid)
 		{
-			endPoint <- stringr::str_interp("workflows/${uuid}")
+			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			if(length(workflow) > 0)
-				body <- jsonlite::toJSON(list(workflow = workflow), 
+			if(length(virtualmachine) > 0)
+				body <- jsonlite::toJSON(list(virtualmachine = virtualmachine), 
 				                         auto_unbox = TRUE)
 			else
 				body <- NULL
@@ -5307,11 +3629,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		workflows.delete = function(uuid)
+		virtual_machines.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("workflows/${uuid}")
+			endPoint <- stringr::str_interp("virtual_machines/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5327,18 +3649,13 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		workflows.list = function(filters = NULL,
-			where = NULL, order = NULL, select = NULL,
-			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+		virtual_machines.logins = function(uuid)
 		{
-			endPoint <- stringr::str_interp("workflows")
+			endPoint <- stringr::str_interp("virtual_machines/${uuid}/logins")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+			queryArgs <- NULL
 			
 			body <- NULL
 			
@@ -5352,11 +3669,11 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.get = function(uuid)
+		virtual_machines.get_all_logins = function()
 		{
-			endPoint <- stringr::str_interp("groups/${uuid}")
+			endPoint <- stringr::str_interp("virtual_machines/get_all_logins")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5372,45 +3689,23 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.create = function(group, ensure_unique_name = "false")
-		{
-			endPoint <- stringr::str_interp("groups")
-			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
-			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
-			
-			if(length(group) > 0)
-				body <- jsonlite::toJSON(list(group = group), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
-			
-			response <- private$REST$http$exec("POST", url, headers, body,
-			                                   queryArgs, private$numRetries)
-			resource <- private$REST$httpParser$parseJSONResponse(response)
-			
-			if(!is.null(resource$errors))
-				stop(resource$errors)
-			
-			resource
-		},
-
-		groups.update = function(group, uuid)
+		virtual_machines.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("groups/${uuid}")
+			endPoint <- stringr::str_interp("virtual_machines")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- NULL
+			queryArgs <- list(filters = filters, where = where,
+							  order = order, select = select, distinct = distinct,
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
-			if(length(group) > 0)
-				body <- jsonlite::toJSON(list(group = group), 
-				                         auto_unbox = TRUE)
-			else
-				body <- NULL
+			body <- NULL
 			
-			response <- private$REST$http$exec("PUT", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5420,17 +3715,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.delete = function(uuid)
+		workflows.get = function(uuid)
 		{
-			endPoint <- stringr::str_interp("groups/${uuid}")
+			endPoint <- stringr::str_interp("workflows/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("DELETE", url, headers, body,
+			response <- private$REST$http$exec("GET", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5440,23 +3735,23 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.contents = function(filters = NULL,
-			where = NULL, order = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact",
-			include_trash = NULL, uuid = NULL, recursive = NULL)
+		workflows.create = function(workflow, ensure_unique_name = "false",
+			cluster_id = NULL)
 		{
-			endPoint <- stringr::str_interp("groups/contents")
+			endPoint <- stringr::str_interp("workflows")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(filters = filters, where = where,
-							  order = order, distinct = distinct, limit = limit,
-							  offset = offset, count = count, include_trash = include_trash,
-							  uuid = uuid, recursive = recursive)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
-			body <- NULL
+			if(length(workflow) > 0)
+				body <- jsonlite::toJSON(list(workflow = workflow), 
+				                         auto_unbox = TRUE)
+			else
+				body <- NULL
 			
-			response <- private$REST$http$exec("GET", url, headers, body,
+			response <- private$REST$http$exec("POST", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5466,17 +3761,21 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.trash = function(uuid)
+		workflows.update = function(workflow, uuid)
 		{
-			endPoint <- stringr::str_interp("groups/${uuid}/trash")
+			endPoint <- stringr::str_interp("workflows/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
-			body <- NULL
+			if(length(workflow) > 0)
+				body <- jsonlite::toJSON(list(workflow = workflow), 
+				                         auto_unbox = TRUE)
+			else
+				body <- NULL
 			
-			response <- private$REST$http$exec("POST", url, headers, body,
+			response <- private$REST$http$exec("PUT", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5486,17 +3785,17 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.untrash = function(uuid)
+		workflows.delete = function(uuid)
 		{
-			endPoint <- stringr::str_interp("groups/${uuid}/untrash")
+			endPoint <- stringr::str_interp("workflows/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
 			body <- NULL
 			
-			response <- private$REST$http$exec("POST", url, headers, body,
+			response <- private$REST$http$exec("DELETE", url, headers, body,
 			                                   queryArgs, private$numRetries)
 			resource <- private$REST$httpParser$parseJSONResponse(response)
 			
@@ -5506,19 +3805,19 @@ Arvados <- R6::R6Class(
 			resource
 		},
 
-		groups.list = function(filters = NULL, where = NULL,
-			order = NULL, select = NULL, distinct = NULL,
-			limit = "100", offset = "0", count = "exact",
-			include_trash = NULL)
+		workflows.list = function(filters = NULL,
+			where = NULL, order = NULL, select = NULL,
+			distinct = NULL, limit = "100", offset = "0",
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
-			endPoint <- stringr::str_interp("groups")
+			endPoint <- stringr::str_interp("workflows")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
 							  limit = limit, offset = offset, count = count,
-							  include_trash = include_trash)
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -5536,7 +3835,7 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5553,13 +3852,14 @@ Arvados <- R6::R6Class(
 		},
 
 		user_agreements.create = function(useragreement,
-			ensure_unique_name = "false")
+			ensure_unique_name = "false", cluster_id = NULL)
 		{
 			endPoint <- stringr::str_interp("user_agreements")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
-			queryArgs <- list(ensure_unique_name = ensure_unique_name)
+			queryArgs <- list(ensure_unique_name = ensure_unique_name,
+							  cluster_id = cluster_id)
 			
 			if(length(useragreement) > 0)
 				body <- jsonlite::toJSON(list(useragreement = useragreement), 
@@ -5581,7 +3881,7 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5605,7 +3905,7 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/${uuid}")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5625,7 +3925,7 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/signatures")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5645,7 +3945,7 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/sign")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
@@ -5664,15 +3964,16 @@ Arvados <- R6::R6Class(
 		user_agreements.list = function(filters = NULL,
 			where = NULL, order = NULL, select = NULL,
 			distinct = NULL, limit = "100", offset = "0",
-			count = "exact")
+			count = "exact", cluster_id = NULL, bypass_federation = NULL)
 		{
 			endPoint <- stringr::str_interp("user_agreements")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- list(filters = filters, where = where,
 							  order = order, select = select, distinct = distinct,
-							  limit = limit, offset = offset, count = count)
+							  limit = limit, offset = offset, count = count,
+							  cluster_id = cluster_id, bypass_federation = bypass_federation)
 			
 			body <- NULL
 			
@@ -5690,7 +3991,27 @@ Arvados <- R6::R6Class(
 		{
 			endPoint <- stringr::str_interp("user_agreements/new")
 			url <- paste0(private$host, endPoint)
-			headers <- list(Authorization = paste("OAuth2", private$token), 
+			headers <- list(Authorization = paste("Bearer", private$token), 
+			                "Content-Type" = "application/json")
+			queryArgs <- NULL
+			
+			body <- NULL
+			
+			response <- private$REST$http$exec("GET", url, headers, body,
+			                                   queryArgs, private$numRetries)
+			resource <- private$REST$httpParser$parseJSONResponse(response)
+			
+			if(!is.null(resource$errors))
+				stop(resource$errors)
+			
+			resource
+		},
+
+		configs.get = function()
+		{
+			endPoint <- stringr::str_interp("config")
+			url <- paste0(private$host, endPoint)
+			headers <- list(Authorization = paste("Bearer", private$token), 
 			                "Content-Type" = "application/json")
 			queryArgs <- NULL
 			
diff --git a/sdk/R/R/autoGenAPI.R b/sdk/R/R/autoGenAPI.R
index aea64323b..c86684f8b 100644
--- a/sdk/R/R/autoGenAPI.R
+++ b/sdk/R/R/autoGenAPI.R
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: Apache-2.0
 
 getAPIDocument <- function(){
-    url <- "https://ce8i5.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
+    url <- "https://jutro.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
     serverResponse <- httr::RETRY("GET", url = url)
 
     httr::content(serverResponse, as = "parsed", type = "application/json")
@@ -17,6 +17,10 @@ generateAPI <- function()
     discoveryDocument <- getAPIDocument()
 
     methodResources <- discoveryDocument$resources
+
+    # Don't emit deprecated APIs
+    methodResources <- methodResources[!(names(methodResources) %in% c("jobs", "job_tasks", "pipeline_templates", "pipeline_instances",
+	    		    "keep_disks", "nodes", "humans", "traits", "specimens"))]
     resourceNames   <- names(methodResources)
 
     methodDoc <- genMethodsDoc(methodResources, resourceNames)
@@ -34,6 +38,10 @@ generateAPI <- function()
                       arvadosAPIFooter)
 
     fileConn <- file("./R/Arvados.R", "w")
+    writeLines(c(
+    "# Copyright (C) The Arvados Authors. All rights reserved.",
+    "#",
+    "# SPDX-License-Identifier: Apache-2.0", ""), fileConn)
     writeLines(unlist(arvadosClass), fileConn)
     close(fileConn)
     NULL
@@ -252,7 +260,7 @@ getRequestURL <- function(methodMetaData)
 
 getRequestHeaders <- function()
 {
-    c("headers <- list(Authorization = paste(\"OAuth2\", private$token), ",
+    c("headers <- list(Authorization = paste(\"Bearer\", private$token), ",
       "                \"Content-Type\" = \"application/json\")")
 }
 

commit cef00a8331c41690e17f3ca0c7a1a51c06ca1cb7
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Wed Sep 23 16:17:09 2020 -0400

    16827: Fix getFileNamesFromResponse
    
    Update tests.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/R/R/HttpParser.R b/sdk/R/R/HttpParser.R
index cd492166a..60bf78282 100644
--- a/sdk/R/R/HttpParser.R
+++ b/sdk/R/R/HttpParser.R
@@ -31,14 +31,13 @@ HttpParser <- R6::R6Class(
         {
             text <- rawToChar(response$content)
             doc <- XML::xmlParse(text, asText=TRUE)
-            base <- paste(paste("/", strsplit(uri, "/")[[1]][-1:-3], sep="", collapse=""), "/", sep="")
+            base <- paste("/", strsplit(uri, "/")[[1]][4], "/", sep="")
             result <- unlist(
                 XML::xpathApply(doc, "//D:response/D:href", function(node) {
                     sub(base, "", URLdecode(XML::xmlValue(node)), fixed=TRUE)
                 })
             )
-            result <- result[result != ""]
-            result[-1]
+            result[result != ""]
         },
 
         getFileSizesFromResponse = function(response, uri)
diff --git a/sdk/R/R/RESTService.R b/sdk/R/R/RESTService.R
index 78b2c35e3..9c65e7286 100644
--- a/sdk/R/R/RESTService.R
+++ b/sdk/R/R/RESTService.R
@@ -36,16 +36,13 @@ RESTService <- R6::R6Class(
         {
             if(is.null(private$webDavHostName))
             {
-                discoveryDocumentURL <- paste0("https://", private$rawHostName,
-                                               "/discovery/v1/apis/arvados/v1/rest")
+                publicConfigURL <- paste0("https://", private$rawHostName,
+                                               "/arvados/v1/config")
 
-                headers <- list(Authorization = paste("OAuth2", self$token))
-
-                serverResponse <- self$http$exec("GET", discoveryDocumentURL, headers,
-                                                 retryTimes = self$numRetries)
+                serverResponse <- self$http$exec("GET", publicConfigURL, retryTimes = self$numRetries)
 
-                discoveryDocument <- self$httpParser$parseJSONResponse(serverResponse)
-                private$webDavHostName <- discoveryDocument$keepWebServiceUrl
+                configDocument <- self$httpParser$parseJSONResponse(serverResponse)
+                private$webDavHostName <- configDocument$Services$WebDAVDownload$ExternalURL
 
                 if(is.null(private$webDavHostName))
                     stop("Unable to find WebDAV server.")
@@ -118,7 +115,7 @@ RESTService <- R6::R6Class(
             collectionURL <- URLencode(paste0(self$getWebDavHostName(),
                                               "c=", uuid))
 
-            headers <- list("Authorization" = paste("OAuth2", self$token))
+            headers <- list("Authorization" = paste("Bearer", self$token))
 
             response <- self$http$exec("PROPFIND", collectionURL, headers,
                                        retryTimes = self$numRetries)
diff --git a/sdk/R/R/autoGenAPI.R b/sdk/R/R/autoGenAPI.R
index 1aef20b6c..aea64323b 100644
--- a/sdk/R/R/autoGenAPI.R
+++ b/sdk/R/R/autoGenAPI.R
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: Apache-2.0
 
 getAPIDocument <- function(){
-    url <- "https://4xphq.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
+    url <- "https://ce8i5.arvadosapi.com/discovery/v1/apis/arvados/v1/rest"
     serverResponse <- httr::RETRY("GET", url = url)
 
     httr::content(serverResponse, as = "parsed", type = "application/json")
diff --git a/sdk/R/tests/testthat/test-ArvadosFile.R b/sdk/R/tests/testthat/test-ArvadosFile.R
index e3457c993..da7d52c67 100644
--- a/sdk/R/tests/testthat/test-ArvadosFile.R
+++ b/sdk/R/tests/testthat/test-ArvadosFile.R
@@ -23,7 +23,7 @@ test_that("get always returns NULL", {
     dog <- ArvadosFile$new("dog")
 
     responseIsNull <- is.null(dog$get("something"))
-    expect_that(responseIsNull, is_true())
+    expect_true(responseIsNull)
 })
 
 test_that("getFirst always returns NULL", {
@@ -31,7 +31,7 @@ test_that("getFirst always returns NULL", {
     dog <- ArvadosFile$new("dog")
 
     responseIsNull <- is.null(dog$getFirst())
-    expect_that(responseIsNull, is_true())
+    expect_true(responseIsNull)
 })
 
 test_that(paste("getSizeInBytes returns zero if arvadosFile",
@@ -266,8 +266,8 @@ test_that("move moves arvados file inside collection tree", {
     dogIsNullOnOldLocation <- is.null(collection$get("animal/dog"))
     dogExistsOnNewLocation <- !is.null(collection$get("dog"))
 
-    expect_that(dogIsNullOnOldLocation, is_true())
-    expect_that(dogExistsOnNewLocation, is_true())
+    expect_true(dogIsNullOnOldLocation)
+    expect_true(dogExistsOnNewLocation)
 })
 
 test_that(paste("copy raises exception if arvados file",
@@ -339,8 +339,8 @@ test_that("copy copies arvados file inside collection tree", {
     dogExistsOnOldLocation <- !is.null(collection$get("animal/dog"))
     dogExistsOnNewLocation <- !is.null(collection$get("dog"))
 
-    expect_that(dogExistsOnOldLocation, is_true())
-    expect_that(dogExistsOnNewLocation, is_true())
+    expect_true(dogExistsOnOldLocation)
+    expect_true(dogExistsOnNewLocation)
 })
 
 test_that("duplicate performs deep cloning of Arvados file", {
diff --git a/sdk/R/tests/testthat/test-Collection.R b/sdk/R/tests/testthat/test-Collection.R
index 636359ae2..20a2ecf05 100644
--- a/sdk/R/tests/testthat/test-Collection.R
+++ b/sdk/R/tests/testthat/test-Collection.R
@@ -86,7 +86,7 @@ test_that(paste("add adds ArvadosFile or Subcollection",
     dog <- collection$get("animal/dog")
     dogExistsInCollection <- !is.null(dog) && dog$getName() == "dog"
 
-    expect_that(dogExistsInCollection, is_true())
+    expect_true(dogExistsInCollection)
     expect_that(fakeREST$createCallCount, equals(1))
 })
 
@@ -119,8 +119,8 @@ test_that(paste("create adds files specified by fileNames",
     dogExistsInCollection <- !is.null(dog) && dog$getName() == "dog"
     catExistsInCollection <- !is.null(cat) && cat$getName() == "cat"
 
-    expect_that(dogExistsInCollection, is_true())
-    expect_that(catExistsInCollection, is_true())
+    expect_true(dogExistsInCollection)
+    expect_true(catExistsInCollection)
     expect_that(fakeREST$createCallCount, equals(2))
 })
 
@@ -168,8 +168,8 @@ test_that(paste("remove removes files specified by paths",
     dogExistsInCollection <- !is.null(dog) && dog$getName() == "dog"
     catExistsInCollection <- !is.null(cat) && cat$getName() == "cat"
 
-    expect_that(dogExistsInCollection, is_false())
-    expect_that(catExistsInCollection, is_false())
+    expect_false(dogExistsInCollection)
+    expect_false(catExistsInCollection)
     expect_that(fakeREST$deleteCallCount, equals(2))
 })
 
@@ -188,8 +188,8 @@ test_that(paste("move moves content to a new location inside file tree",
     dogIsNullOnOldLocation <- is.null(collection$get("animal/dog"))
     dogExistsOnNewLocation <- !is.null(collection$get("dog"))
 
-    expect_that(dogIsNullOnOldLocation, is_true())
-    expect_that(dogExistsOnNewLocation, is_true())
+    expect_true(dogIsNullOnOldLocation)
+    expect_true(dogExistsOnNewLocation)
     expect_that(fakeREST$moveCallCount, equals(1))
 })
 
@@ -219,7 +219,7 @@ test_that("getFileListing returns sorted collection content received from REST s
     contentMatchExpected <- all(collection$getFileListing() ==
                                 c("animal", "animal/fish", "ball"))
 
-    expect_that(contentMatchExpected, is_true())
+    expect_true(contentMatchExpected)
     #2 calls because Collection$new calls getFileListing once
     expect_that(fakeREST$getCollectionContentCallCount, equals(2))
 
@@ -237,7 +237,7 @@ test_that("get returns arvados file or subcollection from internal tree structur
     fish <- collection$get("animal/fish")
     fishIsNotNull <- !is.null(fish)
 
-    expect_that(fishIsNotNull, is_true())
+    expect_true(fishIsNotNull)
     expect_that(fish$getName(), equals("fish"))
 })
 
@@ -256,8 +256,8 @@ test_that(paste("copy copies content to a new location inside file tree",
     dogExistsOnOldLocation <- !is.null(collection$get("animal/dog"))
     dogExistsOnNewLocation <- !is.null(collection$get("dog"))
 
-    expect_that(dogExistsOnOldLocation, is_true())
-    expect_that(dogExistsOnNewLocation, is_true())
+    expect_true(dogExistsOnOldLocation)
+    expect_true(dogExistsOnNewLocation)
     expect_that(fakeREST$copyCallCount, equals(1))
 })
 
diff --git a/sdk/R/tests/testthat/test-CollectionTree.R b/sdk/R/tests/testthat/test-CollectionTree.R
index 1a3aefecd..c4bf9a1da 100644
--- a/sdk/R/tests/testthat/test-CollectionTree.R
+++ b/sdk/R/tests/testthat/test-CollectionTree.R
@@ -34,16 +34,16 @@ test_that("constructor creates file tree from character array properly", {
                                          boat$getCollection()   == "myCollection"
 
     expect_that(root$getName(), equals(""))
-    expect_that(rootIsOfTypeSubcollection, is_true())
-    expect_that(rootHasNoParent, is_true())
-    expect_that(animalIsOfTypeSubcollection, is_true())
-    expect_that(animalsParentIsRoot, is_true())
-    expect_that(animalContainsDog, is_true())
-    expect_that(dogIsOfTypeArvadosFile, is_true())
-    expect_that(dogsParentIsAnimal, is_true())
-    expect_that(boatIsOfTypeArvadosFile, is_true())
-    expect_that(boatsParentIsRoot, is_true())
-    expect_that(allElementsBelongToSameCollection, is_true())
+    expect_true(rootIsOfTypeSubcollection)
+    expect_true(rootHasNoParent)
+    expect_true(animalIsOfTypeSubcollection)
+    expect_true(animalsParentIsRoot)
+    expect_true(animalContainsDog)
+    expect_true(dogIsOfTypeArvadosFile)
+    expect_true(dogsParentIsAnimal)
+    expect_true(boatIsOfTypeArvadosFile)
+    expect_true(boatsParentIsRoot)
+    expect_true(allElementsBelongToSameCollection)
 })
 
 test_that("getElement returns element from tree if element exists on specified path", {
@@ -72,7 +72,7 @@ test_that("getElement returns NULL from tree if element doesn't exists on specif
     fish <- collectionTree$getElement("animal/fish")
     fishIsNULL <- is.null(fish)
 
-    expect_that(fishIsNULL, is_true())
+    expect_true(fishIsNULL)
 })
 
 test_that("getElement trims ./ from start of relativePath", {
diff --git a/sdk/R/tests/testthat/test-HttpParser.R b/sdk/R/tests/testthat/test-HttpParser.R
index 82c0fb0dd..fb9f379b3 100644
--- a/sdk/R/tests/testthat/test-HttpParser.R
+++ b/sdk/R/tests/testthat/test-HttpParser.R
@@ -18,7 +18,7 @@ test_that("parseJSONResponse generates and returns JSON object from server respo
     result <- parser$parseJSONResponse(serverResponse)
     barExists <- !is.null(result$bar)
 
-    expect_that(barExists, is_true())
+    expect_true(barExists)
     expect_that(unlist(result$bar$foo), equals(10))
 })
 
@@ -40,7 +40,7 @@ test_that(paste("parseResponse generates and returns character vector",
 
 webDAVResponseSample =
     paste0("<?xml version=\"1.0\" encoding=\"UTF-8\"?><D:multistatus xmlns:",
-           "D=\"DAV:\"><D:response><D:href>/c=aaaaa-bbbbb-ccccccccccccccc</D",
+           "D=\"DAV:\"><D:response><D:href>/c=aaaaa-bbbbb-ccccccccccccccc/</D",
            ":href><D:propstat><D:prop><D:resourcetype><D:collection xmlns:D=",
            "\"DAV:\"/></D:resourcetype><D:getlastmodified>Fri, 11 Jan 2018 1",
            "1:11:11 GMT</D:getlastmodified><D:displayname></D:displayname><D",
@@ -75,7 +75,7 @@ test_that(paste("getFileNamesFromResponse returns file names belonging to specif
     expectedResult <- "myFile.exe"
     resultMatchExpected <- all.equal(result, expectedResult)
 
-    expect_that(resultMatchExpected, is_true())
+    expect_true(resultMatchExpected)
 })
 
 test_that(paste("getFileSizesFromResponse returns file sizes",
@@ -92,5 +92,5 @@ test_that(paste("getFileSizesFromResponse returns file sizes",
     result <- parser$getFileSizesFromResponse(serverResponse, url)
     resultMatchExpected <- result == expectedResult
 
-    expect_that(resultMatchExpected, is_true())
+    expect_true(resultMatchExpected)
 })
diff --git a/sdk/R/tests/testthat/test-HttpRequest.R b/sdk/R/tests/testthat/test-HttpRequest.R
index f12463c80..eb58d033b 100644
--- a/sdk/R/tests/testthat/test-HttpRequest.R
+++ b/sdk/R/tests/testthat/test-HttpRequest.R
@@ -59,8 +59,8 @@ test_that("exec calls httr functions correctly", {
     http <- HttpRequest$new()
     http$exec("GET", "url")
 
-    expect_that(add_headersCalled, is_true())
-    expect_that(retryCalled, is_true())
+    expect_true(add_headersCalled)
+    expect_true(retryCalled)
     expect_that(expectedConfig$options, equals(list(ssl_verifypeer = 0L)))
 })
 
@@ -101,8 +101,8 @@ test_that("getConnection calls curl functions correctly", {
     http <- HttpRequest$new()
     http$getConnection("location", list(), "r")
 
-    expect_that(new_handleCalled, is_true())
-    expect_that(handle_setheadersCalled, is_true())
-    expect_that(handle_setoptCalled, is_true())
-    expect_that(curlCalled, is_true())
+    expect_true(new_handleCalled)
+    expect_true(handle_setheadersCalled)
+    expect_true(handle_setoptCalled)
+    expect_true(curlCalled)
 })
diff --git a/sdk/R/tests/testthat/test-RESTService.R b/sdk/R/tests/testthat/test-RESTService.R
index 64988e33d..8885ed3de 100644
--- a/sdk/R/tests/testthat/test-RESTService.R
+++ b/sdk/R/tests/testthat/test-RESTService.R
@@ -10,8 +10,8 @@ context("REST service")
 
 test_that("getWebDavHostName calls REST service properly", {
 
-    expectedURL <- "https://host/discovery/v1/apis/arvados/v1/rest"
-    serverResponse <- list(keepWebServiceUrl = "https://myWebDavServer.com")
+    expectedURL <- "https://host/arvados/v1/config"
+    serverResponse <- list(Services = list(WebDAVDownload = list(ExternalURL = "https://myWebDavServer.com")))
     httpRequest <- FakeHttpRequest$new(expectedURL, serverResponse)
 
     REST <- RESTService$new("token", "host",
@@ -19,14 +19,14 @@ test_that("getWebDavHostName calls REST service properly", {
 
     REST$getWebDavHostName()
 
-    expect_that(httpRequest$URLIsProperlyConfigured, is_true())
-    expect_that(httpRequest$requestHeaderContainsAuthorizationField, is_true())
+    expect_true(httpRequest$URLIsProperlyConfigured)
+    expect_false(httpRequest$requestHeaderContainsAuthorizationField)
     expect_that(httpRequest$numberOfGETRequests, equals(1))
 })
 
 test_that("getWebDavHostName returns webDAV host name properly", {
 
-    serverResponse <- list(keepWebServiceUrl = "https://myWebDavServer.com")
+    serverResponse <- list(Services = list(WebDAVDownload = list(ExternalURL = "https://myWebDavServer.com")))
     httpRequest <- FakeHttpRequest$new(expectedURL = NULL, serverResponse)
 
     REST <- RESTService$new("token", "host",
@@ -48,8 +48,8 @@ test_that("create calls REST service properly", {
 
     REST$create("file", uuid)
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
     expect_that(fakeHttp$numberOfPUTRequests, equals(1))
 })
 
@@ -81,8 +81,8 @@ test_that("delete calls REST service properly", {
 
     REST$delete("file", uuid)
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
     expect_that(fakeHttp$numberOfDELETERequests, equals(1))
 })
 
@@ -114,9 +114,9 @@ test_that("move calls REST service properly", {
 
     REST$move("file", "newDestination/file", uuid)
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
-    expect_that(fakeHttp$requestHeaderContainsDestinationField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
+    expect_true(fakeHttp$requestHeaderContainsDestinationField)
     expect_that(fakeHttp$numberOfMOVERequests, equals(1))
 })
 
@@ -148,9 +148,9 @@ test_that("copy calls REST service properly", {
 
     REST$copy("file", "newDestination/file", uuid)
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
-    expect_that(fakeHttp$requestHeaderContainsDestinationField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
+    expect_true(fakeHttp$requestHeaderContainsDestinationField)
     expect_that(fakeHttp$numberOfCOPYRequests, equals(1))
 })
 
@@ -187,8 +187,8 @@ test_that("getCollectionContent retreives correct content from WebDAV server", {
     returnedContentMatchExpected <- all.equal(returnResult,
                                               c("animal", "animal/dog", "ball"))
 
-    expect_that(returnedContentMatchExpected, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
+    expect_true(returnedContentMatchExpected)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
 })
 
 test_that("getCollectionContent raises exception if server returns empty response", {
@@ -266,9 +266,9 @@ test_that("getResourceSize calls REST service properly", {
     returnedContentMatchExpected <- all.equal(returnResult,
                                               c(6, 2, 931, 12003))
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
-    expect_that(returnedContentMatchExpected, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
+    expect_true(returnedContentMatchExpected)
 })
 
 test_that("getResourceSize raises exception if server returns empty response", {
@@ -330,9 +330,9 @@ test_that("read calls REST service properly", {
 
     returnResult <- REST$read("file", uuid, "text", 1024, 512)
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
-    expect_that(fakeHttp$requestHeaderContainsRangeField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
+    expect_true(fakeHttp$requestHeaderContainsRangeField)
     expect_that(returnResult, equals("file content"))
 })
 
@@ -390,10 +390,10 @@ test_that("write calls REST service properly", {
 
     REST$write("file", uuid, fileContent, "text/html")
 
-    expect_that(fakeHttp$URLIsProperlyConfigured, is_true())
-    expect_that(fakeHttp$requestBodyIsProvided, is_true())
-    expect_that(fakeHttp$requestHeaderContainsAuthorizationField, is_true())
-    expect_that(fakeHttp$requestHeaderContainsContentTypeField, is_true())
+    expect_true(fakeHttp$URLIsProperlyConfigured)
+    expect_true(fakeHttp$requestBodyIsProvided)
+    expect_true(fakeHttp$requestHeaderContainsAuthorizationField)
+    expect_true(fakeHttp$requestHeaderContainsContentTypeField)
 })
 
 test_that("write raises exception if server response code is not between 200 and 300", {
diff --git a/sdk/R/tests/testthat/test-Subcollection.R b/sdk/R/tests/testthat/test-Subcollection.R
index a6e420962..a95247f77 100644
--- a/sdk/R/tests/testthat/test-Subcollection.R
+++ b/sdk/R/tests/testthat/test-Subcollection.R
@@ -37,7 +37,7 @@ test_that(paste("getFileListing by default returns sorted path of all files",
     resultsMatch <- length(expectedResult) == length(result) &&
                     all(expectedResult == result)
 
-    expect_that(resultsMatch, is_true())
+    expect_true(resultsMatch)
 })
 
 test_that(paste("getFileListing returns sorted names of all direct children",
@@ -58,7 +58,7 @@ test_that(paste("getFileListing returns sorted names of all direct children",
     resultsMatch <- length(expectedResult) == length(result) &&
                     all(expectedResult == result)
 
-    expect_that(resultsMatch, is_true())
+    expect_true(resultsMatch)
 })
 
 test_that("add adds content to inside collection tree", {
@@ -73,8 +73,8 @@ test_that("add adds content to inside collection tree", {
     animalContainsFish <- animal$get("fish")$getName() == fish$getName()
     animalContainsDog  <- animal$get("dog")$getName()  == dog$getName()
 
-    expect_that(animalContainsFish, is_true())
-    expect_that(animalContainsDog, is_true())
+    expect_true(animalContainsFish)
+    expect_true(animalContainsDog)
 })
 
 test_that("add raises exception if content name is empty string", {
@@ -143,7 +143,7 @@ test_that("remove removes content from subcollection", {
 
     returnValueAfterRemovalIsNull <- is.null(animal$get("fish"))
 
-    expect_that(returnValueAfterRemovalIsNull, is_true())
+    expect_true(returnValueAfterRemovalIsNull)
 })
 
 test_that(paste("remove raises exception",
@@ -198,10 +198,10 @@ test_that(paste("get returns ArvadosFile or Subcollection",
     returnedFishIsSubcollection <- "Subcollection" %in% class(returnedFish)
     returnedDogIsArvadosFile    <- "ArvadosFile"   %in% class(returnedDog)
 
-    expect_that(returnedFishIsSubcollection, is_true())
+    expect_true(returnedFishIsSubcollection)
     expect_that(returnedFish$getName(), equals("fish"))
 
-    expect_that(returnedDogIsArvadosFile, is_true())
+    expect_true(returnedDogIsArvadosFile)
     expect_that(returnedDog$getName(), equals("dog"))
 })
 
@@ -215,7 +215,7 @@ test_that(paste("get returns NULL if file or folder",
 
     returnedDogIsNull <- is.null(animal$get("dog"))
 
-    expect_that(returnedDogIsNull, is_true())
+    expect_true(returnedDogIsNull)
 })
 
 test_that("getFirst returns first child in the subcollection", {
@@ -234,7 +234,7 @@ test_that("getFirst returns NULL if subcollection contains no children", {
 
     returnedElementIsNull <- is.null(animal$getFirst())
 
-    expect_that(returnedElementIsNull, is_true())
+    expect_true(returnedElementIsNull)
 })
 
 test_that(paste("setCollection by default sets collection",
@@ -261,7 +261,7 @@ test_that(paste("setCollection sets collection filed of subcollection only",
     fishCollectionIsNull <- is.null(fish$getCollection())
 
     expect_that(animal$getCollection(), equals("myCollection"))
-    expect_that(fishCollectionIsNull, is_true())
+    expect_true(fishCollectionIsNull)
 })
 
 test_that(paste("move raises exception if subcollection",
@@ -330,8 +330,8 @@ test_that("move moves subcollection inside collection tree", {
     fishIsNullOnOldLocation <- is.null(collection$get("animal/fish"))
     fishExistsOnNewLocation <- !is.null(collection$get("fish"))
 
-    expect_that(fishIsNullOnOldLocation, is_true())
-    expect_that(fishExistsOnNewLocation, is_true())
+    expect_true(fishIsNullOnOldLocation)
+    expect_true(fishExistsOnNewLocation)
 })
 
 test_that(paste("getSizeInBytes returns zero if subcollection",
@@ -425,8 +425,8 @@ test_that("copy copies subcollection inside collection tree", {
     fishExistsOnOldLocation <- !is.null(collection$get("animal/fish"))
     fishExistsOnNewLocation <- !is.null(collection$get("fish"))
 
-    expect_that(fishExistsOnOldLocation, is_true())
-    expect_that(fishExistsOnNewLocation, is_true())
+    expect_true(fishExistsOnOldLocation)
+    expect_true(fishExistsOnNewLocation)
 })
 
 test_that("duplicate performs deep cloning of Subcollection", {

commit 5ba3cdd24b371422d7a2de97d452b8b6537ac0ec
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Thu Sep 24 16:01:20 2020 -0400

    16884: Add public_project permission link to test fixtures
    
    This is the permission link that gives the all users and anonymous
    users read access to public favorites.  It is added by database seeds,
    but it also needs to be present in the fixtures.
    
    refs #16884
    refs #16811
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/api/test/fixtures/links.yml b/services/api/test/fixtures/links.yml
index ee5dcd342..b7f1aaa1f 100644
--- a/services/api/test/fixtures/links.yml
+++ b/services/api/test/fixtures/links.yml
@@ -1125,3 +1125,17 @@ active_manages_viewing_group:
   name: can_manage
   head_uuid: zzzzz-j7d0g-futrprojviewgrp
   properties: {}
+
+public_favorites_permission_link:
+  uuid: zzzzz-o0j2j-testpublicfavor
+  owner_uuid: zzzzz-tpzed-000000000000000
+  created_at: 2014-01-24 20:42:26 -0800
+  modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+  modified_by_user_uuid: zzzzz-tpzed-000000000000000
+  modified_at: 2014-01-24 20:42:26 -0800
+  updated_at: 2014-01-24 20:42:26 -0800
+  tail_uuid: zzzzz-j7d0g-anonymouspublic
+  link_class: permission
+  name: can_read
+  head_uuid: zzzzz-j7d0g-publicfavorites
+  properties: {}

commit 4a2b3c38abb28679835201ff98853b0d8879ab5e
Author: Ward Vandewege <ward at curii.com>
Date:   Wed Sep 23 20:56:12 2020 -0400

    16264: add R dependencies as Debian packages to lib/install/deps.go
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/lib/install/deps.go b/lib/install/deps.go
index 93a0ce452..437802315 100644
--- a/lib/install/deps.go
+++ b/lib/install/deps.go
@@ -144,6 +144,11 @@ func (installCommand) RunCommand(prog string, args []string, stdin io.Reader, st
 			"python3-dev",
 			"r-base",
 			"r-cran-testthat",
+			"r-cran-devtools",
+			"r-cran-knitr",
+			"r-cran-markdown",
+			"r-cran-roxygen2",
+			"r-cran-xml",
 			"sudo",
 			"python3-virtualenv",
 			"python3-venv",

commit 9bca41a9ba41fe4c03f24b32b2c484941793f529
Author: Tom Clegg <tom at tomclegg.ca>
Date:   Fri Sep 18 13:45:09 2020 -0400

    16850: Add KeyCount field to S3 ListObjects response.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at tomclegg.ca>

diff --git a/services/keep-web/s3.go b/services/keep-web/s3.go
index 52cfede46..7cd1b1a89 100644
--- a/services/keep-web/s3.go
+++ b/services/keep-web/s3.go
@@ -363,6 +363,8 @@ func (h *handler) s3list(w http.ResponseWriter, r *http.Request, fs arvados.Cust
 		// github.com/aws/aws-sdk-net never terminates its
 		// paging loop).
 		NextMarker string `xml:"NextMarker,omitempty"`
+		// ListObjectsV2 has a KeyCount response field.
+		KeyCount int
 	}
 	resp := listResp{
 		ListResp: s3.ListResp{
@@ -459,6 +461,7 @@ func (h *handler) s3list(w http.ResponseWriter, r *http.Request, fs arvados.Cust
 		}
 		sort.Slice(resp.CommonPrefixes, func(i, j int) bool { return resp.CommonPrefixes[i].Prefix < resp.CommonPrefixes[j].Prefix })
 	}
+	resp.KeyCount = len(resp.Contents)
 	w.Header().Set("Content-Type", "application/xml")
 	io.WriteString(w, xml.Header)
 	if err := xml.NewEncoder(w).Encode(resp); err != nil {
diff --git a/services/keep-web/s3_test.go b/services/keep-web/s3_test.go
index 66f046b13..33e978c3b 100644
--- a/services/keep-web/s3_test.go
+++ b/services/keep-web/s3_test.go
@@ -432,6 +432,22 @@ func (s *IntegrationSuite) TestS3ListNoNextMarker(c *check.C) {
 	}
 }
 
+// List response should include KeyCount field.
+func (s *IntegrationSuite) TestS3ListKeyCount(c *check.C) {
+	stage := s.s3setup(c)
+	defer stage.teardown(c)
+
+	req, err := http.NewRequest("GET", stage.collbucket.URL("/"), nil)
+	c.Assert(err, check.IsNil)
+	req.Header.Set("Authorization", "AWS "+arvadostest.ActiveTokenV2+":none")
+	req.URL.RawQuery = "prefix=&delimiter=/"
+	resp, err := http.DefaultClient.Do(req)
+	c.Assert(err, check.IsNil)
+	buf, err := ioutil.ReadAll(resp.Body)
+	c.Assert(err, check.IsNil)
+	c.Check(string(buf), check.Matches, `(?ms).*<KeyCount>2</KeyCount>.*`)
+}
+
 func (s *IntegrationSuite) TestS3CollectionList(c *check.C) {
 	stage := s.s3setup(c)
 	defer stage.teardown(c)

commit 76773b0a65a05c2a6356e53f939b17a5e5fa1f21
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Tue Sep 22 17:15:19 2020 -0400

    Tweak database seeds so the reset-to-fixture API works
    
    refs #16811
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/api/app/models/database_seeds.rb b/services/api/app/models/database_seeds.rb
index abfb672af..67bd3d10d 100644
--- a/services/api/app/models/database_seeds.rb
+++ b/services/api/app/models/database_seeds.rb
@@ -7,17 +7,18 @@ require 'update_permissions'
 class DatabaseSeeds
   extend CurrentApiClient
   def self.install
-    system_user
-    system_group
-    all_users_group
-    anonymous_group
-    anonymous_group_read_permission
-    anonymous_user
-    system_root_token_api_client
-    public_project_group
-    public_project_read_permission
-    empty_collection
-    refresh_permissions
+    batch_update_permissions do
+      system_user
+      system_group
+      all_users_group
+      anonymous_group
+      anonymous_group_read_permission
+      anonymous_user
+      system_root_token_api_client
+      public_project_group
+      public_project_read_permission
+      empty_collection
+    end
     refresh_trashed
   end
 end

commit 59a265f9b4ed03552711457484ae8a28ae972b26
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Tue Sep 22 16:31:42 2020 -0400

    16811: Make note about public favorites migration
    
    Also add recommendation to back up database before upgrading.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/doc/admin/upgrading.html.textile.liquid b/doc/admin/upgrading.html.textile.liquid
index c6b415e4f..1eb2468c3 100644
--- a/doc/admin/upgrading.html.textile.liquid
+++ b/doc/admin/upgrading.html.textile.liquid
@@ -16,6 +16,7 @@ h2. General process
 
 # Consult upgrade notes below to see if any manual configuration updates are necessary.
 # Wait for the cluster to be idle and stop Arvados services.
+# Make a backup of your database, as a precaution.
 # Install new packages using @apt-get upgrade@ or @yum upgrade at .
 # Wait for package installation scripts as they perform any necessary data migrations.
 # Restart Arvados services.
@@ -91,6 +92,10 @@ for uuid in $(arv link list --filters '[["link_class", "=", "permission"], ["tai
 done
 </pre>
 
+h4. "Public favorites" moved to their own project
+
+As a side effect of new permission system constraints, "star" links (indicating shortcuts in Workbench) that were previously owned by "All users" (which is now a "role" and cannot own things) will be migrated to a new system project called "Public favorites" which is readable by the "Anonymous users" role.
+
 h2(#v2_0_0). v2.0.0 (2020-02-07)
 
 "Upgrading from 1.4":#v1_4_1

commit 1348641c7bdd8b3f8a03577b13349aa1c1de5be1
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 21 16:59:51 2020 -0400

    16859: default include_old_versions: true for GET by PDH or UUID
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/api/app/controllers/arvados/v1/collections_controller.rb b/services/api/app/controllers/arvados/v1/collections_controller.rb
index 81b9ca9e5..656bd37ae 100644
--- a/services/api/app/controllers/arvados/v1/collections_controller.rb
+++ b/services/api/app/controllers/arvados/v1/collections_controller.rb
@@ -56,11 +56,19 @@ class Arvados::V1::CollectionsController < ApplicationController
   end
 
   def find_object_by_uuid
-    @include_old_versions = true
+    if params[:include_old_versions].nil?
+      @include_old_versions = true
+    else
+      @include_old_versions = params[:include_old_versions]
+    end
 
     if loc = Keep::Locator.parse(params[:id])
       loc.strip_hints!
 
+      opts = {}
+      opts.update({include_trash: true}) if params[:include_trash]
+      opts.update({include_old_versions: @include_old_versions})
+
       # It matters which Collection object we pick because we use it to get signed_manifest_text,
       # the value of which is affected by the value of trash_at.
       #
@@ -72,14 +80,13 @@ class Arvados::V1::CollectionsController < ApplicationController
       # it will select the Collection object with the longest
       # available lifetime.
 
-      if c = Collection.readable_by(*@read_users).where({ portable_data_hash: loc.to_s }).order("trash_at desc").limit(1).first
+      if c = Collection.readable_by(*@read_users, opts).where({ portable_data_hash: loc.to_s }).order("trash_at desc").limit(1).first
         @object = {
           uuid: c.portable_data_hash,
           portable_data_hash: c.portable_data_hash,
           manifest_text: c.signed_manifest_text,
         }
       end
-      true
     else
       super
     end
diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb
index d8017881d..c025394bc 100644
--- a/services/api/test/functional/arvados/v1/collections_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb
@@ -1388,6 +1388,16 @@ EOS
                   json_response['name']
   end
 
+  test 'can get old version collection by PDH' do
+    authorize_with :active
+    get :show, params: {
+      id: collections(:collection_owned_by_active_past_version_1).portable_data_hash,
+    }
+    assert_response :success
+    assert_equal collections(:collection_owned_by_active_past_version_1).portable_data_hash,
+                  json_response['portable_data_hash']
+  end
+
   test 'version and current_version_uuid are ignored at creation time' do
     permit_unsigned_manifests
     authorize_with :active

commit 2b5431b453c81536dd3ba487ffc201540ab72876
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Tue Sep 22 13:20:51 2020 -0400

    Tweak text saying which version of Ruby to install & add upgrade note
    
    refs #16861
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/doc/_includes/_install_ruby_and_bundler.liquid b/doc/_includes/_install_ruby_and_bundler.liquid
index 9ea8c92cd..d1d33cbbe 100644
--- a/doc/_includes/_install_ruby_and_bundler.liquid
+++ b/doc/_includes/_install_ruby_and_bundler.liquid
@@ -18,11 +18,13 @@ Future versions of Arvados may require a newer version of Ruby than is packaged
 
 h3. Centos 7
 
-The Ruby version shipped with Centos 7 is too old.  Use "RVM":#rvm.
+The Ruby version shipped with Centos 7 is too old.  Use "RVM":#rvm to install Ruby 2.5 or later.
 
 h3. Debian and Ubuntu
 
-Debian 9 (stretch) and Ubuntu 16.04 (xenial) ship Ruby 2.3, which is too old to run Arvados.  Use "RVM":#rvm. Later releases have newer versions of Ruby that can also run Arvados.
+Debian 9 (stretch) and Ubuntu 16.04 (xenial) ship Ruby 2.3, which is not supported by Arvados.  Use "RVM":#rvm to install Ruby 2.5 or later.
+
+Debian 10 (buster) and Ubuntu 18.04 (bionic) and later ship with Ruby 2.5, which is supported by Arvados.
 
 <notextile>
 <pre><code># <span class="userinput">apt-get --no-install-recommends install ruby ruby-dev bundler</span></code></pre>
diff --git a/doc/admin/upgrading.html.textile.liquid b/doc/admin/upgrading.html.textile.liquid
index 061b68fa5..c6b415e4f 100644
--- a/doc/admin/upgrading.html.textile.liquid
+++ b/doc/admin/upgrading.html.textile.liquid
@@ -34,10 +34,14 @@ TODO: extract this information based on git commit messages and generate changel
 <div class="releasenotes">
 </notextile>
 
-h2(#master). development master (as of 2020-06-17)
+h2(#master). development master (as of 2020-09-22)
 
 "Upgrading from 2.0.0":#v2_0_0
 
+h3. Minimum supported Ruby version is now 2.5
+
+The minimum supported Ruby version is now 2.5.  If you are running Arvados on Debian 9 or Ubuntu 16.04, you may need to switch to using RVM or upgrade your OS.  See "Install Ruby and Bundler":../install/ruby.html for more information.
+
 h3. Removing libpam-arvados, replaced with libpam-arvados-go
 
 The Python-based PAM package has been replaced with a version written in Go. See "using PAM for authentication":{{site.baseurl}}/install/setup-login.html#pam for details.

commit ee2d76e5ca4b3da4869d0db9fd68212a781deba0
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 21 16:13:13 2020 -0400

    16856: Fix tests.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/cwl/tests/test_submit.py b/sdk/cwl/tests/test_submit.py
index 4da545bf3..d2dd6e816 100644
--- a/sdk/cwl/tests/test_submit.py
+++ b/sdk/cwl/tests/test_submit.py
@@ -302,7 +302,7 @@ def stubs(func):
             'secret_mounts': {},
             'state': 'Committed',
             'command': ['arvados-cwl-runner', '--local', '--api=containers',
-                        '--no-log-timestamps', '--disable-validate',
+                        '--no-log-timestamps', '--disable-validate', '--disable-color',
                         '--eval-timeout=20', '--thread-count=1',
                         '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue',
                         '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'],
@@ -412,7 +412,7 @@ class TestSubmit(unittest.TestCase):
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = [
             'arvados-cwl-runner', '--local', '--api=containers',
-            '--no-log-timestamps', '--disable-validate',
+            '--no-log-timestamps', '--disable-validate', '--disable-color',
             '--eval-timeout=20', '--thread-count=1',
             '--disable-reuse', "--collection-cache-size=256",
             '--debug', '--on-error=continue',
@@ -436,7 +436,7 @@ class TestSubmit(unittest.TestCase):
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = [
             'arvados-cwl-runner', '--local', '--api=containers',
-            '--no-log-timestamps', '--disable-validate',
+            '--no-log-timestamps', '--disable-validate', '--disable-color',
             '--eval-timeout=20', '--thread-count=1',
             '--disable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue',
             '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
@@ -468,7 +468,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        '--debug', '--on-error=stop',
@@ -491,7 +491,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        "--output-name="+output_name, '--debug', '--on-error=continue',
@@ -513,7 +513,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256", "--debug",
                                        "--storage-classes=foo", '--on-error=continue',
@@ -576,7 +576,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256", '--debug',
                                        '--on-error=continue',
@@ -599,7 +599,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        '--debug', '--on-error=continue',
@@ -623,7 +623,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        "--output-tags="+output_tags, '--debug', '--on-error=continue',
@@ -700,7 +700,7 @@ class TestSubmit(unittest.TestCase):
             'name': 'expect_arvworkflow.cwl#main',
             'container_image': '999999999999999999999999999999d3+99',
             'command': ['arvados-cwl-runner', '--local', '--api=containers',
-                        '--no-log-timestamps', '--disable-validate',
+                        '--no-log-timestamps', '--disable-validate', '--disable-color',
                         '--eval-timeout=20', '--thread-count=1',
                         '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue',
                         '/var/lib/cwl/workflow/expect_arvworkflow.cwl#main', '/var/lib/cwl/cwl.input.json'],
@@ -795,7 +795,7 @@ class TestSubmit(unittest.TestCase):
             'name': 'a test workflow',
             'container_image': "999999999999999999999999999999d3+99",
             'command': ['arvados-cwl-runner', '--local', '--api=containers',
-                        '--no-log-timestamps', '--disable-validate',
+                        '--no-log-timestamps', '--disable-validate', '--disable-color',
                         '--eval-timeout=20', '--thread-count=1',
                         '--enable-reuse', "--collection-cache-size=256", '--debug', '--on-error=continue',
                         '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json'],
@@ -859,7 +859,7 @@ class TestSubmit(unittest.TestCase):
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["owner_uuid"] = project_uuid
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        "--eval-timeout=20", "--thread-count=1",
                                        '--enable-reuse', "--collection-cache-size=256", '--debug',
                                        '--on-error=continue',
@@ -881,7 +881,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=60.0', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        '--debug', '--on-error=continue',
@@ -902,7 +902,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=1',
                                        '--enable-reuse', "--collection-cache-size=500",
                                        '--debug', '--on-error=continue',
@@ -924,7 +924,7 @@ class TestSubmit(unittest.TestCase):
 
         expect_container = copy.deepcopy(stubs.expect_container_spec)
         expect_container["command"] = ['arvados-cwl-runner', '--local', '--api=containers',
-                                       '--no-log-timestamps', '--disable-validate',
+                                       '--no-log-timestamps', '--disable-validate', '--disable-color',
                                        '--eval-timeout=20', '--thread-count=20',
                                        '--enable-reuse', "--collection-cache-size=256",
                                        '--debug', '--on-error=continue',
@@ -994,7 +994,7 @@ class TestSubmit(unittest.TestCase):
             "arv": "http://arvados.org/cwl#",
         }
         expect_container['command'] = ['arvados-cwl-runner', '--local', '--api=containers',
-                        '--no-log-timestamps', '--disable-validate',
+                        '--no-log-timestamps', '--disable-validate', '--disable-color',
                         '--eval-timeout=20', '--thread-count=1',
                         '--enable-reuse', "--collection-cache-size=512", '--debug', '--on-error=continue',
                         '/var/lib/cwl/workflow.json#main', '/var/lib/cwl/cwl.input.json']
@@ -1059,6 +1059,7 @@ class TestSubmit(unittest.TestCase):
                 "--api=containers",
                 "--no-log-timestamps",
                 "--disable-validate",
+                "--disable-color",
                 "--eval-timeout=20",
                 '--thread-count=1',
                 "--enable-reuse",

commit 161999468e2c6e823fa488c667353d138d8f155d
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 21 14:44:57 2020 -0400

    16856: Log the cluster being submitted to
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/apps/workbench/app/views/work_units/_show_component.html.erb b/apps/workbench/app/views/work_units/_show_component.html.erb
index cac263d1e..4cce090a2 100644
--- a/apps/workbench/app/views/work_units/_show_component.html.erb
+++ b/apps/workbench/app/views/work_units/_show_component.html.erb
@@ -45,13 +45,13 @@ SPDX-License-Identifier: AGPL-3.0 %>
       <div class="panel-heading">
         <h4 class="panel-title">
           <a class="component-detail-panel" data-toggle="collapse" href="#errorDetail">
-            <span class="caret"></span> Error: <%= sanitize(wu.runtime_status[:error]) %>
+            <span class="caret"></span> Error: <%= h(wu.runtime_status[:error]) %>
           </a>
         </h4>
       </div>
       <div id="errorDetail" class="panel-body panel-collapse collapse">
         <% if wu.runtime_status[:errorDetail] %>
-          <pre><%= sanitize(wu.runtime_status[:errorDetail]) %></pre>
+          <pre><%= h(wu.runtime_status[:errorDetail]) %></pre>
         <% else %>
           No detailed information available.
         <% end %>
@@ -69,13 +69,13 @@ SPDX-License-Identifier: AGPL-3.0 %>
       <div class="panel-heading">
         <h4 class="panel-title">
           <a class="component-detail-panel" data-toggle="collapse" href="#warningDetail">
-            <span class="caret"></span> Warning: <%= sanitize(wu.runtime_status[:warning]) %>
+            <span class="caret"></span> Warning: <%= h(wu.runtime_status[:warning]) %>
           </a>
         </h4>
       </div>
       <div id="warningDetail" class="panel-body panel-collapse collapse">
         <% if wu.runtime_status[:warningDetail] %>
-          <pre><%= sanitize(wu.runtime_status[:warningDetail]) %></pre>
+          <pre><%= h(wu.runtime_status[:warningDetail]) %></pre>
         <% else %>
           No detailed information available.
         <% end %>
diff --git a/sdk/cwl/arvados_cwl/arvcontainer.py b/sdk/cwl/arvados_cwl/arvcontainer.py
index 9d14ceeab..99d82f339 100644
--- a/sdk/cwl/arvados_cwl/arvcontainer.py
+++ b/sdk/cwl/arvados_cwl/arvcontainer.py
@@ -325,8 +325,8 @@ class ArvadosContainer(JobBase):
                 logger.info("%s reused container %s", self.arvrunner.label(self), response["container_uuid"])
             else:
                 logger.info("%s %s state is %s", self.arvrunner.label(self), response["uuid"], response["state"])
-        except Exception:
-            logger.exception("%s got an error", self.arvrunner.label(self))
+        except Exception as e:
+            logger.exception("%s error submitting container\n%s", self.arvrunner.label(self), e)
             logger.debug("Container request was %s", container_request)
             self.output_callback({}, "permanentFail")
 
diff --git a/sdk/cwl/arvados_cwl/executor.py b/sdk/cwl/arvados_cwl/executor.py
index 9ba798ec6..68141586d 100644
--- a/sdk/cwl/arvados_cwl/executor.py
+++ b/sdk/cwl/arvados_cwl/executor.py
@@ -524,6 +524,8 @@ The 'jobs' API is no longer supported.
     def arv_executor(self, updated_tool, job_order, runtimeContext, logger=None):
         self.debug = runtimeContext.debug
 
+        logger.info("Using cluster %s (%s)", self.api.config()["ClusterID"], self.api.config()["Services"]["Controller"]["ExternalURL"])
+
         updated_tool.visit(self.check_features)
 
         self.project_uuid = runtimeContext.project_uuid
diff --git a/sdk/dev-jobs.dockerfile b/sdk/dev-jobs.dockerfile
index dd067e977..f7719dbc4 100644
--- a/sdk/dev-jobs.dockerfile
+++ b/sdk/dev-jobs.dockerfile
@@ -14,12 +14,12 @@
 #  of the docker build root.)
 
 FROM debian:9
-MAINTAINER Ward Vandewege <ward at curoverse.com>
+MAINTAINER Peter Amstutz <peter.amstutz at curii.com>
 
 ENV DEBIAN_FRONTEND noninteractive
 
-ARG pythoncmd=python
-ARG pipcmd=pip
+ARG pythoncmd=python3
+ARG pipcmd=pip3
 
 RUN apt-get update -q && apt-get install -qy --no-install-recommends \
     git ${pythoncmd}-pip ${pythoncmd}-virtualenv ${pythoncmd}-dev libcurl4-gnutls-dev \

commit 78ea5727119d2c29d14fd395f2297b3d0db17405
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 21 14:33:17 2020 -0400

    16856: Make spurious msg "Using empty collection" debug log level
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/python/arvados/commands/run.py b/sdk/python/arvados/commands/run.py
index a45775470..1e64eeb1d 100644
--- a/sdk/python/arvados/commands/run.py
+++ b/sdk/python/arvados/commands/run.py
@@ -236,7 +236,7 @@ def uploadfiles(files, api, dry_run=False, num_retries=0,
             # empty collection
             pdh = collection.portable_data_hash()
             assert (pdh == config.EMPTY_BLOCK_LOCATOR), "Empty collection portable_data_hash did not have expected locator, was %s" % pdh
-            logger.info("Using empty collection %s", pdh)
+            logger.debug("Using empty collection %s", pdh)
 
     for c in files:
         c.keepref = "%s/%s" % (pdh, c.fn)

commit 72c368cb5016dab37554756fcbb6e30e17357126
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 21 14:25:58 2020 -0400

    16856: Pass --disable-color, workbench log doesn't do color codes
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/sdk/cwl/arvados_cwl/__init__.py b/sdk/cwl/arvados_cwl/__init__.py
index dcbe03a05..4bfe27278 100644
--- a/sdk/cwl/arvados_cwl/__init__.py
+++ b/sdk/cwl/arvados_cwl/__init__.py
@@ -192,6 +192,10 @@ def arg_parser():  # type: () -> argparse.ArgumentParser
                         action="store_false", default=True,
                         help=argparse.SUPPRESS)
 
+    parser.add_argument("--disable-color", dest="enable_color",
+                        action="store_false", default=True,
+                        help=argparse.SUPPRESS)
+
     parser.add_argument("--disable-js-validation",
                         action="store_true", default=False,
                         help=argparse.SUPPRESS)
diff --git a/sdk/cwl/arvados_cwl/arvcontainer.py b/sdk/cwl/arvados_cwl/arvcontainer.py
index fb23c2ccf..9d14ceeab 100644
--- a/sdk/cwl/arvados_cwl/arvcontainer.py
+++ b/sdk/cwl/arvados_cwl/arvcontainer.py
@@ -475,6 +475,7 @@ class RunnerContainer(Runner):
                    "--api=containers",
                    "--no-log-timestamps",
                    "--disable-validate",
+                   "--disable-color",
                    "--eval-timeout=%s" % self.arvrunner.eval_timeout,
                    "--thread-count=%s" % self.arvrunner.thread_count,
                    "--enable-reuse" if self.enable_reuse else "--disable-reuse",

commit 4053029e959bc5857f95542b9da464351289a35c
Author: Ward Vandewege <ward at curii.com>
Date:   Tue Sep 22 11:52:35 2020 -0400

    Update our docs to state a minimum requirement of Ruby 2.5, since we
    don't test on 2.3 anymore.
    
    closes #16868
    refs #16861
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/doc/_includes/_install_ruby_and_bundler.liquid b/doc/_includes/_install_ruby_and_bundler.liquid
index d14e555f8..9ea8c92cd 100644
--- a/doc/_includes/_install_ruby_and_bundler.liquid
+++ b/doc/_includes/_install_ruby_and_bundler.liquid
@@ -4,7 +4,7 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-Minimum of Ruby 2.3 is required.  Ruby 2.5 is recommended.
+Ruby 2.5 or newer is required.
 
 * "Option 1: Install from packages":#packages
 * "Option 2: Install with RVM":#rvm
@@ -13,16 +13,16 @@ Minimum of Ruby 2.3 is required.  Ruby 2.5 is recommended.
 h2(#packages). Option 1: Install from packages
 
 {% include 'notebox_begin' %}
-Future versions of Arvados may require a newer version of Ruby than is packaged with your OS.  Using OS packages simplifies initial install, but may complicate upgrades that rely on a newer Ruby.  If this is a concern, we recommend using "RVM.":#rvm
+Future versions of Arvados may require a newer version of Ruby than is packaged with your OS.  Using OS packages simplifies initial install, but may complicate upgrades that rely on a newer Ruby.  If this is a concern, we recommend using "RVM":#rvm.
 {% include 'notebox_end' %}
 
 h3. Centos 7
 
-The Ruby version shipped with Centos 7 is too old.  Use "RVM.":#rvm
+The Ruby version shipped with Centos 7 is too old.  Use "RVM":#rvm.
 
 h3. Debian and Ubuntu
 
-Debian 9 (stretch) and Ubuntu 16.04 (xenial) ship Ruby 2.3, which is sufficient to run Arvados.  Later releases have newer versions of Ruby that can also run Arvados.
+Debian 9 (stretch) and Ubuntu 16.04 (xenial) ship Ruby 2.3, which is too old to run Arvados.  Use "RVM":#rvm. Later releases have newer versions of Ruby that can also run Arvados.
 
 <notextile>
 <pre><code># <span class="userinput">apt-get --no-install-recommends install ruby ruby-dev bundler</span></code></pre>

commit 6ae66e2b611eeab0697d822bbdaa2dccbd1f3c77
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date:   Fri Sep 18 19:17:04 2020 -0300

    16791: Restores original deadline of 10 seconds on test.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>

diff --git a/services/api/test/unit/log_test.rb b/services/api/test/unit/log_test.rb
index 131f8b4b1..76d78f9ea 100644
--- a/services/api/test/unit/log_test.rb
+++ b/services/api/test/unit/log_test.rb
@@ -372,7 +372,7 @@ class LogTest < ActiveSupport::TestCase
     act_as_system_user do
       Log.create!()
     end
-    deadline = Time.now + 1
+    deadline = Time.now + 10
     while remaining_audit_logs.count == initial_audit_log_count
       if Time.now > deadline
         raise "timed out"

commit 4e636294758928a3477da4d4d746677388dab69b
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date:   Fri Sep 18 17:18:57 2020 -0300

    16791: Fixes audit log cleaning tests.
    
    Log fixtures lacking the created_at field set in the past in combination
    with incorrect testing made us believe the LogTest was working ok.
    Specifically, LogTest#test_delete_old_audit_logs_in_thread was not doing
    the waiting for the log entries to be eliminated, so there was a race
    between the AuditLogs thread cleaning the records and the test teardown doing
    the rollback producing the intermittent failure of
    use_ownership_and_permission_links_to_determine_which_logs_a_user_can_see.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>

diff --git a/services/api/test/fixtures/logs.yml b/services/api/test/fixtures/logs.yml
index b1b77c519..25f1efff6 100644
--- a/services/api/test/fixtures/logs.yml
+++ b/services/api/test/fixtures/logs.yml
@@ -9,6 +9,7 @@ noop: # nothing happened ...to the 'spectator' user
   object_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
   object_owner_uuid: zzzzz-tpzed-000000000000000
   event_at: <%= 1.minute.ago.to_s(:db) %>
+  created_at: <%= 1.minute.ago.to_s(:db) %>
 
 admin_changes_repository2: # admin changes repository2, which is owned by active user
   id: 2
@@ -16,6 +17,7 @@ admin_changes_repository2: # admin changes repository2, which is owned by active
   owner_uuid: zzzzz-tpzed-d9tiejq69daie8f # admin user
   object_uuid: zzzzz-2x53u-382brsig8rp3667 # repository foo
   object_owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz # active user
+  created_at: <%= 2.minute.ago.to_s(:db) %>
   event_at: <%= 2.minute.ago.to_s(:db) %>
   event_type: update
 
@@ -25,6 +27,7 @@ admin_changes_specimen: # admin changes specimen owned_by_spectator
   owner_uuid: zzzzz-tpzed-d9tiejq69daie8f # admin user
   object_uuid: zzzzz-2x53u-3b0xxwzlbzxq5yr # specimen owned_by_spectator
   object_owner_uuid: zzzzz-tpzed-l1s2piq4t4mps8r # spectator user
+  created_at: <%= 3.minute.ago.to_s(:db) %>
   event_at: <%= 3.minute.ago.to_s(:db) %>
   event_type: update
 
@@ -34,6 +37,7 @@ system_adds_foo_file: # foo collection added, readable by active through link
   owner_uuid: zzzzz-tpzed-000000000000000 # system user
   object_uuid: zzzzz-4zz18-znfnqtbbv4spc3w # foo file
   object_owner_uuid: zzzzz-tpzed-000000000000000 # system user
+  created_at: <%= 4.minute.ago.to_s(:db) %>
   event_at: <%= 4.minute.ago.to_s(:db) %>
   event_type: create
 
@@ -43,6 +47,7 @@ system_adds_baz: # baz collection added, readable by active and spectator throug
   owner_uuid: zzzzz-tpzed-000000000000000 # system user
   object_uuid: zzzzz-4zz18-y9vne9npefyxh8g # baz file
   object_owner_uuid: zzzzz-tpzed-000000000000000 # system user
+  created_at: <%= 5.minute.ago.to_s(:db) %>
   event_at: <%= 5.minute.ago.to_s(:db) %>
   event_type: create
 
diff --git a/services/api/test/unit/log_test.rb b/services/api/test/unit/log_test.rb
index 58f0cddb7..131f8b4b1 100644
--- a/services/api/test/unit/log_test.rb
+++ b/services/api/test/unit/log_test.rb
@@ -319,6 +319,7 @@ class LogTest < ActiveSupport::TestCase
 
   def assert_no_logs_deleted
     logs_before = Log.unscoped.all.count
+    assert logs_before > 0
     yield
     assert_equal logs_before, Log.unscoped.all.count
   end
@@ -350,34 +351,34 @@ class LogTest < ActiveSupport::TestCase
   # but 3 minutes suits our test data better (and is test-worthy in
   # that it's expected to work correctly in production).
   test 'delete old audit logs with production settings' do
-    initial_log_count = Log.unscoped.all.count
+    initial_log_count = remaining_audit_logs.count
+    assert initial_log_count > 0
     AuditLogs.delete_old(max_age: 180, max_batch: 100000)
     assert_operator remaining_audit_logs.count, :<, initial_log_count
   end
 
   test 'delete all audit logs in multiple batches' do
+    assert remaining_audit_logs.count > 2
     AuditLogs.delete_old(max_age: 0.00001, max_batch: 2)
     assert_equal [], remaining_audit_logs.collect(&:uuid)
   end
 
   test 'delete old audit logs in thread' do
-    begin
-      Rails.configuration.AuditLogs.MaxAge = 20
-      Rails.configuration.AuditLogs.MaxDeleteBatch = 100000
-      Rails.cache.delete 'AuditLogs'
-      initial_log_count = Log.unscoped.all.count + 1
-      act_as_system_user do
-        Log.create!()
-        initial_log_count += 1
-      end
-      deadline = Time.now + 10
-      while remaining_audit_logs.count == initial_log_count
-        if Time.now > deadline
-          raise "timed out"
-        end
-        sleep 0.1
+    Rails.configuration.AuditLogs.MaxAge = 20
+    Rails.configuration.AuditLogs.MaxDeleteBatch = 100000
+    Rails.cache.delete 'AuditLogs'
+    initial_audit_log_count = remaining_audit_logs.count
+    assert initial_audit_log_count > 0
+    act_as_system_user do
+      Log.create!()
+    end
+    deadline = Time.now + 1
+    while remaining_audit_logs.count == initial_audit_log_count
+      if Time.now > deadline
+        raise "timed out"
       end
-      assert_operator remaining_audit_logs.count, :<, initial_log_count
+      sleep 0.1
     end
+    assert_operator remaining_audit_logs.count, :<, initial_audit_log_count
   end
 end

commit 9ce48534a58022505aac8fb0879a4d5fbf5ef156
Author: Lucas Di Pentima <lucas at di-pentima.com.ar>
Date:   Thu Sep 17 11:46:44 2020 -0300

    16791: Fixes log uuids on fixtures.
    
    Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas at di-pentima.com.ar>

diff --git a/services/api/test/fixtures/logs.yml b/services/api/test/fixtures/logs.yml
index 0785c12a5..b1b77c519 100644
--- a/services/api/test/fixtures/logs.yml
+++ b/services/api/test/fixtures/logs.yml
@@ -4,7 +4,7 @@
 
 noop: # nothing happened ...to the 'spectator' user
   id: 1
-  uuid: zzzzz-xxxxx-pshmckwoma9plh7
+  uuid: zzzzz-57u5n-pshmckwoma9plh7
   owner_uuid: zzzzz-tpzed-000000000000000
   object_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
   object_owner_uuid: zzzzz-tpzed-000000000000000
@@ -12,7 +12,7 @@ noop: # nothing happened ...to the 'spectator' user
 
 admin_changes_repository2: # admin changes repository2, which is owned by active user
   id: 2
-  uuid: zzzzz-xxxxx-pshmckwoma00002
+  uuid: zzzzz-57u5n-pshmckwoma00002
   owner_uuid: zzzzz-tpzed-d9tiejq69daie8f # admin user
   object_uuid: zzzzz-2x53u-382brsig8rp3667 # repository foo
   object_owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz # active user
@@ -21,7 +21,7 @@ admin_changes_repository2: # admin changes repository2, which is owned by active
 
 admin_changes_specimen: # admin changes specimen owned_by_spectator
   id: 3
-  uuid: zzzzz-xxxxx-pshmckwoma00003
+  uuid: zzzzz-57u5n-pshmckwoma00003
   owner_uuid: zzzzz-tpzed-d9tiejq69daie8f # admin user
   object_uuid: zzzzz-2x53u-3b0xxwzlbzxq5yr # specimen owned_by_spectator
   object_owner_uuid: zzzzz-tpzed-l1s2piq4t4mps8r # spectator user
@@ -30,7 +30,7 @@ admin_changes_specimen: # admin changes specimen owned_by_spectator
 
 system_adds_foo_file: # foo collection added, readable by active through link
   id: 4
-  uuid: zzzzz-xxxxx-pshmckwoma00004
+  uuid: zzzzz-57u5n-pshmckwoma00004
   owner_uuid: zzzzz-tpzed-000000000000000 # system user
   object_uuid: zzzzz-4zz18-znfnqtbbv4spc3w # foo file
   object_owner_uuid: zzzzz-tpzed-000000000000000 # system user
@@ -39,7 +39,7 @@ system_adds_foo_file: # foo collection added, readable by active through link
 
 system_adds_baz: # baz collection added, readable by active and spectator through group 'all users' group membership
   id: 5
-  uuid: zzzzz-xxxxx-pshmckwoma00005
+  uuid: zzzzz-57u5n-pshmckwoma00005
   owner_uuid: zzzzz-tpzed-000000000000000 # system user
   object_uuid: zzzzz-4zz18-y9vne9npefyxh8g # baz file
   object_owner_uuid: zzzzz-tpzed-000000000000000 # system user
@@ -48,7 +48,7 @@ system_adds_baz: # baz collection added, readable by active and spectator throug
 
 log_owned_by_active:
   id: 6
-  uuid: zzzzz-xxxxx-pshmckwoma12345
+  uuid: zzzzz-57u5n-pshmckwoma12345
   owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz # active user
   object_uuid: zzzzz-2x53u-382brsig8rp3667 # repository foo
   object_owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz # active user

commit c037735e0529c4ff605d90cdae5079200e258270
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Fri Sep 18 19:21:09 2020 -0400

    16811: Add a test that system users/groups can't be deleted.
    
    Also tweak PublicFavoritesProject migration to use up/down instead of
    change.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/services/api/db/migrate/20200914203202_public_favorites_project.rb b/services/api/db/migrate/20200914203202_public_favorites_project.rb
index 0718778dd..ef139aa70 100644
--- a/services/api/db/migrate/20200914203202_public_favorites_project.rb
+++ b/services/api/db/migrate/20200914203202_public_favorites_project.rb
@@ -4,7 +4,7 @@
 
 class PublicFavoritesProject < ActiveRecord::Migration[5.2]
   include CurrentApiClient
-  def change
+  def up
     act_as_system_user do
       public_project_group
       public_project_read_permission
@@ -17,4 +17,7 @@ class PublicFavoritesProject < ActiveRecord::Migration[5.2]
       end
     end
   end
+
+  def down
+  end
 end
diff --git a/services/api/test/fixtures/groups.yml b/services/api/test/fixtures/groups.yml
index ee0d786bb..31a72f172 100644
--- a/services/api/test/fixtures/groups.yml
+++ b/services/api/test/fixtures/groups.yml
@@ -56,6 +56,13 @@ system_group:
   description: System-owned Group
   group_class: role
 
+public_favorites_project:
+  uuid: zzzzz-j7d0g-publicfavorites
+  owner_uuid: zzzzz-tpzed-000000000000000
+  name: Public favorites
+  description: Public favorites
+  group_class: project
+
 empty_lonely_group:
   uuid: zzzzz-j7d0g-jtp06ulmvsezgyu
   owner_uuid: zzzzz-tpzed-000000000000000
diff --git a/services/api/test/unit/permission_test.rb b/services/api/test/unit/permission_test.rb
index 10664474c..123031b35 100644
--- a/services/api/test/unit/permission_test.rb
+++ b/services/api/test/unit/permission_test.rb
@@ -579,4 +579,24 @@ class PermissionTest < ActiveSupport::TestCase
     assert users(:active).can?(write: prj.uuid)
     assert users(:active).can?(manage: prj.uuid)
   end
+
+  [system_user_uuid, anonymous_user_uuid].each do |u|
+    test "cannot delete system user #{u}" do
+      act_as_system_user do
+        assert_raises ArvadosModel::PermissionDeniedError do
+          User.find_by_uuid(u).destroy
+        end
+      end
+    end
+  end
+
+  [system_group_uuid, anonymous_group_uuid, public_project_uuid].each do |g|
+    test "cannot delete system group #{g}" do
+      act_as_system_user do
+        assert_raises ArvadosModel::PermissionDeniedError do
+          Group.find_by_uuid(g).destroy
+        end
+      end
+    end
+  end
 end

commit 58ac679391b0fef4b8dcdc00f90c08cdded6e705
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Mon Sep 14 16:42:07 2020 -0400

    16811: Add "Public project" for storing favorites.
    
    Workbench and documentation updated for "public favorites" group
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index c626e97f1..cf4bfa8c5 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -927,7 +927,7 @@ class ApplicationController < ActionController::Base
   helper_method :my_starred_projects
   def my_starred_projects user
     return if defined?(@starred_projects) && @starred_projects
-    links = Link.filter([['tail_uuid', 'in', ["#{Rails.configuration.ClusterID}-j7d0g-fffffffffffffff", user.uuid]],
+    links = Link.filter([['owner_uuid', 'in', ["#{Rails.configuration.ClusterID}-j7d0g-publicfavorites", user.uuid]],
                          ['link_class', '=', 'star'],
                          ['head_uuid', 'is_a', 'arvados#group']]).with_count("none").select(%w(head_uuid))
     uuids = links.collect { |x| x.head_uuid }
diff --git a/doc/api/methods/links.html.textile.liquid b/doc/api/methods/links.html.textile.liquid
index 98ff23ffb..c71105c74 100644
--- a/doc/api/methods/links.html.textile.liquid
+++ b/doc/api/methods/links.html.textile.liquid
@@ -43,32 +43,27 @@ h3. star
 
 A **star** link is a shortcut to a project that is displayed in the user interface (Workbench) as "favorites".  Users can mark their own favorites (implemented by creating or deleting **star** links).
 
-An admin can also create **star** links owned by the system user, with @tail_uuid@ as the "All Users" group.  These are "public favorites" that will be displayed to all users that have permission to read the project that has been favorited.  Note: setting a public favorite also requires creating a @can_read@ permission link from @All Users@ to the 'star' link record.
+An admin can also create **star** links owned by the "Public favorites" project.  These are favorites will be displayed to all users that have permission to read the project that has been favorited.
 
 The schema for a star link is:
 
 table(table table-bordered table-condensed).
 |_. Field|_. Value|_. Description|
-|tail_uuid|user or group uuid|Either the user that owns the favorite, or the "All Users" group for public favorites.|
+|owner_uuid|user or group uuid|Either the user that owns the favorite, or the "Public favorites" group.|
+|tail_uuid|user or group uuid|Should be the same as owner_uuid|
 |head_uuid|project uuid|The project being favorited|
 |link_class|string of value "star"|Indicates this represents a link to a user favorite|
 
 h4. Creating a public favorite
 
- at tail_uuid@ is either an individual user, or the "All Users" group.  The @head_uuid@ is the project being favorited.
+ at owner_uuid@ is either an individual user, or the "Public favorites" group.  The @head_uuid@ is the project being favorited.
 
 <pre>
 $ linkuuid=$(arv --format=uuid link create --link '{
     "link_class": "star",
-    "owner_uuid": "zzzzz-tpzed-000000000000000",
-    "tail_uuid": "zzzzz-j7d0g-fffffffffffffff",
+    "owner_uuid": "zzzzz-j7d0g-publicfavorites",
+    "tail_uuid": "zzzzz-j7d0g-publicfavorites",
     "head_uuid":  "zzzzz-j7d0g-theprojectuuid"}')
-
-$ arv link create --link '{
-    "link_class": "permission",
-    "name": "can_read",
-    "tail_uuid": "zzzzz-j7d0g-fffffffffffffff",
-    "head_uuid":  "zzzzz-o0j2j-'$linkuuid'"}'
 </pre>
 
 h4. Removing a favorite
@@ -84,7 +79,7 @@ To list all 'star' links that will be displayed for a user:
 <pre>
 $ arv link list --filters '[
   ["link_class", "=", "star"],
-  ["tail_uuid", "in", ["zzzzz-j7d0g-fffffffffffffff", "zzzzz-tpzed-currentuseruuid"]]]'
+  ["tail_uuid", "in", ["zzzzz-j7d0g-publicfavorites", "zzzzz-tpzed-currentuseruuid"]]]'
 </pre>
 
 h3. tag
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 709b4b4d1..3966b7c39 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -627,7 +627,12 @@ class ArvadosModel < ApplicationRecord
   end
 
   def permission_to_destroy
-    permission_to_update
+    if [system_user_uuid, system_group_uuid, anonymous_group_uuid,
+        anonymous_user_uuid, public_project_uuid].include? uuid
+      false
+    else
+      permission_to_update
+    end
   end
 
   def maybe_update_modified_by_fields
diff --git a/services/api/app/models/database_seeds.rb b/services/api/app/models/database_seeds.rb
index d7c5e04df..abfb672af 100644
--- a/services/api/app/models/database_seeds.rb
+++ b/services/api/app/models/database_seeds.rb
@@ -14,6 +14,8 @@ class DatabaseSeeds
     anonymous_group_read_permission
     anonymous_user
     system_root_token_api_client
+    public_project_group
+    public_project_read_permission
     empty_collection
     refresh_permissions
     refresh_trashed
diff --git a/services/api/db/migrate/20200914203202_public_favorites_project.rb b/services/api/db/migrate/20200914203202_public_favorites_project.rb
new file mode 100644
index 000000000..0718778dd
--- /dev/null
+++ b/services/api/db/migrate/20200914203202_public_favorites_project.rb
@@ -0,0 +1,20 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+class PublicFavoritesProject < ActiveRecord::Migration[5.2]
+  include CurrentApiClient
+  def change
+    act_as_system_user do
+      public_project_group
+      public_project_read_permission
+      Link.where(link_class: "star",
+                 owner_uuid: system_user_uuid,
+                 tail_uuid: all_users_group_uuid).each do |ln|
+        ln.owner_uuid = public_project_uuid
+        ln.tail_uuid = public_project_uuid
+        ln.save!
+      end
+    end
+  end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index 83987d051..a5740834c 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -3197,6 +3197,7 @@ INSERT INTO "schema_migrations" (version) VALUES
 ('20190809135453'),
 ('20190905151603'),
 ('20200501150153'),
-('20200602141328');
+('20200602141328'),
+('20200914203202');
 
 
diff --git a/services/api/lib/current_api_client.rb b/services/api/lib/current_api_client.rb
index cfdae0bdd..dc40f158e 100644
--- a/services/api/lib/current_api_client.rb
+++ b/services/api/lib/current_api_client.rb
@@ -9,6 +9,8 @@ $anonymous_user = nil
 $anonymous_group = nil
 $anonymous_group_read_permission = nil
 $empty_collection = nil
+$public_project_group = nil
+$public_project_group_read_permission = nil
 
 module CurrentApiClient
   def current_user
@@ -65,6 +67,12 @@ module CurrentApiClient
      'anonymouspublic'].join('-')
   end
 
+  def public_project_uuid
+    [Rails.configuration.ClusterID,
+     Group.uuid_prefix,
+     'publicfavorites'].join('-')
+  end
+
   def system_user
     $system_user = check_cache $system_user do
       real_current_user = Thread.current[:user]
@@ -189,6 +197,31 @@ module CurrentApiClient
     end
   end
 
+  def public_project_group
+    $public_project_group = check_cache $public_project_group do
+      act_as_system_user do
+        ActiveRecord::Base.transaction do
+          Group.where(uuid: public_project_uuid).
+            first_or_create!(group_class: "project",
+                             name: "Public favorites",
+                             description: "Public favorites")
+        end
+      end
+    end
+  end
+
+  def public_project_read_permission
+    $public_project_group_read_permission =
+        check_cache $public_project_group_read_permission do
+      act_as_system_user do
+        Link.where(tail_uuid: anonymous_group.uuid,
+                   head_uuid: public_project_group.uuid,
+                   link_class: "permission",
+                   name: "can_read").first_or_create!
+      end
+    end
+  end
+
   def system_root_token_api_client
     $system_root_token_api_client = check_cache $system_root_token_api_client do
       act_as_system_user do

commit 10e3554400dfae1d8e6fe58cd78f46b0a60f86be
Author: Peter Amstutz <peter.amstutz at curii.com>
Date:   Thu Sep 10 17:41:54 2020 -0400

    16811: Make public favorites work
    
    Update API docs.
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz at curii.com>

diff --git a/apps/workbench/app/controllers/application_controller.rb b/apps/workbench/app/controllers/application_controller.rb
index 77ec68bdb..c626e97f1 100644
--- a/apps/workbench/app/controllers/application_controller.rb
+++ b/apps/workbench/app/controllers/application_controller.rb
@@ -927,7 +927,7 @@ class ApplicationController < ActionController::Base
   helper_method :my_starred_projects
   def my_starred_projects user
     return if defined?(@starred_projects) && @starred_projects
-    links = Link.filter([['owner_uuid', 'in', ["#{Rails.configuration.ClusterID}-j7d0g-fffffffffffffff", user.uuid]],
+    links = Link.filter([['tail_uuid', 'in', ["#{Rails.configuration.ClusterID}-j7d0g-fffffffffffffff", user.uuid]],
                          ['link_class', '=', 'star'],
                          ['head_uuid', 'is_a', 'arvados#group']]).with_count("none").select(%w(head_uuid))
     uuids = links.collect { |x| x.head_uuid }
diff --git a/doc/api/methods/links.html.textile.liquid b/doc/api/methods/links.html.textile.liquid
index 2e5de1856..98ff23ffb 100644
--- a/doc/api/methods/links.html.textile.liquid
+++ b/doc/api/methods/links.html.textile.liquid
@@ -43,28 +43,35 @@ h3. star
 
 A **star** link is a shortcut to a project that is displayed in the user interface (Workbench) as "favorites".  Users can mark their own favorites (implemented by creating or deleting **star** links).
 
-An admin can also create **star** links owned by the "All Users" group, these will be displayed to all users that have permission to read the project that has been favorited.
+An admin can also create **star** links owned by the system user, with @tail_uuid@ as the "All Users" group.  These are "public favorites" that will be displayed to all users that have permission to read the project that has been favorited.  Note: setting a public favorite also requires creating a @can_read@ permission link from @All Users@ to the 'star' link record.
 
 The schema for a star link is:
 
 table(table table-bordered table-condensed).
 |_. Field|_. Value|_. Description|
-|owner_uuid|user or group uuid|Either the user that owns the favorite, or the "All Users" group for public favorites.|
+|tail_uuid|user or group uuid|Either the user that owns the favorite, or the "All Users" group for public favorites.|
 |head_uuid|project uuid|The project being favorited|
 |link_class|string of value "star"|Indicates this represents a link to a user favorite|
 
-h4. Creating a favorite
+h4. Creating a public favorite
 
- at owner_uuid@ is either an individual user, or the "All Users" group.  The @head_uuid@ is the project being favorited.
+ at tail_uuid@ is either an individual user, or the "All Users" group.  The @head_uuid@ is the project being favorited.
 
 <pre>
+$ linkuuid=$(arv --format=uuid link create --link '{
+    "link_class": "star",
+    "owner_uuid": "zzzzz-tpzed-000000000000000",
+    "tail_uuid": "zzzzz-j7d0g-fffffffffffffff",
+    "head_uuid":  "zzzzz-j7d0g-theprojectuuid"}')
+
 $ arv link create --link '{
-    "owner_uuid": "zzzzz-j7d0g-fffffffffffffff",
-    "head_uuid":  "zzzzz-j7d0g-theprojectuuid",
-    "link_class": "star"}'
+    "link_class": "permission",
+    "name": "can_read",
+    "tail_uuid": "zzzzz-j7d0g-fffffffffffffff",
+    "head_uuid":  "zzzzz-o0j2j-'$linkuuid'"}'
 </pre>
 
-h4. Deleting a favorite
+h4. Removing a favorite
 
 <pre>
 $ arv link delete --uuid zzzzz-o0j2j-thestarlinkuuid
@@ -77,7 +84,7 @@ To list all 'star' links that will be displayed for a user:
 <pre>
 $ arv link list --filters '[
   ["link_class", "=", "star"],
-  ["owner_uuid", "in", ["zzzzz-j7d0g-fffffffffffffff", "zzzzz-tpzed-currentuseruuid"]]]'
+  ["tail_uuid", "in", ["zzzzz-j7d0g-fffffffffffffff", "zzzzz-tpzed-currentuseruuid"]]]'
 </pre>
 
 h3. tag

commit cf07c5549bb73b9fdefee7dd266f627dd4d62b47
Author: Ward Vandewege <ward at curii.com>
Date:   Fri Sep 25 17:31:43 2020 -0400

    16267: fix logic bug, use local checked out arvados directory in dev
           mode, not the copy under ~/.arvbox
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/tools/arvbox/bin/arvbox b/tools/arvbox/bin/arvbox
index e8e3fa17c..29f25daf8 100755
--- a/tools/arvbox/bin/arvbox
+++ b/tools/arvbox/bin/arvbox
@@ -374,27 +374,25 @@ build() {
         FORCE=-f
     fi
     GITHEAD=$(cd $ARVBOX_DOCKER && git log --format=%H -n1 HEAD)
+
+    set +e
+    if which greadlink >/dev/null 2>/dev/null ; then
+        LOCAL_ARVADOS_ROOT=$(greadlink -f $(dirname $0)/../../../)
+    else
+        LOCAL_ARVADOS_ROOT=$(readlink -f $(dirname $0)/../../../)
+    fi
+    set -e
+
     if test "$1" = localdemo -o "$1" = publicdemo ; then
-        set +e
-        if which greadlink >/dev/null 2>/dev/null ; then
-          ARVADOS_ROOT=$(greadlink -f $(dirname $0)/../../../)
-        else
-          ARVADOS_ROOT=$(readlink -f $(dirname $0)/../../../)
-        fi
-        set -e
-        docker build --build-arg=BUILDTYPE=demo $NO_CACHE --build-arg=arvados_version=$GITHEAD --build-arg=workdir=/tools/arvbox/lib/arvbox/docker -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVADOS_ROOT"
-        docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
-        docker build $NO_CACHE -t arvados/arvbox-demo:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
-        docker tag $FORCE arvados/arvbox-demo:$GITHEAD arvados/arvbox-demo:latest
+        BUILDTYPE=demo
     else
-        if ! test -d "$ARVADOS_ROOT" ; then
-            git clone https://git.arvados.org/arvados.git "$ARVADOS_ROOT"
-        fi
-        docker build --build-arg=BUILDTYPE=dev $NO_CACHE --build-arg=arvados_version=$GITHEAD --build-arg=workdir=/tools/arvbox/lib/arvbox/docker -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVADOS_ROOT"
-        docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
-        docker build $NO_CACHE -t arvados/arvbox-dev:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
-        docker tag $FORCE arvados/arvbox-dev:$GITHEAD arvados/arvbox-dev:latest
+        BUILDTYPE=dev
     fi
+
+    docker build --build-arg=BUILDTYPE=$BUILDTYPE $NO_CACHE --build-arg=arvados_version=$GITHEAD --build-arg=workdir=/tools/arvbox/lib/arvbox/docker -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$LOCAL_ARVADOS_ROOT"
+    docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
+    docker build $NO_CACHE -t arvados/arvbox-$BUILDTYPE:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.$BUILDTYPE" "$ARVBOX_DOCKER"
+    docker tag $FORCE arvados/arvbox-$BUILDTYPE:$GITHEAD arvados/arvbox-$BUILDTYPE:latest
 }
 
 check() {

commit 22d03e114e25c7076185fba36a912766c49a9ed4
Author: Ward Vandewege <ward at curii.com>
Date:   Thu Sep 24 20:49:57 2020 -0400

    16267: implement review feedback.
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/tools/arvbox/bin/arvbox b/tools/arvbox/bin/arvbox
index 8fd77f1f2..e8e3fa17c 100755
--- a/tools/arvbox/bin/arvbox
+++ b/tools/arvbox/bin/arvbox
@@ -363,6 +363,7 @@ stop() {
 }
 
 build() {
+    export DOCKER_BUILDKIT=1
     if ! test -f "$ARVBOX_DOCKER/Dockerfile.base" ;  then
         echo "Could not find Dockerfile (expected it at $ARVBOX_DOCKER/Dockerfile.base)"
         exit 1
@@ -373,12 +374,24 @@ build() {
         FORCE=-f
     fi
     GITHEAD=$(cd $ARVBOX_DOCKER && git log --format=%H -n1 HEAD)
-    docker build --build-arg=arvados_version=$GITHEAD $NO_CACHE -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVBOX_DOCKER"
-    docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
     if test "$1" = localdemo -o "$1" = publicdemo ; then
+        set +e
+        if which greadlink >/dev/null 2>/dev/null ; then
+          ARVADOS_ROOT=$(greadlink -f $(dirname $0)/../../../)
+        else
+          ARVADOS_ROOT=$(readlink -f $(dirname $0)/../../../)
+        fi
+        set -e
+        docker build --build-arg=BUILDTYPE=demo $NO_CACHE --build-arg=arvados_version=$GITHEAD --build-arg=workdir=/tools/arvbox/lib/arvbox/docker -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVADOS_ROOT"
+        docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
         docker build $NO_CACHE -t arvados/arvbox-demo:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.demo" "$ARVBOX_DOCKER"
         docker tag $FORCE arvados/arvbox-demo:$GITHEAD arvados/arvbox-demo:latest
     else
+        if ! test -d "$ARVADOS_ROOT" ; then
+            git clone https://git.arvados.org/arvados.git "$ARVADOS_ROOT"
+        fi
+        docker build --build-arg=BUILDTYPE=dev $NO_CACHE --build-arg=arvados_version=$GITHEAD --build-arg=workdir=/tools/arvbox/lib/arvbox/docker -t arvados/arvbox-base:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.base" "$ARVADOS_ROOT"
+        docker tag $FORCE arvados/arvbox-base:$GITHEAD arvados/arvbox-base:latest
         docker build $NO_CACHE -t arvados/arvbox-dev:$GITHEAD -f "$ARVBOX_DOCKER/Dockerfile.dev" "$ARVBOX_DOCKER"
         docker tag $FORCE arvados/arvbox-dev:$GITHEAD arvados/arvbox-dev:latest
     fi
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.base b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
index 9031de79b..115754cac 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.base
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
@@ -1,9 +1,19 @@
+# syntax = docker/dockerfile:experimental
 # Copyright (C) The Arvados Authors. All rights reserved.
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-FROM debian:10
+ARG BUILDTYPE
+
+# We're using poor man's conditionals (see
+# https://www.docker.com/blog/advanced-dockerfiles-faster-builds-and-smaller-images-using-buildkit-and-multistage-builds/)
+# here to dtrt in the dev/test scenario and the demo scenario. In the dev/test
+# scenario, we use the docker context (i.e. the copy of Arvados checked out on
+# the host) to build arvados-server. In the demo scenario, we check out a new
+# tree, and use the $arvados_version commit (passed in via an argument).
 
+###########################################################################################################
+FROM debian:10-slim as dev
 ENV DEBIAN_FRONTEND noninteractive
 
 RUN echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/backports.list
@@ -12,22 +22,67 @@ RUN apt-get update && \
     apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
     golang -t buster-backports
 
-# The arvbox-specific dependencies are
-#  gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less
 RUN apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
-    build-essential ca-certificates git libpam0g-dev \
-    gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less && \
-    apt-get clean
+    build-essential ca-certificates git libpam0g-dev
 
 ENV GOPATH /var/lib/gopath
 
+# the --mount option requires the experimental syntax enabled (enables
+# buildkit) on the first line of this file. This Dockerfile must also be built
+# with the DOCKER_BUILDKIT=1 environment variable set.
+RUN --mount=type=bind,target=/usr/src/arvados \
+    cd /usr/src/arvados && \
+    go mod download && \
+    cd cmd/arvados-server && \
+    go install
+
+###########################################################################################################
+FROM debian:10-slim as demo
+ENV DEBIAN_FRONTEND noninteractive
+
+RUN echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/backports.list
+
+RUN apt-get update && \
+    apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
+    golang -t buster-backports
+
+RUN apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
+    build-essential ca-certificates git libpam0g-dev
+
+ENV GOPATH /var/lib/gopath
+
+ARG arvados_version
+RUN echo arvados_version is git commit $arvados_version
+
 RUN cd /usr/src && \
-    git clone https://git.arvados.org/arvados.git && \
-    cd arvados && \
+    git clone --no-checkout https://git.arvados.org/arvados.git && \
+    git -C arvados checkout ${arvados_version} && \
+    cd /usr/src/arvados && \
     go mod download && \
     cd cmd/arvados-server && \
-    go install && \
-    $GOPATH/bin/arvados-server install -type test
+    go install
+
+###########################################################################################################
+FROM ${BUILDTYPE} as base
+
+###########################################################################################################
+FROM debian:10
+ENV DEBIAN_FRONTEND noninteractive
+
+# The arvbox-specific dependencies are
+#  gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less
+RUN apt-get update && \
+    apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
+    gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less && \
+    apt-get clean
+
+ENV GOPATH /var/lib/gopath
+RUN echo buildtype is $BUILDTYPE
+
+RUN mkdir -p $GOPATH/bin/
+COPY --from=base $GOPATH/bin/arvados-server $GOPATH/bin/arvados-server
+RUN $GOPATH/bin/arvados-server --version
+RUN $GOPATH/bin/arvados-server install -type test
 
 RUN /etc/init.d/postgresql start && \
     su postgres -c 'dropuser arvados' && \
@@ -41,7 +96,9 @@ VOLUME /var/lib/docker
 VOLUME /var/log/nginx
 VOLUME /etc/ssl/private
 
-ADD 8D81803C0EBFCD88.asc /tmp/
+ARG workdir
+
+ADD $workdir/8D81803C0EBFCD88.asc /tmp/
 RUN apt-key add --no-tty /tmp/8D81803C0EBFCD88.asc && \
     rm -f /tmp/8D81803C0EBFCD88.asc
 
@@ -60,16 +117,16 @@ ENV LC_ALL en_US.UTF-8
 ARG arvados_version
 RUN echo arvados_version is git commit $arvados_version
 
-ADD fuse.conf /etc/
+COPY $workdir/fuse.conf /etc/
 
-ADD gitolite.rc \
-    keep-setup.sh common.sh createusers.sh \
-    logger runsu.sh waitforpostgres.sh \
-    yml_override.py api-setup.sh \
-    go-setup.sh devenv.sh cluster-config.sh edit_users.py \
+COPY $workdir/gitolite.rc \
+    $workdir/keep-setup.sh $workdir/common.sh $workdir/createusers.sh \
+    $workdir/logger $workdir/runsu.sh $workdir/waitforpostgres.sh \
+    $workdir/yml_override.py $workdir/api-setup.sh \
+    $workdir/go-setup.sh $workdir/devenv.sh $workdir/cluster-config.sh $workdir/edit_users.py \
     /usr/local/lib/arvbox/
 
-ADD runit /etc/runit
+COPY $workdir/runit /etc/runit
 
 # arvbox mounts a docker volume at $ARVADOS_CONTAINER_PATH, make sure that that
 # doesn't overlap with the directory where `arvados-server install -type test`
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
index 192b2a144..777c71356 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
@@ -8,6 +8,7 @@ ARG composer_version=arvados-fork
 ARG workbench2_version=master
 
 RUN cd /usr/src && \
+    git clone --no-checkout https://git.arvados.org/arvados.git && \
     git -C arvados checkout ${arvados_version} && \
     git -C arvados pull && \
     git clone --no-checkout https://github.com/arvados/composer.git && \
diff --git a/tools/arvbox/lib/arvbox/docker/common.sh b/tools/arvbox/lib/arvbox/docker/common.sh
index 4bfe9dd51..48d356640 100644
--- a/tools/arvbox/lib/arvbox/docker/common.sh
+++ b/tools/arvbox/lib/arvbox/docker/common.sh
@@ -77,6 +77,8 @@ run_bundler() {
     #         flock $GEM_HOME/gems.lock gem install --verbose --no-document bundler --version ${bundleversion}
     #     fi
     # fi
+    # Make sure to put the gem binaries in the right place
+    flock /var/lib/arvados/lib/ruby/gems/2.5.0/gems.lock bundler config bin $GEM_HOME/bin
     if ! flock $GEM_HOME/gems.lock bundler install --verbose --local --no-deployment $frozen "$@" ; then
         flock $GEM_HOME/gems.lock bundler install --verbose --no-deployment $frozen "$@"
     fi

commit 0c9f79dd67d7abce9b533d0dc90693619a9fc6b9
Author: Ward Vandewege <ward at curii.com>
Date:   Wed Sep 23 19:46:21 2020 -0400

    16267: switch to `arvados-server install -type test` for installing
           dependencies.
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/tools/arvbox/bin/arvbox b/tools/arvbox/bin/arvbox
index 122e2bec7..8fd77f1f2 100755
--- a/tools/arvbox/bin/arvbox
+++ b/tools/arvbox/bin/arvbox
@@ -60,6 +60,8 @@ PIPCACHE="$ARVBOX_DATA/pip"
 NPMCACHE="$ARVBOX_DATA/npm"
 GOSTUFF="$ARVBOX_DATA/gopath"
 RLIBS="$ARVBOX_DATA/Rlibs"
+ARVADOS_CONTAINER_PATH="/var/lib/arvados-arvbox"
+GEM_HOME="/var/lib/arvados/lib/ruby/gems/2.5.0"
 
 getip() {
     docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $ARVBOX_CONTAINER
@@ -78,7 +80,7 @@ gethost() {
 }
 
 getclusterid() {
-    docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/api_uuid_prefix
+    docker exec $ARVBOX_CONTAINER cat $ARVADOS_CONTAINER_PATH/api_uuid_prefix
 }
 
 updateconf() {
@@ -96,7 +98,7 @@ EOF
 }
 
 listusers() {
-    docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml $(getclusterid) list
+    docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py $ARVADOS_CONTAINER_PATH/cluster_config.yml $(getclusterid) list
 }
 
 wait_for_arvbox() {
@@ -129,9 +131,9 @@ docker_run_dev() {
            "--volume=$COMPOSER_ROOT:/usr/src/composer:rw" \
            "--volume=$WORKBENCH2_ROOT:/usr/src/workbench2:rw" \
            "--volume=$PG_DATA:/var/lib/postgresql:rw" \
-           "--volume=$VAR_DATA:/var/lib/arvados:rw" \
+           "--volume=$VAR_DATA:$ARVADOS_CONTAINER_PATH:rw" \
            "--volume=$PASSENGER:/var/lib/passenger:rw" \
-           "--volume=$GEMS:/var/lib/gems:rw" \
+           "--volume=$GEMS:$GEM_HOME:rw" \
            "--volume=$PIPCACHE:/var/lib/pip:rw" \
            "--volume=$NPMCACHE:/var/lib/npm:rw" \
            "--volume=$GOSTUFF:/var/lib/gopath:rw" \
@@ -220,7 +222,7 @@ run() {
         fi
 
         if ! (docker ps -a | grep -E "$ARVBOX_CONTAINER-data$" -q) ; then
-            docker create -v /var/lib/postgresql -v /var/lib/arvados --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
+            docker create -v /var/lib/postgresql -v $ARVADOS_CONTAINER_PATH --name $ARVBOX_CONTAINER-data arvados/arvbox-demo /bin/true
         fi
 
         docker run \
@@ -264,11 +266,6 @@ run() {
                        $ARVBOX_CONTAINER \
                        /usr/local/lib/arvbox/runsu.sh \
                        /usr/local/lib/arvbox/waitforpostgres.sh
-
-                docker exec -ti \
-                       $ARVBOX_CONTAINER \
-                       /usr/local/lib/arvbox/runsu.sh \
-                       /var/lib/arvbox/service/api/run-service --only-setup
             fi
 
             interactive=""
@@ -281,12 +278,12 @@ run() {
                    -e COLUMNS=$(tput cols) \
                    -e TERM=$TERM \
                    -e WORKSPACE=/usr/src/arvados \
-                   -e GEM_HOME=/var/lib/gems \
-                   -e CONFIGSRC=/var/lib/arvados/run_tests \
+                   -e GEM_HOME=$GEM_HOME \
+                   -e CONFIGSRC=$ARVADOS_CONTAINER_PATH/run_tests \
                    $ARVBOX_CONTAINER \
                    /usr/local/lib/arvbox/runsu.sh \
                    /usr/src/arvados/build/run-tests.sh \
-                   --temp /var/lib/arvados/test \
+                   --temp $ARVADOS_CONTAINER_PATH/test \
                    $interactive \
                    "$@"
         elif [[ "$CONFIG" = devenv ]] ; then
@@ -299,15 +296,15 @@ run() {
                     --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \
                         arvados/arvbox-dev$TAG
             fi
-                exec docker exec --interactive --tty \
-                     -e LINES=$(tput lines) \
-                     -e COLUMNS=$(tput cols) \
-                     -e TERM=$TERM \
-                     -e "ARVBOX_HOME=$HOME" \
-                     -e "DISPLAY=$DISPLAY" \
-                     --workdir=$PWD \
+            exec docker exec --interactive --tty \
+                 -e LINES=$(tput lines) \
+                 -e COLUMNS=$(tput cols) \
+                 -e TERM=$TERM \
+                 -e "ARVBOX_HOME=$HOME" \
+                 -e "DISPLAY=$DISPLAY" \
+                 --workdir=$PWD \
                  ${ARVBOX_CONTAINER} \
-                     /usr/local/lib/arvbox/devenv.sh "$@"
+                 /usr/local/lib/arvbox/devenv.sh "$@"
         elif [[ "$CONFIG" =~ dev$ ]] ; then
             docker_run_dev \
                    --detach \
@@ -424,7 +421,7 @@ case "$subcmd" in
                -e LINES=$(tput lines) \
                -e COLUMNS=$(tput cols) \
                -e TERM=$TERM \
-               -e GEM_HOME=/var/lib/gems \
+               -e GEM_HOME=$GEM_HOME \
                $ARVBOX_CONTAINER /bin/bash
         ;;
 
@@ -433,14 +430,14 @@ case "$subcmd" in
                -e LINES=$(tput lines) \
                -e COLUMNS=$(tput cols) \
                -e TERM=$TERM \
-               -e GEM_HOME=/var/lib/gems \
+               -e GEM_HOME=$GEM_HOME \
                -u arvbox \
                -w /usr/src/arvados \
                $ARVBOX_CONTAINER /bin/bash --login
         ;;
 
     pipe)
-        exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash -
+        exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=$GEM_HOME /bin/bash -
         ;;
 
     stop)
@@ -587,24 +584,24 @@ case "$subcmd" in
         if test -n "$1" ; then
             CERT="$1"
         fi
-        docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/root-cert.pem > "$CERT"
+        docker exec $ARVBOX_CONTAINER cat $ARVADOS_CONTAINER_PATH/root-cert.pem > "$CERT"
         echo "Certificate copied to $CERT"
         ;;
 
     psql)
-        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados'
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat $ARVADOS_CONTAINER_PATH/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados'
         ;;
 
     checkpoint)
-        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec pg_dump --host=localhost --username=arvados --clean arvados_development > /var/lib/arvados/checkpoint.sql'
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat $ARVADOS_CONTAINER_PATH/api_database_pw) exec pg_dump --host=localhost --username=arvados --clean arvados_development > $ARVADOS_CONTAINER_PATH/checkpoint.sql'
         ;;
 
     restore)
-        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados --quiet --file=/var/lib/arvados/checkpoint.sql'
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat $ARVADOS_CONTAINER_PATH/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados --quiet --file=$ARVADOS_CONTAINER_PATH/checkpoint.sql'
         ;;
 
     hotreset)
-        exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash - <<EOF
+        exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=$GEM_HOME /bin/bash - <<EOF
 sv stop api
 sv stop controller
 sv stop websockets
@@ -615,11 +612,11 @@ cd /usr/src/arvados/services/api
 export DISABLE_DATABASE_ENVIRONMENT_CHECK=1
 export RAILS_ENV=development
 bundle exec rake db:drop
-rm /var/lib/arvados/api_database_setup
-rm /var/lib/arvados/superuser_token
-rm /var/lib/arvados/keep0-uuid
-rm /var/lib/arvados/keep1-uuid
-rm /var/lib/arvados/keepproxy-uuid
+rm $ARVADOS_CONTAINER_PATH/api_database_setup
+rm $ARVADOS_CONTAINER_PATH/superuser_token
+rm $ARVADOS_CONTAINER_PATH/keep0-uuid
+rm $ARVADOS_CONTAINER_PATH/keep1-uuid
+rm $ARVADOS_CONTAINER_PATH/keepproxy-uuid
 sv start api
 sv start controller
 sv start websockets
@@ -630,12 +627,12 @@ EOF
         ;;
 
     adduser)
-        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) add $@
+        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py $ARVADOS_CONTAINER_PATH/cluster_config.yml.override $(getclusterid) add $@
         docker exec $ARVBOX_CONTAINER sv restart controller
         ;;
 
     removeuser)
-        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) remove $@
+        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py $ARVADOS_CONTAINER_PATH/cluster_config.yml.override $(getclusterid) remove $@
         docker exec $ARVBOX_CONTAINER sv restart controller
         ;;
 
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.base b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
index eb52ca5a7..9031de79b 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.base
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
@@ -6,47 +6,36 @@ FROM debian:10
 
 ENV DEBIAN_FRONTEND noninteractive
 
+RUN echo "deb http://deb.debian.org/debian buster-backports main" > /etc/apt/sources.list.d/backports.list
+
 RUN apt-get update && \
     apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
-    postgresql postgresql-contrib git build-essential runit curl libpq-dev \
-    libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev libpam-dev \
-    openssh-server netcat-traditional \
-    graphviz bzip2 less sudo virtualenv \
-    fuse libfuse-dev \
-    pkg-config libattr1-dev \
-    libwww-perl libio-socket-ssl-perl libcrypt-ssleay-perl \
-    libjson-perl nginx gitolite3 lsof libreadline-dev \
-    apt-transport-https ca-certificates python3-yaml \
-    linkchecker python3-virtualenv python3-venv xvfb iceweasel \
-    libgnutls28-dev python3-dev vim cadaver cython gnupg dirmngr \
-    libsecret-1-dev r-base r-cran-testthat libxml2-dev pandoc \
-    python3-setuptools python3-pip default-jdk-headless bsdmainutils net-tools \
-    ruby ruby-dev bundler shellinabox  && \
-    apt-get clean
+    golang -t buster-backports
 
-ENV RUBYVERSION_MINOR 2.5
-ENV RUBYVERSION 2.5.1
-
-# Install Ruby from source
-# RUN cd /tmp && \
-#  curl -f http://cache.ruby-lang.org/pub/ruby/${RUBYVERSION_MINOR}/ruby-${RUBYVERSION}.tar.gz | tar -xzf - && \
-#  cd ruby-${RUBYVERSION} && \
-#  ./configure --disable-install-doc && \
-#  make && \
-#  make install && \
-#  cd /tmp && \
-#  rm -rf ruby-${RUBYVERSION}
+# The arvbox-specific dependencies are
+#  gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less
+RUN apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
+    build-essential ca-certificates git libpam0g-dev \
+    gnupg2 runit python3-pip python3-setuptools python3-yaml shellinabox netcat less && \
+    apt-get clean
 
-ENV GEM_HOME /var/lib/gems
-ENV PATH $PATH:/var/lib/gems/bin
+ENV GOPATH /var/lib/gopath
 
-ENV GOVERSION 1.15.2
+RUN cd /usr/src && \
+    git clone https://git.arvados.org/arvados.git && \
+    cd arvados && \
+    go mod download && \
+    cd cmd/arvados-server && \
+    go install && \
+    $GOPATH/bin/arvados-server install -type test
 
-# Install golang binary
-RUN curl -f http://storage.googleapis.com/golang/go${GOVERSION}.linux-amd64.tar.gz | \
-    tar -C /usr/local -xzf -
+RUN /etc/init.d/postgresql start && \
+    su postgres -c 'dropuser arvados' && \
+    su postgres -c 'createuser -s arvbox' && \
+    /etc/init.d/postgresql stop
 
-ENV PATH ${PATH}:/usr/local/go/bin
+ENV GEM_HOME /var/lib/arvados/lib/ruby/gems/2.5.0
+ENV PATH $PATH:$GEM_HOME/bin
 
 VOLUME /var/lib/docker
 VOLUME /var/log/nginx
@@ -62,35 +51,6 @@ RUN mkdir -p /etc/apt/sources.list.d && \
     apt-get -yq --no-install-recommends install docker-ce=5:19.03.13~3-0~debian-buster && \
     apt-get clean
 
-RUN rm -rf /var/lib/postgresql && mkdir -p /var/lib/postgresql
-
-ENV PJSVERSION=1.9.8
-# bitbucket is the origin, but downloads fail sometimes, so use our own mirror instead.
-#ENV PJSURL=https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-${PJSVERSION}-linux-x86_64.tar.bz2
-ENV PJSURL=http://cache.arvados.org/phantomjs-${PJSVERSION}-linux-x86_64.tar.bz2
-
-RUN set -e && \
- curl -L -f ${PJSURL} | tar -C /usr/local -xjf - && \
- ln -s ../phantomjs-${PJSVERSION}-linux-x86_64/bin/phantomjs /usr/local/bin
-
-ENV GDVERSION=v0.23.0
-ENV GDURL=https://github.com/mozilla/geckodriver/releases/download/$GDVERSION/geckodriver-$GDVERSION-linux64.tar.gz
-RUN set -e && curl -L -f ${GDURL} | tar -C /usr/local/bin -xzf - geckodriver
-
-ENV NODEVERSION v8.15.1
-
-# Install nodejs binary
-RUN curl -L -f https://nodejs.org/dist/${NODEVERSION}/node-${NODEVERSION}-linux-x64.tar.xz | tar -C /usr/local -xJf - && \
-    ln -s ../node-${NODEVERSION}-linux-x64/bin/node ../node-${NODEVERSION}-linux-x64/bin/npm /usr/local/bin
-
-ENV GRADLEVERSION 5.3.1
-
-RUN cd /tmp && \
-    curl -L -O https://services.gradle.org/distributions/gradle-${GRADLEVERSION}-bin.zip && \
-    unzip gradle-${GRADLEVERSION}-bin.zip -d /usr/local && \
-    ln -s ../gradle-${GRADLEVERSION}/bin/gradle /usr/local/bin && \
-    rm gradle-${GRADLEVERSION}-bin.zip
-
 # Set UTF-8 locale
 RUN echo en_US.UTF-8 UTF-8 > /etc/locale.gen && locale-gen
 ENV LANG en_US.UTF-8
@@ -111,6 +71,11 @@ ADD gitolite.rc \
 
 ADD runit /etc/runit
 
+# arvbox mounts a docker volume at $ARVADOS_CONTAINER_PATH, make sure that that
+# doesn't overlap with the directory where `arvados-server install -type test`
+# put everything (/var/lib/arvados)
+ENV ARVADOS_CONTAINER_PATH /var/lib/arvados-arvbox
+
 # Start the supervisor.
 ENV SVDIR /etc/service
 STOPSIGNAL SIGINT
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
index ed728204f..192b2a144 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.demo
@@ -8,7 +8,6 @@ ARG composer_version=arvados-fork
 ARG workbench2_version=master
 
 RUN cd /usr/src && \
-    git clone --no-checkout https://git.arvados.org/arvados.git && \
     git -C arvados checkout ${arvados_version} && \
     git -C arvados pull && \
     git clone --no-checkout https://github.com/arvados/composer.git && \
@@ -19,11 +18,14 @@ RUN cd /usr/src && \
     git -C workbench2 pull && \
     chown -R 1000:1000 /usr/src
 
+# avoid rebuilding arvados-server, it's already been built as part of the base image
+RUN install $GOPATH/bin/arvados-server /usr/local/bin
+
 ADD service/ /var/lib/arvbox/service
 RUN ln -sf /var/lib/arvbox/service /etc
-RUN mkdir -p /var/lib/arvados
-RUN echo "production" > /var/lib/arvados/api_rails_env
-RUN echo "production" > /var/lib/arvados/workbench_rails_env
+RUN mkdir -p $ARVADOS_CONTAINER_PATH
+RUN echo "production" > $ARVADOS_CONTAINER_PATH/api_rails_env
+RUN echo "production" > $ARVADOS_CONTAINER_PATH/workbench_rails_env
 
 RUN /usr/local/lib/arvbox/createusers.sh
 
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.dev b/tools/arvbox/lib/arvbox/docker/Dockerfile.dev
index c7621e387..e9c296a19 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.dev
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.dev
@@ -7,11 +7,11 @@ ARG arvados_version
 
 ADD service/ /var/lib/arvbox/service
 RUN ln -sf /var/lib/arvbox/service /etc
-RUN mkdir -p /var/lib/arvados
-RUN echo "development" > /var/lib/arvados/api_rails_env
-RUN echo "development" > /var/lib/arvados/workbench_rails_env
+RUN mkdir -p $ARVADOS_CONTAINER_PATH
+RUN echo "development" > $ARVADOS_CONTAINER_PATH/api_rails_env
+RUN echo "development" > $ARVADOS_CONTAINER_PATH/workbench_rails_env
 
 RUN mkdir /etc/test-service && \
     ln -sf /var/lib/arvbox/service/postgres /etc/test-service && \
     ln -sf /var/lib/arvbox/service/certificate /etc/test-service
-RUN mkdir /etc/devenv-service
\ No newline at end of file
+RUN mkdir /etc/devenv-service
diff --git a/tools/arvbox/lib/arvbox/docker/api-setup.sh b/tools/arvbox/lib/arvbox/docker/api-setup.sh
index 6a261bf4c..f20278a69 100755
--- a/tools/arvbox/lib/arvbox/docker/api-setup.sh
+++ b/tools/arvbox/lib/arvbox/docker/api-setup.sh
@@ -11,27 +11,27 @@ set -ex -o pipefail
 
 cd /usr/src/arvados/services/api
 
-if test -s /var/lib/arvados/api_rails_env ; then
-  export RAILS_ENV=$(cat /var/lib/arvados/api_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/api_rails_env ; then
+  export RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/api_rails_env)
 else
   export RAILS_ENV=development
 fi
 
 set -u
 
-flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
+flock $ARVADOS_CONTAINER_PATH/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
 
 if test -a /usr/src/arvados/services/api/config/arvados_config.rb ; then
     rm -f config/application.yml config/database.yml
 else
-    uuid_prefix=$(cat /var/lib/arvados/api_uuid_prefix)
-    secret_token=$(cat /var/lib/arvados/api_secret_token)
-    blob_signing_key=$(cat /var/lib/arvados/blob_signing_key)
-    management_token=$(cat /var/lib/arvados/management_token)
-    database_pw=$(cat /var/lib/arvados/api_database_pw)
-    vm_uuid=$(cat /var/lib/arvados/vm-uuid)
+    uuid_prefix=$(cat $ARVADOS_CONTAINER_PATH/api_uuid_prefix)
+    secret_token=$(cat $ARVADOS_CONTAINER_PATH/api_secret_token)
+    blob_signing_key=$(cat $ARVADOS_CONTAINER_PATH/blob_signing_key)
+    management_token=$(cat $ARVADOS_CONTAINER_PATH/management_token)
+    database_pw=$(cat $ARVADOS_CONTAINER_PATH/api_database_pw)
+    vm_uuid=$(cat $ARVADOS_CONTAINER_PATH/vm-uuid)
 
-cat >config/application.yml <<EOF
+    cat >config/application.yml <<EOF
 $RAILS_ENV:
   uuid_prefix: $uuid_prefix
   secret_token: $secret_token
@@ -51,18 +51,18 @@ $RAILS_ENV:
   ManagementToken: $management_token
 EOF
 
-(cd config && /usr/local/lib/arvbox/yml_override.py application.yml)
-sed "s/password:.*/password: $database_pw/" <config/database.yml.example >config/database.yml
+    (cd config && /usr/local/lib/arvbox/yml_override.py application.yml)
+    sed "s/password:.*/password: $database_pw/" <config/database.yml.example >config/database.yml
 fi
 
-if ! test -f /var/lib/arvados/api_database_setup ; then
+if ! test -f $ARVADOS_CONTAINER_PATH/api_database_setup ; then
    bundle exec rake db:setup
-   touch /var/lib/arvados/api_database_setup
+   touch $ARVADOS_CONTAINER_PATH/api_database_setup
 fi
 
-if ! test -s /var/lib/arvados/superuser_token ; then
+if ! test -s $ARVADOS_CONTAINER_PATH/superuser_token ; then
     superuser_tok=$(bundle exec ./script/create_superuser_token.rb)
-    echo "$superuser_tok" > /var/lib/arvados/superuser_token
+    echo "$superuser_tok" > $ARVADOS_CONTAINER_PATH/superuser_token
 fi
 
 rm -rf tmp
diff --git a/tools/arvbox/lib/arvbox/docker/cluster-config.sh b/tools/arvbox/lib/arvbox/docker/cluster-config.sh
index bebf983b6..948eb00a5 100755
--- a/tools/arvbox/lib/arvbox/docker/cluster-config.sh
+++ b/tools/arvbox/lib/arvbox/docker/cluster-config.sh
@@ -6,7 +6,9 @@
 exec 2>&1
 set -ex -o pipefail
 
-if [[ -s /etc/arvados/config.yml ]] && [[ /var/lib/arvados/cluster_config.yml.override -ot /etc/arvados/config.yml ]] ; then
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
+
+if [[ -s /etc/arvados/config.yml ]] && [[ $ARVADOS_CONTAINER_PATH/cluster_config.yml.override -ot /etc/arvados/config.yml ]] ; then
    exit
 fi
 
@@ -14,58 +16,58 @@ fi
 
 set -u
 
-if ! test -s /var/lib/arvados/api_uuid_prefix ; then
-  ruby -e 'puts "x#{rand(2**64).to_s(36)[0,4]}"' > /var/lib/arvados/api_uuid_prefix
+if ! test -s $ARVADOS_CONTAINER_PATH/api_uuid_prefix ; then
+  ruby -e 'puts "x#{rand(2**64).to_s(36)[0,4]}"' > $ARVADOS_CONTAINER_PATH/api_uuid_prefix
 fi
-uuid_prefix=$(cat /var/lib/arvados/api_uuid_prefix)
+uuid_prefix=$(cat $ARVADOS_CONTAINER_PATH/api_uuid_prefix)
 
-if ! test -s /var/lib/arvados/api_secret_token ; then
-    ruby -e 'puts rand(2**400).to_s(36)' > /var/lib/arvados/api_secret_token
+if ! test -s $ARVADOS_CONTAINER_PATH/api_secret_token ; then
+    ruby -e 'puts rand(2**400).to_s(36)' > $ARVADOS_CONTAINER_PATH/api_secret_token
 fi
-secret_token=$(cat /var/lib/arvados/api_secret_token)
+secret_token=$(cat $ARVADOS_CONTAINER_PATH/api_secret_token)
 
-if ! test -s /var/lib/arvados/blob_signing_key ; then
-    ruby -e 'puts rand(2**400).to_s(36)' > /var/lib/arvados/blob_signing_key
+if ! test -s $ARVADOS_CONTAINER_PATH/blob_signing_key ; then
+    ruby -e 'puts rand(2**400).to_s(36)' > $ARVADOS_CONTAINER_PATH/blob_signing_key
 fi
-blob_signing_key=$(cat /var/lib/arvados/blob_signing_key)
+blob_signing_key=$(cat $ARVADOS_CONTAINER_PATH/blob_signing_key)
 
-if ! test -s /var/lib/arvados/management_token ; then
-    ruby -e 'puts rand(2**400).to_s(36)' > /var/lib/arvados/management_token
+if ! test -s $ARVADOS_CONTAINER_PATH/management_token ; then
+    ruby -e 'puts rand(2**400).to_s(36)' > $ARVADOS_CONTAINER_PATH/management_token
 fi
-management_token=$(cat /var/lib/arvados/management_token)
+management_token=$(cat $ARVADOS_CONTAINER_PATH/management_token)
 
-if ! test -s /var/lib/arvados/system_root_token ; then
-    ruby -e 'puts rand(2**400).to_s(36)' > /var/lib/arvados/system_root_token
+if ! test -s $ARVADOS_CONTAINER_PATH/system_root_token ; then
+    ruby -e 'puts rand(2**400).to_s(36)' > $ARVADOS_CONTAINER_PATH/system_root_token
 fi
-system_root_token=$(cat /var/lib/arvados/system_root_token)
+system_root_token=$(cat $ARVADOS_CONTAINER_PATH/system_root_token)
 
-if ! test -s /var/lib/arvados/vm-uuid ; then
-    echo $uuid_prefix-2x53u-$(ruby -e 'puts rand(2**400).to_s(36)[0,15]') > /var/lib/arvados/vm-uuid
+if ! test -s $ARVADOS_CONTAINER_PATH/vm-uuid ; then
+    echo $uuid_prefix-2x53u-$(ruby -e 'puts rand(2**400).to_s(36)[0,15]') > $ARVADOS_CONTAINER_PATH/vm-uuid
 fi
-vm_uuid=$(cat /var/lib/arvados/vm-uuid)
+vm_uuid=$(cat $ARVADOS_CONTAINER_PATH/vm-uuid)
 
-if ! test -f /var/lib/arvados/api_database_pw ; then
-    ruby -e 'puts rand(2**128).to_s(36)' > /var/lib/arvados/api_database_pw
+if ! test -f $ARVADOS_CONTAINER_PATH/api_database_pw ; then
+    ruby -e 'puts rand(2**128).to_s(36)' > $ARVADOS_CONTAINER_PATH/api_database_pw
 fi
-database_pw=$(cat /var/lib/arvados/api_database_pw)
+database_pw=$(cat $ARVADOS_CONTAINER_PATH/api_database_pw)
 
 if ! (psql postgres -c "\du" | grep "^ arvados ") >/dev/null ; then
     psql postgres -c "create user arvados with password '$database_pw'"
 fi
 psql postgres -c "ALTER USER arvados WITH SUPERUSER;"
 
-if ! test -s /var/lib/arvados/workbench_secret_token ; then
-  ruby -e 'puts rand(2**400).to_s(36)' > /var/lib/arvados/workbench_secret_token
+if ! test -s $ARVADOS_CONTAINER_PATH/workbench_secret_token ; then
+  ruby -e 'puts rand(2**400).to_s(36)' > $ARVADOS_CONTAINER_PATH/workbench_secret_token
 fi
-workbench_secret_key_base=$(cat /var/lib/arvados/workbench_secret_token)
+workbench_secret_key_base=$(cat $ARVADOS_CONTAINER_PATH/workbench_secret_token)
 
-if test -s /var/lib/arvados/api_rails_env ; then
-  database_env=$(cat /var/lib/arvados/api_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/api_rails_env ; then
+  database_env=$(cat $ARVADOS_CONTAINER_PATH/api_rails_env)
 else
   database_env=development
 fi
 
-cat >/var/lib/arvados/cluster_config.yml <<EOF
+cat >$ARVADOS_CONTAINER_PATH/cluster_config.yml <<EOF
 Clusters:
   ${uuid_prefix}:
     SystemRootToken: $system_root_token
@@ -143,41 +145,44 @@ Clusters:
       ArvadosDocsite: http://$localip:${services[doc]}/
     Git:
       GitCommand: /usr/share/gitolite3/gitolite-shell
-      GitoliteHome: /var/lib/arvados/git
-      Repositories: /var/lib/arvados/git/repositories
+      GitoliteHome: $ARVADOS_CONTAINER_PATH/git
+      Repositories: $ARVADOS_CONTAINER_PATH/git/repositories
     Volumes:
       ${uuid_prefix}-nyw5e-000000000000000:
         Driver: Directory
         DriverParameters:
-          Root: /var/lib/arvados/keep0
+          Root: $ARVADOS_CONTAINER_PATH/keep0
         AccessViaHosts:
           "http://localhost:${services[keepstore0]}": {}
       ${uuid_prefix}-nyw5e-111111111111111:
         Driver: Directory
         DriverParameters:
-          Root: /var/lib/arvados/keep1
+          Root: $ARVADOS_CONTAINER_PATH/keep1
         AccessViaHosts:
           "http://localhost:${services[keepstore1]}": {}
 EOF
 
-/usr/local/lib/arvbox/yml_override.py /var/lib/arvados/cluster_config.yml
+/usr/local/lib/arvbox/yml_override.py $ARVADOS_CONTAINER_PATH/cluster_config.yml
 
-cp /var/lib/arvados/cluster_config.yml /etc/arvados/config.yml
+cp $ARVADOS_CONTAINER_PATH/cluster_config.yml /etc/arvados/config.yml
 
+# Do not abort if certain optional files don't exist (e.g. cluster_config.yml.override)
+set +e
 chmod og-rw \
-      /var/lib/arvados/cluster_config.yml.override \
-      /var/lib/arvados/cluster_config.yml \
+      $ARVADOS_CONTAINER_PATH/cluster_config.yml.override \
+      $ARVADOS_CONTAINER_PATH/cluster_config.yml \
       /etc/arvados/config.yml \
-      /var/lib/arvados/api_secret_token \
-      /var/lib/arvados/blob_signing_key \
-      /var/lib/arvados/management_token \
-      /var/lib/arvados/system_root_token \
-      /var/lib/arvados/api_database_pw \
-      /var/lib/arvados/workbench_secret_token \
-      /var/lib/arvados/superuser_token \
-
-mkdir -p /var/lib/arvados/run_tests
-cat >/var/lib/arvados/run_tests/config.yml <<EOF
+      $ARVADOS_CONTAINER_PATH/api_secret_token \
+      $ARVADOS_CONTAINER_PATH/blob_signing_key \
+      $ARVADOS_CONTAINER_PATH/management_token \
+      $ARVADOS_CONTAINER_PATH/system_root_token \
+      $ARVADOS_CONTAINER_PATH/api_database_pw \
+      $ARVADOS_CONTAINER_PATH/workbench_secret_token \
+      $ARVADOS_CONTAINER_PATH/superuser_token \
+set -e
+
+mkdir -p $ARVADOS_CONTAINER_PATH/run_tests
+cat >$ARVADOS_CONTAINER_PATH/run_tests/config.yml <<EOF
 Clusters:
   zzzzz:
     PostgreSQL:
diff --git a/tools/arvbox/lib/arvbox/docker/common.sh b/tools/arvbox/lib/arvbox/docker/common.sh
index 185467cf7..4bfe9dd51 100644
--- a/tools/arvbox/lib/arvbox/docker/common.sh
+++ b/tools/arvbox/lib/arvbox/docker/common.sh
@@ -3,12 +3,13 @@
 # SPDX-License-Identifier: AGPL-3.0
 
 export DEBIAN_FRONTEND=noninteractive
-export PATH=${PATH}:/usr/local/go/bin:/var/lib/gems/bin
-export GEM_HOME=/var/lib/gems
+export GEM_HOME=/var/lib/arvados/lib/ruby/gems/2.5.0
+export PATH=${PATH}:/usr/local/go/bin:$GEM_HOME/bin:/var/lib/arvados/bin
 export npm_config_cache=/var/lib/npm
 export npm_config_cache_min=Infinity
 export R_LIBS=/var/lib/Rlibs
 export HOME=$(getent passwd arvbox | cut -d: -f6)
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
 
 defaultdev=$(/sbin/ip route|awk '/default/ { print $5 }')
 dockerip=$(/sbin/ip route | grep default | awk '{ print $3 }')
@@ -19,10 +20,10 @@ else
     localip=$containerip
 fi
 
-root_cert=/var/lib/arvados/root-cert.pem
-root_cert_key=/var/lib/arvados/root-cert.key
-server_cert=/var/lib/arvados/server-cert-${localip}.pem
-server_cert_key=/var/lib/arvados/server-cert-${localip}.key
+root_cert=$ARVADOS_CONTAINER_PATH/root-cert.pem
+root_cert_key=$ARVADOS_CONTAINER_PATH/root-cert.key
+server_cert=$ARVADOS_CONTAINER_PATH/server-cert-${localip}.pem
+server_cert_key=$ARVADOS_CONTAINER_PATH/server-cert-${localip}.key
 
 declare -A services
 services=(
@@ -62,22 +63,22 @@ run_bundler() {
         # The 'gem install bundler line below' is cf.
         # https://bundler.io/blog/2019/05/14/solutions-for-cant-find-gem-bundler-with-executable-bundle.html,
         # until we get bundler 2.7.10/3.0.0 or higher
-        gem install bundler --no-document -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1|tr -d ' ')"
+        flock $GEM_HOME/gems.lock gem install bundler --no-document -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1|tr -d ' ')"
         frozen=--frozen
     else
         frozen=""
     fi
-    # if ! test -x /var/lib/gems/bin/bundler ; then
+    # if ! test -x $GEM_HOME/bin/bundler ; then
     # 	bundleversion=2.0.2
     #     bundlergem=$(ls -r $GEM_HOME/cache/bundler-${bundleversion}.gem 2>/dev/null | head -n1 || true)
     #     if test -n "$bundlergem" ; then
-    #         flock /var/lib/gems/gems.lock gem install --verbose --local --no-document $bundlergem
+    #         flock $GEM_HOME/gems.lock gem install --verbose --local --no-document $bundlergem
     #     else
-    #         flock /var/lib/gems/gems.lock gem install --verbose --no-document bundler --version ${bundleversion}
+    #         flock $GEM_HOME/gems.lock gem install --verbose --no-document bundler --version ${bundleversion}
     #     fi
     # fi
-    if ! flock /var/lib/gems/gems.lock bundler install --verbose --local --no-deployment $frozen "$@" ; then
-        flock /var/lib/gems/gems.lock bundler install --verbose --no-deployment $frozen "$@"
+    if ! flock $GEM_HOME/gems.lock bundler install --verbose --local --no-deployment $frozen "$@" ; then
+        flock $GEM_HOME/gems.lock bundler install --verbose --no-deployment $frozen "$@"
     fi
 }
 
diff --git a/tools/arvbox/lib/arvbox/docker/createusers.sh b/tools/arvbox/lib/arvbox/docker/createusers.sh
index de1e7bba9..cea23bc81 100755
--- a/tools/arvbox/lib/arvbox/docker/createusers.sh
+++ b/tools/arvbox/lib/arvbox/docker/createusers.sh
@@ -5,16 +5,19 @@
 
 set -e -o pipefail
 
+export GEM_HOME=/var/lib/arvados/lib/ruby/gems/2.5.0
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
+
 if ! grep "^arvbox:" /etc/passwd >/dev/null 2>/dev/null ; then
     HOSTUID=$(ls -nd /usr/src/arvados | sed 's/ */ /' | cut -d' ' -f4)
     HOSTGID=$(ls -nd /usr/src/arvados | sed 's/ */ /' | cut -d' ' -f5)
 
-    mkdir -p /var/lib/arvados/git /var/lib/gems \
+    mkdir -p $ARVADOS_CONTAINER_PATH/git $GEM_HOME \
           /var/lib/passenger /var/lib/gopath \
           /var/lib/pip /var/lib/npm
 
     if test -z "$ARVBOX_HOME" ; then
-	ARVBOX_HOME=/var/lib/arvados
+        ARVBOX_HOME=$ARVADOS_CONTAINER_PATH
     fi
 
     groupadd --gid $HOSTGID --non-unique arvbox
@@ -25,27 +28,25 @@ if ! grep "^arvbox:" /etc/passwd >/dev/null 2>/dev/null ; then
             --groups docker \
             --shell /bin/bash \
             arvbox
-    useradd --home-dir /var/lib/arvados/git --uid $HOSTUID --gid $HOSTGID --non-unique git
+    useradd --home-dir $ARVADOS_CONTAINER_PATH/git --uid $HOSTUID --gid $HOSTGID --non-unique git
     useradd --groups docker crunch
 
     if [[ "$1" != --no-chown ]] ; then
-	chown arvbox:arvbox -R /usr/local /var/lib/arvados /var/lib/gems \
+        chown arvbox:arvbox -R /usr/local $ARVADOS_CONTAINER_PATH $GEM_HOME \
               /var/lib/passenger /var/lib/postgresql \
               /var/lib/nginx /var/log/nginx /etc/ssl/private \
-              /var/lib/gopath /var/lib/pip /var/lib/npm
+              /var/lib/gopath /var/lib/pip /var/lib/npm \
+              /var/lib/arvados
     fi
 
-    mkdir -p /var/lib/gems/ruby
-    chown arvbox:arvbox -R /var/lib/gems/ruby
-
     mkdir -p /tmp/crunch0 /tmp/crunch1
     chown crunch:crunch -R /tmp/crunch0 /tmp/crunch1
 
     echo "arvbox    ALL=(crunch) NOPASSWD: ALL" >> /etc/sudoers
 
     cat <<EOF > /etc/profile.d/paths.sh
-export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/go/bin:/var/lib/gems/bin:$(ls -d /usr/local/node-*)/bin
-export GEM_HOME=/var/lib/gems
+export PATH=/usr/local/bin:/usr/bin:/bin:$GEM_HOME/bin
+export GEM_HOME=/var/lib/arvados/lib/ruby/gems/2.5.0
 export npm_config_cache=/var/lib/npm
 export npm_config_cache_min=Infinity
 export R_LIBS=/var/lib/Rlibs
diff --git a/tools/arvbox/lib/arvbox/docker/devenv.sh b/tools/arvbox/lib/arvbox/docker/devenv.sh
index 4df5463f1..b5c57f39f 100755
--- a/tools/arvbox/lib/arvbox/docker/devenv.sh
+++ b/tools/arvbox/lib/arvbox/docker/devenv.sh
@@ -3,7 +3,8 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-flock /var/lib/arvados/createusers.lock /usr/local/lib/arvbox/createusers.sh --no-chown
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
+flock $ARVADOS_CONTAINER_PATH/createusers.lock /usr/local/lib/arvbox/createusers.sh --no-chown
 
 if [[ -n "$*" ]] ; then
     exec su --preserve-environment arvbox -c "$*"
diff --git a/tools/arvbox/lib/arvbox/docker/go-setup.sh b/tools/arvbox/lib/arvbox/docker/go-setup.sh
index 9bee91044..21be0ccd6 100644
--- a/tools/arvbox/lib/arvbox/docker/go-setup.sh
+++ b/tools/arvbox/lib/arvbox/docker/go-setup.sh
@@ -8,10 +8,14 @@ mkdir -p $GOPATH
 
 cd /usr/src/arvados
 if [[ $UID = 0 ]] ; then
-    /usr/local/lib/arvbox/runsu.sh flock /var/lib/gopath/gopath.lock go mod download
+  /usr/local/lib/arvbox/runsu.sh flock /var/lib/gopath/gopath.lock go mod download
+  if [[ ! -f /usr/local/bin/arvados-server ]]; then
     /usr/local/lib/arvbox/runsu.sh flock /var/lib/gopath/gopath.lock go install git.arvados.org/arvados.git/cmd/arvados-server
+  fi
 else
-    flock /var/lib/gopath/gopath.lock go mod download
+  flock /var/lib/gopath/gopath.lock go mod download
+  if [[ ! -f /usr/local/bin/arvados-server ]]; then
     flock /var/lib/gopath/gopath.lock go install git.arvados.org/arvados.git/cmd/arvados-server
+  fi
 fi
 install $GOPATH/bin/arvados-server /usr/local/bin
diff --git a/tools/arvbox/lib/arvbox/docker/keep-setup.sh b/tools/arvbox/lib/arvbox/docker/keep-setup.sh
index 3bc3899b0..657a9a260 100755
--- a/tools/arvbox/lib/arvbox/docker/keep-setup.sh
+++ b/tools/arvbox/lib/arvbox/docker/keep-setup.sh
@@ -17,11 +17,11 @@ if test "$1" = "--only-deps" ; then
     exit
 fi
 
-mkdir -p /var/lib/arvados/$1
+mkdir -p $ARVADOS_CONTAINER_PATH/$1
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
 
 set +e
 read -rd $'\000' keepservice <<EOF
@@ -34,25 +34,25 @@ read -rd $'\000' keepservice <<EOF
 EOF
 set -e
 
-if test -s /var/lib/arvados/$1-uuid ; then
-    keep_uuid=$(cat /var/lib/arvados/$1-uuid)
+if test -s $ARVADOS_CONTAINER_PATH/$1-uuid ; then
+    keep_uuid=$(cat $ARVADOS_CONTAINER_PATH/$1-uuid)
     arv keep_service update --uuid $keep_uuid --keep-service "$keepservice"
 else
     UUID=$(arv --format=uuid keep_service create --keep-service "$keepservice")
-    echo $UUID > /var/lib/arvados/$1-uuid
+    echo $UUID > $ARVADOS_CONTAINER_PATH/$1-uuid
 fi
 
-management_token=$(cat /var/lib/arvados/management_token)
+management_token=$(cat $ARVADOS_CONTAINER_PATH/management_token)
 
 set +e
 sv hup /var/lib/arvbox/service/keepproxy
 
-cat >/var/lib/arvados/$1.yml <<EOF
+cat >$ARVADOS_CONTAINER_PATH/$1.yml <<EOF
 Listen: "localhost:$2"
-BlobSigningKeyFile: /var/lib/arvados/blob_signing_key
-SystemAuthTokenFile: /var/lib/arvados/superuser_token
+BlobSigningKeyFile: $ARVADOS_CONTAINER_PATH/blob_signing_key
+SystemAuthTokenFile: $ARVADOS_CONTAINER_PATH/superuser_token
 ManagementToken: $management_token
 MaxBuffers: 20
 EOF
 
-exec /usr/local/bin/keepstore -config=/var/lib/arvados/$1.yml
+exec /usr/local/bin/keepstore -config=$ARVADOS_CONTAINER_PATH/$1.yml
diff --git a/tools/arvbox/lib/arvbox/docker/runit/2 b/tools/arvbox/lib/arvbox/docker/runit/2
index 5812f3d8b..eccf62553 100755
--- a/tools/arvbox/lib/arvbox/docker/runit/2
+++ b/tools/arvbox/lib/arvbox/docker/runit/2
@@ -3,7 +3,7 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin
+PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin
 
 echo
 echo "Arvados-in-a-box starting"
diff --git a/tools/arvbox/lib/arvbox/docker/runsu.sh b/tools/arvbox/lib/arvbox/docker/runsu.sh
index 88d832f0e..674b15775 100755
--- a/tools/arvbox/lib/arvbox/docker/runsu.sh
+++ b/tools/arvbox/lib/arvbox/docker/runsu.sh
@@ -6,9 +6,11 @@
 HOSTUID=$(ls -nd /usr/src/arvados | sed 's/ */ /' | cut -d' ' -f4)
 HOSTGID=$(ls -nd /usr/src/arvados | sed 's/ */ /' | cut -d' ' -f5)
 
-flock /var/lib/arvados/createusers.lock /usr/local/lib/arvbox/createusers.sh
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
 
-export HOME=/var/lib/arvados
+flock $ARVADOS_CONTAINER_PATH/createusers.lock /usr/local/lib/arvbox/createusers.sh
+
+export HOME=$ARVADOS_CONTAINER_PATH
 
 chown arvbox /dev/stderr
 
diff --git a/tools/arvbox/lib/arvbox/docker/service/api/run-service b/tools/arvbox/lib/arvbox/docker/service/api/run-service
index f052b5d63..7df7b2820 100755
--- a/tools/arvbox/lib/arvbox/docker/service/api/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/api/run-service
@@ -10,8 +10,8 @@ set -ex -o pipefail
 
 cd /usr/src/arvados/services/api
 
-if test -s /var/lib/arvados/api_rails_env ; then
-  export RAILS_ENV=$(cat /var/lib/arvados/api_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/api_rails_env ; then
+  export RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/api_rails_env)
 else
   export RAILS_ENV=development
 fi
@@ -24,7 +24,7 @@ if test "$1" = "--only-deps" ; then
     exit
 fi
 
-flock /var/lib/arvados/api.lock /usr/local/lib/arvbox/api-setup.sh
+flock $ARVADOS_CONTAINER_PATH/api.lock /usr/local/lib/arvbox/api-setup.sh
 
 set +u
 if test "$1" = "--only-setup" ; then
diff --git a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service
index 5f71e5ab2..b369ff622 100755
--- a/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/arv-git-httpd/run-service
@@ -18,7 +18,7 @@ fi
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export PATH="$PATH:/var/lib/arvados/git/bin"
+export PATH="$PATH:$ARVADOS_CONTAINER_PATH/git/bin"
 cd ~git
 
 exec /usr/local/bin/arv-git-httpd
diff --git a/tools/arvbox/lib/arvbox/docker/service/certificate/run b/tools/arvbox/lib/arvbox/docker/service/certificate/run
index 6443b0179..2536981a7 100755
--- a/tools/arvbox/lib/arvbox/docker/service/certificate/run
+++ b/tools/arvbox/lib/arvbox/docker/service/certificate/run
@@ -8,9 +8,9 @@ set -ex -o pipefail
 
 . /usr/local/lib/arvbox/common.sh
 
-/usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
+/usr/local/lib/arvbox/runsu.sh flock $ARVADOS_CONTAINER_PATH/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
 
-uuid_prefix=$(cat /var/lib/arvados/api_uuid_prefix)
+uuid_prefix=$(cat $ARVADOS_CONTAINER_PATH/api_uuid_prefix)
 
 if ! openssl verify -CAfile $root_cert $root_cert ; then
     # req           signing request sub-command
@@ -74,13 +74,13 @@ if ! openssl verify -CAfile $root_cert $server_cert ; then
 	    -extensions x509_ext \
 	    -config <(cat /etc/ssl/openssl.cnf \
 			  <(printf "\n[x509_ext]\nkeyUsage=critical,digitalSignature,keyEncipherment\nsubjectAltName=DNS:localhost,$san")) \
-            -out /var/lib/arvados/server-cert-${localip}.csr \
+            -out $ARVADOS_CONTAINER_PATH/server-cert-${localip}.csr \
             -keyout $server_cert_key \
             -days 365
 
     openssl x509 \
 	    -req \
-	    -in /var/lib/arvados/server-cert-${localip}.csr \
+	    -in $ARVADOS_CONTAINER_PATH/server-cert-${localip}.csr \
 	    -CA $root_cert \
 	    -CAkey $root_cert_key \
 	    -out $server_cert \
diff --git a/tools/arvbox/lib/arvbox/docker/service/controller/run b/tools/arvbox/lib/arvbox/docker/service/controller/run
index 588e9d2da..e495e222e 100755
--- a/tools/arvbox/lib/arvbox/docker/service/controller/run
+++ b/tools/arvbox/lib/arvbox/docker/service/controller/run
@@ -15,6 +15,6 @@ if test "$1" = "--only-deps" ; then
     exit
 fi
 
-/usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
+/usr/local/lib/arvbox/runsu.sh flock $ARVADOS_CONTAINER_PATH/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
 
 exec /usr/local/bin/arvados-controller
diff --git a/tools/arvbox/lib/arvbox/docker/service/crunch-dispatch-local/run-service b/tools/arvbox/lib/arvbox/docker/service/crunch-dispatch-local/run-service
index 6e80d30ab..821afdce5 100755
--- a/tools/arvbox/lib/arvbox/docker/service/crunch-dispatch-local/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/crunch-dispatch-local/run-service
@@ -25,6 +25,6 @@ chmod +x /usr/local/bin/crunch-run.sh
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
 
 exec /usr/local/bin/crunch-dispatch-local -crunch-run-command=/usr/local/bin/crunch-run.sh -poll-interval=1
diff --git a/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service b/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service
index 6055efc47..e91386b67 100755
--- a/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/gitolite/run-service
@@ -8,16 +8,16 @@ set -eux -o pipefail
 
 . /usr/local/lib/arvbox/common.sh
 
-mkdir -p /var/lib/arvados/git
+mkdir -p $ARVADOS_CONTAINER_PATH/git
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
 
 export USER=git
 export USERNAME=git
 export LOGNAME=git
-export HOME=/var/lib/arvados/git
+export HOME=$ARVADOS_CONTAINER_PATH/git
 
 cd ~arvbox
 
@@ -33,7 +33,7 @@ if test -s ~arvbox/.ssh/known_hosts ; then
     ssh-keygen -f ".ssh/known_hosts" -R localhost
 fi
 
-if ! test -f /var/lib/arvados/gitolite-setup ; then
+if ! test -f $ARVADOS_CONTAINER_PATH/gitolite-setup ; then
     cd ~git
 
     # Do a no-op login to populate known_hosts
@@ -57,7 +57,7 @@ if ! test -f /var/lib/arvados/gitolite-setup ; then
     git config push.default simple
     git push
 
-    touch /var/lib/arvados/gitolite-setup
+    touch $ARVADOS_CONTAINER_PATH/gitolite-setup
 else
     # Do a no-op login to populate known_hosts
     # with the hostkey, so it won't try to ask
@@ -68,14 +68,14 @@ fi
 
 prefix=$(arv --format=uuid user current | cut -d- -f1)
 
-if ! test -s /var/lib/arvados/arvados-git-uuid ; then
+if ! test -s $ARVADOS_CONTAINER_PATH/arvados-git-uuid ; then
     repo_uuid=$(arv --format=uuid repository create --repository "{\"owner_uuid\":\"$prefix-tpzed-000000000000000\", \"name\":\"arvados\"}")
-    echo $repo_uuid > /var/lib/arvados/arvados-git-uuid
+    echo $repo_uuid > $ARVADOS_CONTAINER_PATH/arvados-git-uuid
 fi
 
-repo_uuid=$(cat /var/lib/arvados/arvados-git-uuid)
+repo_uuid=$(cat $ARVADOS_CONTAINER_PATH/arvados-git-uuid)
 
-if ! test -s /var/lib/arvados/arvados-git-link-uuid ; then
+if ! test -s $ARVADOS_CONTAINER_PATH/arvados-git-link-uuid ; then
     all_users_group_uuid="$prefix-j7d0g-fffffffffffffff"
 
     set +e
@@ -89,19 +89,19 @@ if ! test -s /var/lib/arvados/arvados-git-link-uuid ; then
 EOF
     set -e
     link_uuid=$(arv --format=uuid link create --link "$newlink")
-    echo $link_uuid > /var/lib/arvados/arvados-git-link-uuid
+    echo $link_uuid > $ARVADOS_CONTAINER_PATH/arvados-git-link-uuid
 fi
 
-if ! test -d /var/lib/arvados/git/repositories/$repo_uuid.git ; then
-    git clone --bare /usr/src/arvados /var/lib/arvados/git/repositories/$repo_uuid.git
+if ! test -d $ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git ; then
+    git clone --bare /usr/src/arvados $ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git
 else
-    git --git-dir=/var/lib/arvados/git/repositories/$repo_uuid.git fetch -f /usr/src/arvados master:master
+    git --git-dir=$ARVADOS_CONTAINER_PATH/git/repositories/$repo_uuid.git fetch -f /usr/src/arvados master:master
 fi
 
 cd /usr/src/arvados/services/api
 
-if test -s /var/lib/arvados/api_rails_env ; then
-  RAILS_ENV=$(cat /var/lib/arvados/api_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/api_rails_env ; then
+  RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/api_rails_env)
 else
   RAILS_ENV=development
 fi
@@ -110,8 +110,8 @@ git_user_key=$(cat ~git/.ssh/id_rsa.pub)
 
 cat > config/arvados-clients.yml <<EOF
 $RAILS_ENV:
-  gitolite_url: /var/lib/arvados/git/repositories/gitolite-admin.git
-  gitolite_tmp: /var/lib/arvados/git
+  gitolite_url: $ARVADOS_CONTAINER_PATH/git/repositories/gitolite-admin.git
+  gitolite_tmp: $ARVADOS_CONTAINER_PATH/git
   arvados_api_host: $localip:${services[controller-ssl]}
   arvados_api_token: "$ARVADOS_API_TOKEN"
   arvados_api_host_insecure: false
diff --git a/tools/arvbox/lib/arvbox/docker/service/keepproxy/run-service b/tools/arvbox/lib/arvbox/docker/service/keepproxy/run-service
index d093fbc88..cf5ccd724 100755
--- a/tools/arvbox/lib/arvbox/docker/service/keepproxy/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/keepproxy/run-service
@@ -19,7 +19,7 @@ fi
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
 
 set +e
 read -rd $'\000' keepservice <<EOF
@@ -32,12 +32,12 @@ read -rd $'\000' keepservice <<EOF
 EOF
 set -e
 
-if test -s /var/lib/arvados/keepproxy-uuid ; then
-    keep_uuid=$(cat /var/lib/arvados/keepproxy-uuid)
+if test -s $ARVADOS_CONTAINER_PATH/keepproxy-uuid ; then
+    keep_uuid=$(cat $ARVADOS_CONTAINER_PATH/keepproxy-uuid)
     arv keep_service update --uuid $keep_uuid --keep-service "$keepservice"
 else
     UUID=$(arv --format=uuid keep_service create --keep-service "$keepservice")
-    echo $UUID > /var/lib/arvados/keepproxy-uuid
+    echo $UUID > $ARVADOS_CONTAINER_PATH/keepproxy-uuid
 fi
 
 exec /usr/local/bin/keepproxy
diff --git a/tools/arvbox/lib/arvbox/docker/service/nginx/run b/tools/arvbox/lib/arvbox/docker/service/nginx/run
index cfb7788de..82db92137 100755
--- a/tools/arvbox/lib/arvbox/docker/service/nginx/run
+++ b/tools/arvbox/lib/arvbox/docker/service/nginx/run
@@ -21,9 +21,9 @@ fi
 
 openssl verify -CAfile $root_cert $server_cert
 
-cat <<EOF >/var/lib/arvados/nginx.conf
+cat <<EOF >$ARVADOS_CONTAINER_PATH/nginx.conf
 worker_processes auto;
-pid /var/lib/arvados/nginx.pid;
+pid $ARVADOS_CONTAINER_PATH/nginx.pid;
 
 error_log stderr;
 daemon off;
@@ -235,4 +235,4 @@ server {
 
 EOF
 
-exec nginx -c /var/lib/arvados/nginx.conf
+exec nginx -c $ARVADOS_CONTAINER_PATH/nginx.conf
diff --git a/tools/arvbox/lib/arvbox/docker/service/postgres/run b/tools/arvbox/lib/arvbox/docker/service/postgres/run
index 3ef78ee45..d8abc4d89 100755
--- a/tools/arvbox/lib/arvbox/docker/service/postgres/run
+++ b/tools/arvbox/lib/arvbox/docker/service/postgres/run
@@ -3,7 +3,8 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-flock /var/lib/arvados/createusers.lock /usr/local/lib/arvbox/createusers.sh
+export ARVADOS_CONTAINER_PATH=/var/lib/arvados-arvbox
+flock $ARVADOS_CONTAINER_PATH/createusers.lock /usr/local/lib/arvbox/createusers.sh
 
 make-ssl-cert generate-default-snakeoil --force-overwrite
 
diff --git a/tools/arvbox/lib/arvbox/docker/service/postgres/run-service b/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
index f2377a0c2..3569fd312 100755
--- a/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
@@ -10,7 +10,6 @@ PGVERSION=11
 
 if ! test -d /var/lib/postgresql/$PGVERSION/main ; then
     /usr/lib/postgresql/$PGVERSION/bin/initdb --locale=en_US.UTF-8 -D /var/lib/postgresql/$PGVERSION/main
-    sh -c "while ! (psql postgres -c'\du' | grep '^ arvbox ') >/dev/null ; do createuser -s arvbox ; sleep 1 ; done" &
 fi
 mkdir -p /var/run/postgresql/$PGVERSION-main.pg_stat_tmp
 
diff --git a/tools/arvbox/lib/arvbox/docker/service/ready/run-service b/tools/arvbox/lib/arvbox/docker/service/ready/run-service
index 21cb7d48c..b29dafed7 100755
--- a/tools/arvbox/lib/arvbox/docker/service/ready/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/ready/run-service
@@ -49,9 +49,9 @@ export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
 
 vm_ok=0
-if test -s /var/lib/arvados/vm-uuid -a -s /var/lib/arvados/superuser_token; then
-    vm_uuid=$(cat /var/lib/arvados/vm-uuid)
-    export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+if test -s $ARVADOS_CONTAINER_PATH/vm-uuid -a -s $ARVADOS_CONTAINER_PATH/superuser_token; then
+    vm_uuid=$(cat $ARVADOS_CONTAINER_PATH/vm-uuid)
+    export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
     if (which arv && arv virtual_machine get --uuid $vm_uuid) >/dev/null 2>/dev/null ; then
         vm_ok=1
     fi
@@ -63,7 +63,7 @@ fi
 
 if ! [[ -z "$waiting" ]] ; then
     if ps x | grep -v grep | grep "bundle install" > /dev/null; then
-        gemcount=$(ls /var/lib/gems/ruby/2.1.0/gems 2>/dev/null | wc -l)
+        gemcount=$(ls $GEM_HOME/gems 2>/dev/null | wc -l)
 
         gemlockcount=0
         for l in /usr/src/arvados/services/api/Gemfile.lock \
diff --git a/tools/arvbox/lib/arvbox/docker/service/vm/run b/tools/arvbox/lib/arvbox/docker/service/vm/run
index ee210e35d..4ea11aadc 100755
--- a/tools/arvbox/lib/arvbox/docker/service/vm/run
+++ b/tools/arvbox/lib/arvbox/docker/service/vm/run
@@ -16,8 +16,8 @@ cd /usr/src/arvados/services/login-sync
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
-export ARVADOS_VIRTUAL_MACHINE_UUID=$(cat /var/lib/arvados/vm-uuid)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
+export ARVADOS_VIRTUAL_MACHINE_UUID=$(cat $ARVADOS_CONTAINER_PATH/vm-uuid)
 
 while true ; do
       arvados-login-sync
diff --git a/tools/arvbox/lib/arvbox/docker/service/vm/run-service b/tools/arvbox/lib/arvbox/docker/service/vm/run-service
index 932ba5981..5369af31d 100755
--- a/tools/arvbox/lib/arvbox/docker/service/vm/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/vm/run-service
@@ -21,8 +21,8 @@ set -u
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
 export ARVADOS_API_HOST_INSECURE=1
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
-export ARVADOS_VIRTUAL_MACHINE_UUID=$(cat /var/lib/arvados/vm-uuid)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
+export ARVADOS_VIRTUAL_MACHINE_UUID=$(cat $ARVADOS_CONTAINER_PATH/vm-uuid)
 
 set +e
 read -rd $'\000' vm <<EOF
diff --git a/tools/arvbox/lib/arvbox/docker/service/websockets/run b/tools/arvbox/lib/arvbox/docker/service/websockets/run
index efa2e08a7..f962c3e8f 100755
--- a/tools/arvbox/lib/arvbox/docker/service/websockets/run
+++ b/tools/arvbox/lib/arvbox/docker/service/websockets/run
@@ -15,6 +15,6 @@ if test "$1" = "--only-deps" ; then
     exit
 fi
 
-/usr/local/lib/arvbox/runsu.sh flock /var/lib/arvados/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
+/usr/local/lib/arvbox/runsu.sh flock $ARVADOS_CONTAINER_PATH/cluster_config.yml.lock /usr/local/lib/arvbox/cluster-config.sh
 
 exec /usr/local/lib/arvbox/runsu.sh /usr/local/bin/arvados-ws
diff --git a/tools/arvbox/lib/arvbox/docker/service/workbench/run b/tools/arvbox/lib/arvbox/docker/service/workbench/run
index e16349378..b8a28fa76 100755
--- a/tools/arvbox/lib/arvbox/docker/service/workbench/run
+++ b/tools/arvbox/lib/arvbox/docker/service/workbench/run
@@ -15,8 +15,8 @@ rm -rf tmp
 mkdir tmp
 chown arvbox:arvbox tmp
 
-if test -s /var/lib/arvados/workbench_rails_env ; then
-  export RAILS_ENV=$(cat /var/lib/arvados/workbench_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/workbench_rails_env ; then
+  export RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/workbench_rails_env)
 else
   export RAILS_ENV=development
 fi
@@ -24,7 +24,7 @@ fi
 if test "$1" != "--only-deps" ; then
     openssl verify -CAfile $root_cert $server_cert
     exec bundle exec passenger start --port=${services[workbench]} \
-	 --ssl --ssl-certificate=/var/lib/arvados/server-cert-${localip}.pem \
-	 --ssl-certificate-key=/var/lib/arvados/server-cert-${localip}.key \
+	 --ssl --ssl-certificate=$ARVADOS_CONTAINER_PATH/server-cert-${localip}.pem \
+	 --ssl-certificate-key=$ARVADOS_CONTAINER_PATH/server-cert-${localip}.key \
          --user arvbox
 fi
diff --git a/tools/arvbox/lib/arvbox/docker/service/workbench/run-service b/tools/arvbox/lib/arvbox/docker/service/workbench/run-service
index 06742cf82..51b9420ee 100755
--- a/tools/arvbox/lib/arvbox/docker/service/workbench/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/workbench/run-service
@@ -10,8 +10,8 @@ set -ex -o pipefail
 
 cd /usr/src/arvados/apps/workbench
 
-if test -s /var/lib/arvados/workbench_rails_env ; then
-  export RAILS_ENV=$(cat /var/lib/arvados/workbench_rails_env)
+if test -s $ARVADOS_CONTAINER_PATH/workbench_rails_env ; then
+  export RAILS_ENV=$(cat $ARVADOS_CONTAINER_PATH/workbench_rails_env)
 else
   export RAILS_ENV=development
 fi
@@ -35,7 +35,7 @@ fi
 
 set -u
 
-secret_token=$(cat /var/lib/arvados/workbench_secret_token)
+secret_token=$(cat $ARVADOS_CONTAINER_PATH/workbench_secret_token)
 
 if test -a /usr/src/arvados/apps/workbench/config/arvados_config.rb ; then
     rm -f config/application.yml
diff --git a/tools/arvbox/lib/arvbox/docker/service/workbench2/run-service b/tools/arvbox/lib/arvbox/docker/service/workbench2/run-service
index e3fbd22c4..8c3c49efd 100755
--- a/tools/arvbox/lib/arvbox/docker/service/workbench2/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/workbench2/run-service
@@ -27,7 +27,7 @@ cat <<EOF > /usr/src/workbench2/public/config.json
 EOF
 
 export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
-export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+export ARVADOS_API_TOKEN=$(cat $ARVADOS_CONTAINER_PATH/superuser_token)
 
 url_prefix="https://$localip:${services[workbench2-ssl]}/"
 
diff --git a/tools/arvbox/lib/arvbox/docker/waitforpostgres.sh b/tools/arvbox/lib/arvbox/docker/waitforpostgres.sh
index 6bda618ab..9b2eb69f9 100755
--- a/tools/arvbox/lib/arvbox/docker/waitforpostgres.sh
+++ b/tools/arvbox/lib/arvbox/docker/waitforpostgres.sh
@@ -9,6 +9,6 @@ while ! psql postgres -c\\du >/dev/null 2>/dev/null ; do
     sleep 1
 done
 
-while ! test -s /var/lib/arvados/server-cert-${localip}.pem ; do
+while ! test -s $ARVADOS_CONTAINER_PATH/server-cert-${localip}.pem ; do
     sleep 1
 done

commit cfb21c7d76b0961afb920a1c4ec0b2d29f1b21d3
Author: Ward Vandewege <ward at curii.com>
Date:   Fri Sep 18 17:06:41 2020 -0400

    16831: arvbox: bugfix: fix bundler version issue in documentation.
           Upgrade images to Debian Buster. Clean up whitespace in the
           arvbox command.
    
    Arvados-DCO-1.1-Signed-off-by: Ward Vandewege <ward at curii.com>

diff --git a/tools/arvbox/bin/arvbox b/tools/arvbox/bin/arvbox
index 279d46c08..122e2bec7 100755
--- a/tools/arvbox/bin/arvbox
+++ b/tools/arvbox/bin/arvbox
@@ -107,11 +107,11 @@ wait_for_arvbox() {
     while read line ; do
         if [[ $line =~ "ok: down: ready:" ]] ; then
             kill $LOGPID
-	    set +e
-	    wait $LOGPID 2>/dev/null
-	    set -e
-	else
-	    echo $line
+            set +e
+            wait $LOGPID 2>/dev/null
+            set -e
+        else
+            echo $line
         fi
     done < $FF
     rm $FF
@@ -125,7 +125,7 @@ wait_for_arvbox() {
 
 docker_run_dev() {
     docker run \
-	   "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
+           "--volume=$ARVADOS_ROOT:/usr/src/arvados:rw" \
            "--volume=$COMPOSER_ROOT:/usr/src/composer:rw" \
            "--volume=$WORKBENCH2_ROOT:/usr/src/workbench2:rw" \
            "--volume=$PG_DATA:/var/lib/postgresql:rw" \
@@ -136,8 +136,8 @@ docker_run_dev() {
            "--volume=$NPMCACHE:/var/lib/npm:rw" \
            "--volume=$GOSTUFF:/var/lib/gopath:rw" \
            "--volume=$RLIBS:/var/lib/Rlibs:rw" \
-	   --label "org.arvados.arvbox_config=$CONFIG" \
-	   "$@"
+           --label "org.arvados.arvbox_config=$CONFIG" \
+           "$@"
 }
 
 running_config() {
@@ -153,10 +153,10 @@ run() {
     need_setup=1
 
     if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
-	if [[ $(running_config) != "$CONFIG" ]] ; then
-	    echo "Container $ARVBOX_CONTAINER is '$(running_config)' config but requested '$CONFIG'; use restart or reboot"
-	    return 1
-	fi
+        if [[ $(running_config) != "$CONFIG" ]] ; then
+            echo "Container $ARVBOX_CONTAINER is '$(running_config)' config but requested '$CONFIG'; use restart or reboot"
+            return 1
+        fi
         if test "$CONFIG" = test -o "$CONFIG" = devenv ; then
             need_setup=0
         else
@@ -175,12 +175,12 @@ run() {
     if test -n "$TAG"
     then
         if test $(echo $TAG | cut -c1-1) != '-' ; then
-	    TAG=":$TAG"
+            TAG=":$TAG"
             shift
         else
-	    if [[ $TAG = '-' ]] ; then
-		shift
-	    fi
+            if [[ $TAG = '-' ]] ; then
+                shift
+            fi
             unset TAG
         fi
     fi
@@ -192,7 +192,7 @@ run() {
             defaultdev=$(/sbin/ip route|awk '/default/ { print $5 }')
             localip=$(ip addr show $defaultdev | grep 'inet ' | sed 's/ *inet \(.*\)\/.*/\1/')
         fi
-	echo "Public arvbox will use address $localip"
+        echo "Public arvbox will use address $localip"
         iptemp=$(mktemp)
         echo $localip > $iptemp
         chmod og+r $iptemp
@@ -207,7 +207,7 @@ run() {
               --publish=8001:8001
               --publish=8002:8002
               --publish=4202:4202
-	      --publish=45000-45020:45000-45020"
+              --publish=45000-45020:45000-45020"
     else
         PUBLIC=""
     fi
@@ -228,7 +228,7 @@ run() {
                --name=$ARVBOX_CONTAINER \
                --privileged \
                --volumes-from $ARVBOX_CONTAINER-data \
-	       --label "org.arvados.arvbox_config=$CONFIG" \
+               --label "org.arvados.arvbox_config=$CONFIG" \
                $PUBLIC \
                arvados/arvbox-demo$TAG
         updateconf
@@ -257,7 +257,7 @@ run() {
                        --detach \
                        --name=$ARVBOX_CONTAINER \
                        --privileged \
-		       "--env=SVDIR=/etc/test-service" \
+                       "--env=SVDIR=/etc/test-service" \
                        arvados/arvbox-dev$TAG
 
                 docker exec -ti \
@@ -271,10 +271,10 @@ run() {
                        /var/lib/arvbox/service/api/run-service --only-setup
             fi
 
-	    interactive=""
-	    if [[ -z "$@" ]] ; then
-		interactive=--interactive
-	    fi
+            interactive=""
+            if [[ -z "$@" ]] ; then
+                interactive=--interactive
+            fi
 
             docker exec -ti \
                    -e LINES=$(tput lines) \
@@ -282,32 +282,32 @@ run() {
                    -e TERM=$TERM \
                    -e WORKSPACE=/usr/src/arvados \
                    -e GEM_HOME=/var/lib/gems \
-		   -e CONFIGSRC=/var/lib/arvados/run_tests \
+                   -e CONFIGSRC=/var/lib/arvados/run_tests \
                    $ARVBOX_CONTAINER \
                    /usr/local/lib/arvbox/runsu.sh \
                    /usr/src/arvados/build/run-tests.sh \
                    --temp /var/lib/arvados/test \
-		   $interactive \
+                   $interactive \
                    "$@"
         elif [[ "$CONFIG" = devenv ]] ; then
-	    if [[ $need_setup = 1 ]] ; then
-    		docker_run_dev \
+            if [[ $need_setup = 1 ]] ; then
+                    docker_run_dev \
                     --detach \
-		    --name=${ARVBOX_CONTAINER} \
-		    "--env=SVDIR=/etc/devenv-service" \
-    		    "--volume=$HOME:$HOME:rw" \
-		    --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \
-    		    arvados/arvbox-dev$TAG
-	    fi
-    	    exec docker exec --interactive --tty \
-    		 -e LINES=$(tput lines) \
-    		 -e COLUMNS=$(tput cols) \
-    		 -e TERM=$TERM \
-    		 -e "ARVBOX_HOME=$HOME" \
-    		 -e "DISPLAY=$DISPLAY" \
-    		 --workdir=$PWD \
-		 ${ARVBOX_CONTAINER} \
-    		 /usr/local/lib/arvbox/devenv.sh "$@"
+                    --name=${ARVBOX_CONTAINER} \
+                    "--env=SVDIR=/etc/devenv-service" \
+                        "--volume=$HOME:$HOME:rw" \
+                    --volume=/tmp/.X11-unix:/tmp/.X11-unix:rw \
+                        arvados/arvbox-dev$TAG
+            fi
+                exec docker exec --interactive --tty \
+                     -e LINES=$(tput lines) \
+                     -e COLUMNS=$(tput cols) \
+                     -e TERM=$TERM \
+                     -e "ARVBOX_HOME=$HOME" \
+                     -e "DISPLAY=$DISPLAY" \
+                     --workdir=$PWD \
+                 ${ARVBOX_CONTAINER} \
+                     /usr/local/lib/arvbox/devenv.sh "$@"
         elif [[ "$CONFIG" =~ dev$ ]] ; then
             docker_run_dev \
                    --detach \
@@ -318,12 +318,12 @@ run() {
             updateconf
             wait_for_arvbox
             echo "The Arvados source code is checked out at: $ARVADOS_ROOT"
-	    echo "The Arvados testing root certificate is $VAR_DATA/root-cert.pem"
-	    if [[ "$(listusers)" =~ ^\{\} ]] ; then
-		echo "No users defined, use 'arvbox adduser' to add user logins"
-	    else
-		echo "Use 'arvbox listusers' to see user logins"
-	    fi
+            echo "The Arvados testing root certificate is $VAR_DATA/root-cert.pem"
+            if [[ "$(listusers)" =~ ^\{\} ]] ; then
+                echo "No users defined, use 'arvbox adduser' to add user logins"
+            else
+                echo "Use 'arvbox listusers' to see user logins"
+            fi
         else
             echo "Unknown configuration '$CONFIG'"
         fi
@@ -337,7 +337,7 @@ update() {
     if test -n "$TAG"
     then
         if test $(echo $TAG | cut -c1-1) != '-' ; then
-	    TAG=":$TAG"
+            TAG=":$TAG"
             shift
         else
             unset TAG
@@ -345,9 +345,9 @@ update() {
     fi
 
     if echo "$CONFIG" | grep 'demo$' ; then
-	docker pull arvados/arvbox-demo$TAG
+        docker pull arvados/arvbox-demo$TAG
     else
-	docker pull arvados/arvbox-dev$TAG
+        docker pull arvados/arvbox-dev$TAG
     fi
 }
 
@@ -421,22 +421,22 @@ case "$subcmd" in
 
     sh*)
         exec docker exec --interactive --tty \
-	       -e LINES=$(tput lines) \
-	       -e COLUMNS=$(tput cols) \
-	       -e TERM=$TERM \
-	       -e GEM_HOME=/var/lib/gems \
-	       $ARVBOX_CONTAINER /bin/bash
+               -e LINES=$(tput lines) \
+               -e COLUMNS=$(tput cols) \
+               -e TERM=$TERM \
+               -e GEM_HOME=/var/lib/gems \
+               $ARVBOX_CONTAINER /bin/bash
         ;;
 
     ash*)
         exec docker exec --interactive --tty \
-	       -e LINES=$(tput lines) \
-	       -e COLUMNS=$(tput cols) \
-	       -e TERM=$TERM \
-	       -e GEM_HOME=/var/lib/gems \
-	       -u arvbox \
-	       -w /usr/src/arvados \
-	       $ARVBOX_CONTAINER /bin/bash --login
+               -e LINES=$(tput lines) \
+               -e COLUMNS=$(tput cols) \
+               -e TERM=$TERM \
+               -e GEM_HOME=/var/lib/gems \
+               -u arvbox \
+               -w /usr/src/arvados \
+               $ARVBOX_CONTAINER /bin/bash --login
         ;;
 
     pipe)
@@ -463,7 +463,7 @@ case "$subcmd" in
     update)
         check $@
         stop
-	update $@
+        update $@
         run $@
         ;;
 
@@ -482,7 +482,7 @@ case "$subcmd" in
     status)
         echo "Container: $ARVBOX_CONTAINER"
         if docker ps -a --filter "status=running" | grep -E "$ARVBOX_CONTAINER$" -q ; then
-	    echo "Cluster id: $(getclusterid)"
+            echo "Cluster id: $(getclusterid)"
             echo "Status: running"
             echo "Container IP: $(getip)"
             echo "Published host: $(gethost)"
@@ -563,17 +563,17 @@ case "$subcmd" in
 
     clone)
         if test -n "$2" ; then
-	    mkdir -p "$ARVBOX_BASE/$2"
+            mkdir -p "$ARVBOX_BASE/$2"
             cp -a "$ARVBOX_BASE/$1/passenger" \
-	       "$ARVBOX_BASE/$1/gems" \
-	       "$ARVBOX_BASE/$1/pip" \
-	       "$ARVBOX_BASE/$1/npm" \
-	       "$ARVBOX_BASE/$1/gopath" \
-	       "$ARVBOX_BASE/$1/Rlibs" \
-	       "$ARVBOX_BASE/$1/arvados" \
-	       "$ARVBOX_BASE/$1/composer" \
-	       "$ARVBOX_BASE/$1/workbench2" \
-	       "$ARVBOX_BASE/$2"
+               "$ARVBOX_BASE/$1/gems" \
+               "$ARVBOX_BASE/$1/pip" \
+               "$ARVBOX_BASE/$1/npm" \
+               "$ARVBOX_BASE/$1/gopath" \
+               "$ARVBOX_BASE/$1/Rlibs" \
+               "$ARVBOX_BASE/$1/arvados" \
+               "$ARVBOX_BASE/$1/composer" \
+               "$ARVBOX_BASE/$1/workbench2" \
+               "$ARVBOX_BASE/$2"
             echo "Created new arvbox $2"
             echo "export ARVBOX_CONTAINER=$2"
         else
@@ -583,28 +583,28 @@ case "$subcmd" in
         ;;
 
     root-cert)
-	CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.crt
-	if test -n "$1" ; then
-	    CERT="$1"
-	fi
-	docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/root-cert.pem > "$CERT"
-	echo "Certificate copied to $CERT"
-	;;
+        CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.crt
+        if test -n "$1" ; then
+            CERT="$1"
+        fi
+        docker exec $ARVBOX_CONTAINER cat /var/lib/arvados/root-cert.pem > "$CERT"
+        echo "Certificate copied to $CERT"
+        ;;
 
     psql)
-	exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados'
-	;;
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados'
+        ;;
 
     checkpoint)
-	exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec pg_dump --host=localhost --username=arvados --clean arvados_development > /var/lib/arvados/checkpoint.sql'
-	;;
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec pg_dump --host=localhost --username=arvados --clean arvados_development > /var/lib/arvados/checkpoint.sql'
+        ;;
 
     restore)
-	exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados --quiet --file=/var/lib/arvados/checkpoint.sql'
-	;;
+        exec docker exec -ti $ARVBOX_CONTAINER bash -c 'PGPASSWORD=$(cat /var/lib/arvados/api_database_pw) exec psql --dbname=arvados_development --host=localhost --username=arvados --quiet --file=/var/lib/arvados/checkpoint.sql'
+        ;;
 
     hotreset)
-	exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash - <<EOF
+        exec docker exec -i $ARVBOX_CONTAINER /usr/bin/env GEM_HOME=/var/lib/gems /bin/bash - <<EOF
 sv stop api
 sv stop controller
 sv stop websockets
@@ -627,21 +627,21 @@ sv restart keepstore0
 sv restart keepstore1
 sv restart keepproxy
 EOF
-	;;
+        ;;
 
     adduser)
-	docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) add $@
-	docker exec $ARVBOX_CONTAINER sv restart controller
-	;;
+        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) add $@
+        docker exec $ARVBOX_CONTAINER sv restart controller
+        ;;
 
     removeuser)
-	docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) remove $@
-	docker exec $ARVBOX_CONTAINER sv restart controller
-	;;
+        docker exec -ti $ARVBOX_CONTAINER /usr/local/lib/arvbox/edit_users.py /var/lib/arvados/cluster_config.yml.override $(getclusterid) remove $@
+        docker exec $ARVBOX_CONTAINER sv restart controller
+        ;;
 
     listusers)
-	listusers
-	;;
+        listusers
+        ;;
 
     *)
         echo "Arvados-in-a-box             https://doc.arvados.org/install/arvbox.html"
@@ -661,9 +661,9 @@ EOF
         echo "build   <config>   build arvbox Docker image"
         echo "reboot  <config>   stop, build arvbox Docker image, run"
         echo "rebuild <config>   build arvbox Docker image, no layer cache"
-	echo "checkpoint         create database backup"
-	echo "restore            restore checkpoint"
-	echo "hotreset           reset database and restart API without restarting container"
+        echo "checkpoint         create database backup"
+        echo "restore            restore checkpoint"
+        echo "hotreset           reset database and restart API without restarting container"
         echo "reset              delete arvbox arvados data (be careful!)"
         echo "destroy            delete all arvbox code and data (be careful!)"
         echo "log <service>      tail log of specified service"
@@ -671,12 +671,12 @@ EOF
         echo "cat <files>        get contents of files inside arvbox"
         echo "pipe               run a bash script piped in from stdin"
         echo "sv <start|stop|restart> <service> "
-	echo "                   change state of service inside arvbox"
+        echo "                   change state of service inside arvbox"
         echo "clone <from> <to>  clone dev arvbox"
-	echo "adduser <username> <email>"
-	echo "                   add a user login"
-	echo "removeuser <username>"
-	echo "                   remove user login"
-	echo "listusers          list user logins"
+        echo "adduser <username> <email>"
+        echo "                   add a user login"
+        echo "removeuser <username>"
+        echo "                   remove user login"
+        echo "listusers          list user logins"
         ;;
 esac
diff --git a/tools/arvbox/lib/arvbox/docker/Dockerfile.base b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
index 815db22b4..eb52ca5a7 100644
--- a/tools/arvbox/lib/arvbox/docker/Dockerfile.base
+++ b/tools/arvbox/lib/arvbox/docker/Dockerfile.base
@@ -2,17 +2,17 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-FROM debian:9
+FROM debian:10
 
 ENV DEBIAN_FRONTEND noninteractive
 
 RUN apt-get update && \
     apt-get -yq --no-install-recommends -o Acquire::Retries=6 install \
-    postgresql-9.6 postgresql-contrib-9.6 git build-essential runit curl libpq-dev \
-    libcurl4-openssl-dev libssl1.0-dev zlib1g-dev libpcre3-dev libpam-dev \
+    postgresql postgresql-contrib git build-essential runit curl libpq-dev \
+    libcurl4-openssl-dev libssl-dev zlib1g-dev libpcre3-dev libpam-dev \
     openssh-server netcat-traditional \
     graphviz bzip2 less sudo virtualenv \
-    libpython-dev fuse libfuse-dev \
+    fuse libfuse-dev \
     pkg-config libattr1-dev \
     libwww-perl libio-socket-ssl-perl libcrypt-ssleay-perl \
     libjson-perl nginx gitolite3 lsof libreadline-dev \
@@ -20,14 +20,12 @@ RUN apt-get update && \
     linkchecker python3-virtualenv python3-venv xvfb iceweasel \
     libgnutls28-dev python3-dev vim cadaver cython gnupg dirmngr \
     libsecret-1-dev r-base r-cran-testthat libxml2-dev pandoc \
-    python3-setuptools python3-pip openjdk-8-jdk bsdmainutils net-tools \
-    ruby2.3 ruby-dev bundler shellinabox  && \
-    apt-get remove -yq libpython-dev libpython-stdlib libpython2.7 libpython2.7-dev \
-    libpython2.7-minimal libpython2.7-stdlib python2.7-minimal python2.7 && \
+    python3-setuptools python3-pip default-jdk-headless bsdmainutils net-tools \
+    ruby ruby-dev bundler shellinabox  && \
     apt-get clean
 
-ENV RUBYVERSION_MINOR 2.3
-ENV RUBYVERSION 2.3.5
+ENV RUBYVERSION_MINOR 2.5
+ENV RUBYVERSION 2.5.1
 
 # Install Ruby from source
 # RUN cd /tmp && \
@@ -40,10 +38,9 @@ ENV RUBYVERSION 2.3.5
 #  rm -rf ruby-${RUBYVERSION}
 
 ENV GEM_HOME /var/lib/gems
-ENV GEM_PATH /var/lib/gems
 ENV PATH $PATH:/var/lib/gems/bin
 
-ENV GOVERSION 1.13.6
+ENV GOVERSION 1.15.2
 
 # Install golang binary
 RUN curl -f http://storage.googleapis.com/golang/go${GOVERSION}.linux-amd64.tar.gz | \
@@ -60,9 +57,9 @@ RUN apt-key add --no-tty /tmp/8D81803C0EBFCD88.asc && \
     rm -f /tmp/8D81803C0EBFCD88.asc
 
 RUN mkdir -p /etc/apt/sources.list.d && \
-    echo deb https://download.docker.com/linux/debian/ stretch stable > /etc/apt/sources.list.d/docker.list && \
+    echo deb https://download.docker.com/linux/debian/ buster stable > /etc/apt/sources.list.d/docker.list && \
     apt-get update && \
-    apt-get -yq --no-install-recommends install docker-ce=17.06.0~ce-0~debian && \
+    apt-get -yq --no-install-recommends install docker-ce=5:19.03.13~3-0~debian-buster && \
     apt-get clean
 
 RUN rm -rf /var/lib/postgresql && mkdir -p /var/lib/postgresql
@@ -117,4 +114,4 @@ ADD runit /etc/runit
 # Start the supervisor.
 ENV SVDIR /etc/service
 STOPSIGNAL SIGINT
-CMD ["/sbin/runit"]
+CMD ["/etc/runit/2"]
diff --git a/tools/arvbox/lib/arvbox/docker/common.sh b/tools/arvbox/lib/arvbox/docker/common.sh
index e81e8108e..185467cf7 100644
--- a/tools/arvbox/lib/arvbox/docker/common.sh
+++ b/tools/arvbox/lib/arvbox/docker/common.sh
@@ -2,10 +2,9 @@
 #
 # SPDX-License-Identifier: AGPL-3.0
 
-
+export DEBIAN_FRONTEND=noninteractive
 export PATH=${PATH}:/usr/local/go/bin:/var/lib/gems/bin
 export GEM_HOME=/var/lib/gems
-export GEM_PATH=/var/lib/gems
 export npm_config_cache=/var/lib/npm
 export npm_config_cache_min=Infinity
 export R_LIBS=/var/lib/Rlibs
@@ -60,6 +59,10 @@ fi
 
 run_bundler() {
     if test -f Gemfile.lock ; then
+        # The 'gem install bundler line below' is cf.
+        # https://bundler.io/blog/2019/05/14/solutions-for-cant-find-gem-bundler-with-executable-bundle.html,
+        # until we get bundler 2.7.10/3.0.0 or higher
+        gem install bundler --no-document -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1|tr -d ' ')"
         frozen=--frozen
     else
         frozen=""
@@ -73,8 +76,8 @@ run_bundler() {
     #         flock /var/lib/gems/gems.lock gem install --verbose --no-document bundler --version ${bundleversion}
     #     fi
     # fi
-    if ! flock /var/lib/gems/gems.lock bundler install --verbose --path $GEM_HOME --local --no-deployment $frozen "$@" ; then
-        flock /var/lib/gems/gems.lock bundler install --verbose --path $GEM_HOME --no-deployment $frozen "$@"
+    if ! flock /var/lib/gems/gems.lock bundler install --verbose --local --no-deployment $frozen "$@" ; then
+        flock /var/lib/gems/gems.lock bundler install --verbose --no-deployment $frozen "$@"
     fi
 }
 
diff --git a/tools/arvbox/lib/arvbox/docker/createusers.sh b/tools/arvbox/lib/arvbox/docker/createusers.sh
index 58fb41358..de1e7bba9 100755
--- a/tools/arvbox/lib/arvbox/docker/createusers.sh
+++ b/tools/arvbox/lib/arvbox/docker/createusers.sh
@@ -46,7 +46,6 @@ if ! grep "^arvbox:" /etc/passwd >/dev/null 2>/dev/null ; then
     cat <<EOF > /etc/profile.d/paths.sh
 export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/go/bin:/var/lib/gems/bin:$(ls -d /usr/local/node-*)/bin
 export GEM_HOME=/var/lib/gems
-export GEM_PATH=/var/lib/gems
 export npm_config_cache=/var/lib/npm
 export npm_config_cache_min=Infinity
 export R_LIBS=/var/lib/Rlibs
diff --git a/tools/arvbox/lib/arvbox/docker/service/postgres/run-service b/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
index a0771aa6a..f2377a0c2 100755
--- a/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/postgres/run-service
@@ -6,7 +6,7 @@
 exec 2>&1
 set -eux -o pipefail
 
-PGVERSION=9.6
+PGVERSION=11
 
 if ! test -d /var/lib/postgresql/$PGVERSION/main ; then
     /usr/lib/postgresql/$PGVERSION/bin/initdb --locale=en_US.UTF-8 -D /var/lib/postgresql/$PGVERSION/main
diff --git a/tools/arvbox/lib/arvbox/docker/service/sdk/run-service b/tools/arvbox/lib/arvbox/docker/service/sdk/run-service
index 1ec225ca1..d66bf315b 100755
--- a/tools/arvbox/lib/arvbox/docker/service/sdk/run-service
+++ b/tools/arvbox/lib/arvbox/docker/service/sdk/run-service
@@ -20,20 +20,6 @@ ln -sf /usr/src/arvados/sdk/cli/binstubs/arv /usr/local/bin/arv
 
 export PYCMD=python3
 
-# Need to install the upstream version of pip because the python-pip package
-# shipped with Debian 9 is patched to change behavior in a way that breaks our
-# use case.
-# See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876145
-# When a non-root user attempts to install system packages, it makes the
-# --ignore-installed flag the default (and there is no way to turn it off),
-# this has the effect of making it very hard to share dependencies shared among
-# multiple packages, because it will blindly install the latest version of each
-# dependency requested by each package, even if a compatible package version is
-# already installed.
-if ! pip3 install --no-index --find-links /var/lib/pip pip==9.0.3 ; then
-    pip3 install pip==9.0.3
-fi
-
 pip_install wheel
 
 cd /usr/src/arvados/sdk/python

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list