Merge branch '17944-backend-vocabulary-validation-rebased' into main.
authorLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 11 Nov 2021 17:51:31 +0000 (14:51 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Thu, 11 Nov 2021 17:51:31 +0000 (14:51 -0300)
Refs #17944

Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

20 files changed:
cmd/arvados-package/install.go
doc/Rakefile
doc/_includes/_tutorial_expectations.liquid
doc/admin/upgrading.html.textile.liquid
doc/admin/user-activity.html.textile.liquid
doc/api/permission-model.html.textile.liquid
doc/api/projects.html.textile.liquid
doc/architecture/keep-components-overview.html.textile.liquid
doc/install/arvados-on-kubernetes-GKE.html.textile.liquid
doc/install/arvados-on-kubernetes-minikube.html.textile.liquid
doc/install/arvados-on-kubernetes.html.textile.liquid
doc/install/crunch2/install-compute-node-docker.html.textile.liquid
doc/install/crunch2/install-compute-node-singularity.html.textile.liquid
doc/install/salt-multi-host.html.textile.liquid
doc/user/topics/arvados-sync-groups.html.textile.liquid
lib/controller/federation/conn.go
lib/controller/federation/federation_test.go
lib/controller/integration_test.go
sdk/go/arvados/container.go
services/keepstore/unix_volume.go

index 85c64b867e2b7abfd69af14f78aad431ca61e185..5fdb7a87563aaec1323f9ec26553387c49b4e889 100644 (file)
@@ -45,14 +45,14 @@ func testinstall(ctx context.Context, opts opts, stdin io.Reader, stdout, stderr
                        opts.TargetOS,
                        "bash", "-c", `
 set -e -o pipefail
-apt-get update
+apt-get --allow-releaseinfo-change update
 apt-get install -y --no-install-recommends dpkg-dev eatmydata
 
 mkdir /tmp/pkg
 ln -s /pkg/*.deb /tmp/pkg/
 (cd /tmp/pkg; dpkg-scanpackages --multiversion . | gzip > Packages.gz)
 echo >/etc/apt/sources.list.d/arvados-local.list "deb [trusted=yes] file:///tmp/pkg ./"
-apt-get update
+apt-get --allow-releaseinfo-change update
 
 eatmydata apt-get install -y --no-install-recommends arvados-server-easy postgresql
 eatmydata apt-get remove -y dpkg-dev
@@ -88,7 +88,7 @@ rm /etc/apt/sources.list.d/arvados-local.list
                "bash", "-c", `
 set -e -o pipefail
 PATH="/var/lib/arvados/bin:$PATH"
-apt-get update
+apt-get --allow-releaseinfo-change update
 apt-get install -y --no-install-recommends dpkg-dev
 mkdir /tmp/pkg
 ln -s /pkg/*.deb /tmp/pkg/
@@ -97,7 +97,7 @@ apt-get remove -y dpkg-dev
 echo
 
 echo >/etc/apt/sources.list.d/arvados-local.list "deb [trusted=yes] file:///tmp/pkg ./"
-apt-get update
+apt-get --allow-releaseinfo-change update
 eatmydata apt-get install --reinstall -y --no-install-recommends arvados-server-easy`+versionsuffix+`
 SUDO_FORCE_REMOVE=yes apt-get autoremove -y
 
index 2b4b6af2e0cb2385a95835033fc69c90c5dd8ce3..4427f7822e855e0a0a9d10e5ebb140168114f2b9 100644 (file)
@@ -160,7 +160,8 @@ task :linkchecker => [ :generate ] do
   Dir.chdir(".site") do
     `which linkchecker`
     if $? == 0
-      system "linkchecker index.html --ignore-url='!file://'" or exit $?.exitstatus
+      # we need --check-extern to check relative links, weird but true
+      system "linkchecker index.html --check-extern --ignore-url='!file://'" or exit $?.exitstatus
     else
       puts "Warning: linkchecker not found, skipping run".colorize(:light_red)
     end
index 09b18f0d4d662ac805f22edfbbe594867a40245d..d4d05078f6ce86f8ac564b11049ce282539b16f2 100644 (file)
@@ -5,5 +5,5 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
 {% include 'notebox_begin' %}
-This tutorial assumes that you have access to the "Arvados command line tools":/user/getting_started/setup-cli.html and have set the "API token":{{site.baseurl}}/user/reference/api-tokens.html and confirmed a "working environment.":{{site.baseurl}}/user/getting_started/check-environment.html .
+This tutorial assumes that you have access to the "Arvados command line tools":{{ site.baseurl }}/user/getting_started/setup-cli.html and have set the "API token":{{site.baseurl}}/user/reference/api-tokens.html and confirmed a "working environment.":{{site.baseurl}}/user/getting_started/check-environment.html .
 {% include 'notebox_end' %}
index 211b931886bcd3c40e41b1ee7266f01adee060d3..15b8d2c40d4afcabe1efcc30afa6a2c8d939fafe 100644 (file)
@@ -413,7 +413,7 @@ h3. Python packaging change
 
 As part of story "#9945":https://dev.arvados.org/issues/9945, the distribution packaging (deb/rpm) of our Python packages has changed. These packages now include a built-in virtualenv to reduce dependencies on system packages. We have also stopped packaging and publishing backports for all the Python dependencies of our packages, as they are no longer needed.
 
-One practical consequence of this change is that the use of the Arvados Python SDK (aka "import arvados") will require a tweak if the SDK was installed from a distribution package. It now requires the loading of the virtualenv environment from our packages. The "Install documentation for the Arvados Python SDK":/sdk/python/sdk-python.html reflects this change. This does not affect the use of the command line tools (e.g. arv-get, etc.).
+One practical consequence of this change is that the use of the Arvados Python SDK (aka "import arvados") will require a tweak if the SDK was installed from a distribution package. It now requires the loading of the virtualenv environment from our packages. The "Install documentation for the Arvados Python SDK":{{ site.baseurl }}/sdk/python/sdk-python.html reflects this change. This does not affect the use of the command line tools (e.g. arv-get, etc.).
 
 Python scripts that rely on the distribution Arvados Python SDK packages to import the Arvados SDK will need to be tweaked to load the correct Python environment.
 
index 21bfb7655ca997f51c5f268d94ac7979b9786c3b..01715ff6e3484877598834e985fdb1576fc0c505 100644 (file)
@@ -17,7 +17,7 @@ h2. Option 1: Install from a distribution package
 
 This installation method is recommended to make the CLI tools available system-wide. It can coexist with the installation method described in option 2, below.
 
-First, configure the "Arvados package repositories":../../install/packages.html
+First, configure the "Arvados package repositories":{{ site.baseurl }}/install/packages.html
 
 {% assign arvados_component = 'python3-arvados-user-activity' %}
 
@@ -31,7 +31,7 @@ Step 2: Change directory to @arvados/tools/user-activity@
 
 Step 3: Run @pip install .@ in an appropriate installation environment, such as a @virtualenv@.
 
-Note: depends on the "Arvados Python SDK":../sdk/python/sdk-python.html and its associated build prerequisites (e.g. @pycurl@).
+Note: depends on the "Arvados Python SDK":{{ site.baseurl }}/sdk/python/sdk-python.html and its associated build prerequisites (e.g. @pycurl@).
 
 h2. Usage
 
index 82e8128c6e80445aed6f96409aa0165cd06c74b4..a44d2eefa13ac7cc43e89776d9773169f3b5fe4e 100644 (file)
@@ -46,7 +46,7 @@ This grants the permission in @name@ for @tail_uuid@ accessing @head_uuid@.
 
 If a User has *can_manage* permission on some object, the user has the ability to read, create, update and delete permission links with @head_uuid@ of the managed object.  In other words, the user has the ability to modify the permission grants on the object.
 
-The *can_login* @name@ is only meaningful on a permission link with with @tail_uuid@ a user UUID and @head_uuid@ a Virtual Machine UUID. A permission link of this type gives the user UUID permission to log into the Virtual Machine UUID. The username for the VM is specified in the @properties@ field. Group membership can be specified that way as well, optionally. See the "VM login section on the CLI cheat sheet":/install/cheat_sheet.html#vm-login for an example.
+The *can_login* @name@ is only meaningful on a permission link with with @tail_uuid@ a user UUID and @head_uuid@ a Virtual Machine UUID. A permission link of this type gives the user UUID permission to log into the Virtual Machine UUID. The username for the VM is specified in the @properties@ field. Group membership can be specified that way as well, optionally. See the "VM login section on the 'User management at the CLI' page":{{ site.baseurl }}/admin/user-management-cli.html#vm-login for an example.
 
 h3. Transitive permissions
 
@@ -66,7 +66,7 @@ A "project" is a subtype of Group that is displayed as a "Project" in Workbench,
 * The name of a project is unique only among projects and filters with the same owner_uuid.
 * Projects can be targets (@head_uuid@) of permission links, but not origins (@tail_uuid@).  Putting a project in a @tail_uuid@ field is an error.
 
-A "filter" is a subtype of Group that is displayed as a "Project" in Workbench, and as a directory by @arv-mount@. See "the groups API documentation":/api/methods/groups.html for more information.
+A "filter" is a subtype of Group that is displayed as a "Project" in Workbench, and as a directory by @arv-mount@. See "the groups API documentation":{{ site.baseurl }}/api/methods/groups.html for more information.
 * A filter group cannot own things (cannot appear in @owner_uuid@).  Putting a filter group in an @owner_uuid@ field is an error.
 * A filter group can be owned by a user or a project.
 * The name of a filter is unique only among projects and filters with the same owner_uuid.
index b1c74fe0d729794f26c2b535989f9dedf21c462b..9aa3d85d4d5297adfc91d396a9f8b518d9ff831e 100644 (file)
@@ -11,7 +11,7 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 
 Arvados @projects@ are used to organize objects. Projects can contain @collections@, @container requests@, @workflows@, etc. Projects can also contain other projects. An object is part of a project if the @owner_uuid@ of the object is set to the uuid of the project.
 
-Projects are implemented as a subtype of the Arvados @group@ object type, with @group_class@ set to the value "project". More information is available in the "groups API reference":/api/methods/groups.html.
+Projects are implemented as a subtype of the Arvados @group@ object type, with @group_class@ set to the value "project". More information is available in the "groups API reference":{{ site.baseurl }}/api/methods/groups.html.
 
 Projects can be manipulated via Workbench, the cli tools, the SDKs, and the Arvados APIs.
 
index b07716aacf09b522781f8e5754c3fc30a2e3f591..4b1ca9b8458d27c518c53c3703bd7be7b9a71560 100644 (file)
@@ -14,13 +14,13 @@ Keep has a number of components. This page describes each component and the role
 h3. Keep clients for data access
 
 In order to access data in Keep, a client is needed to store data in and retrieve data from Keep. Different types of Keep clients exist:
-* a command line client like "@arv-get@":/user/tutorials/tutorial-keep-get.html#download-using-arv or "@arv-put@":/user/tutorials/tutorial-keep.html#upload-using-command
-* a FUSE mount provided by "@arv-mount@":/user/tutorials/tutorial-keep-mount-gnu-linux.html
+* a command line client like "@arv-get@":{{ site.baseurl }}/user/tutorials/tutorial-keep-get.html#download-using-arv or "@arv-put@":{{ site.baseurl }}/user/tutorials/tutorial-keep.html#upload-using-command
+* a FUSE mount provided by "@arv-mount@":{{ site.baseurl }}/user/tutorials/tutorial-keep-mount-gnu-linux.html
 * a WebDAV mount provided by @keep-web@
 * an S3-compatible endpoint provided by @keep-web@
-* programmatic access via the "Arvados SDKs":/sdk/index.html
+* programmatic access via the "Arvados SDKs":{{ site.baseurl }}/sdk/index.html
 
-In essense, these clients all do the same thing: they translate file and directory references into requests for Keep blocks and collection manifests. How Keep clients work, and how they use rendezvous hashing, is described in greater detail in "the next section":/architecture/keep-clients.html.
+In essense, these clients all do the same thing: they translate file and directory references into requests for Keep blocks and collection manifests. How Keep clients work, and how they use rendezvous hashing, is described in greater detail in "the next section":{{ site.baseurl }}/architecture/keep-clients.html.
 
 For example, when a request comes in to read a file from Keep, the client will
 * request the collection object (including its manifest) from the API server
@@ -32,7 +32,7 @@ All of those steps are subject to access control, which applies at the level of
 
 h3. API server
 
-The API server stores collection objects and all associated metadata. That includes data about where the blocks for a collection are to be stored, e.g. when "storage classes":/admin/storage-classes.html are configured, as well as the desired and confirmed replication count for each block. It also stores the ACLs that control access to the collections. Finally, the API server provides Keep clients with time-based block signatures for access.
+The API server stores collection objects and all associated metadata. That includes data about where the blocks for a collection are to be stored, e.g. when "storage classes":{{ site.baseurl }}/admin/storage-classes.html are configured, as well as the desired and confirmed replication count for each block. It also stores the ACLs that control access to the collections. Finally, the API server provides Keep clients with time-based block signatures for access.
 
 h3. Keepstore
 
index f7b7a1641526f8d19d007335dd020c78ebd648ed..5a5d59bc86201c82602bd84b4c6b26f2ce8d117e 100644 (file)
@@ -9,7 +9,7 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-This page documents setting up and running the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Google Kubernetes Engine@ (GKE).
+This page documents setting up and running the "Arvados on Kubernetes":{{ site.baseurl }}/install/arvados-on-kubernetes.html @Helm@ chart on @Google Kubernetes Engine@ (GKE).
 
 h2. Prerequisites
 
index 9ecb2c89562b446166721ca0b9b0c04d5b4091c5..6b292caf3904d5a078ae9d8eaf939d41b4f0c236 100644 (file)
@@ -9,7 +9,7 @@ Copyright (C) The Arvados Authors. All rights reserved.
 SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
-This page documents setting up and running the "Arvados on Kubernetes":/install/arvados-on-kubernetes.html @Helm@ chart on @Minikube@.
+This page documents setting up and running the "Arvados on Kubernetes":{{ site.baseurl }}/install/arvados-on-kubernetes.html @Helm@ chart on @Minikube@.
 
 h2. Prerequisites
 
index 9169b7810ed94b0b8411a7cc238c4fede72c203e..5ef757d10e689b33c8466a5acf44f7771a7142c3 100644 (file)
@@ -28,5 +28,5 @@ h2. Requirements
 * Minikube or Google Kubernetes Engine (Kubernetes 1.10+ with at least 3 nodes, 2+ cores per node)
 * @kubectl@ and @Helm 3@ installed locally, and able to connect to your Kubernetes cluster
 
-Please refer to "Arvados on Minikube":/install/arvados-on-kubernetes-minikube.html or "Arvados on GKE":/install/arvados-on-kubernetes-GKE.html for detailed installation instructions.
+Please refer to "Arvados on Minikube":{{ site.baseurl }}/install/arvados-on-kubernetes-minikube.html or "Arvados on GKE":{{ site.baseurl }}/install/arvados-on-kubernetes-GKE.html for detailed installation instructions.
 
index 876bb6ae5da58e9d928e7b49bcd9bee6d5b949a4..66bd85b7c5038073beaf95d342fde7c2060d90b2 100644 (file)
@@ -10,7 +10,7 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
 {% include 'notebox_begin_warning' %}
-This page describes the requirements for a compute node in a Slurm or LSF cluster that will run containers dispatched by @crunch-dispatch-slurm@ or @arvados-dispatch-lsf@. If you are installing a cloud cluster, refer to "Build a cloud compute node image":/install/crunch2-cloud/install-compute-node.html.
+This page describes the requirements for a compute node in a Slurm or LSF cluster that will run containers dispatched by @crunch-dispatch-slurm@ or @arvados-dispatch-lsf@. If you are installing a cloud cluster, refer to "Build a cloud compute node image":{{ site.baseurl }}/install/crunch2-cloud/install-compute-node.html.
 {% include 'notebox_end' %}
 
 {% include 'notebox_begin_warning' %}
index 09a3b4e3aba38bec42c3e7eb8168eff94fe60f95..8e9db0c4e3d7bcd2a1312f19caeba89ba08da245 100644 (file)
@@ -10,7 +10,7 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 {% endcomment %}
 
 {% include 'notebox_begin_warning' %}
-This page describes the requirements for a compute node in a Slurm or LSF cluster that will run containers dispatched by @crunch-dispatch-slurm@ or @arvados-dispatch-lsf@. If you are installing a cloud cluster, refer to "Build a cloud compute node image":/install/crunch2-cloud/install-compute-node.html.
+This page describes the requirements for a compute node in a Slurm or LSF cluster that will run containers dispatched by @crunch-dispatch-slurm@ or @arvados-dispatch-lsf@. If you are installing a cloud cluster, refer to "Build a cloud compute node image":{{ site.baseurl }}/install/crunch2-cloud/install-compute-node.html.
 {% include 'notebox_end' %}
 
 {% include 'notebox_begin_warning' %}
index ab36035a846fc05e8204a751672b313239ceb074..e497240c4c20ea27a06d4e522b7d2ab033f102a8 100644 (file)
@@ -11,7 +11,6 @@ SPDX-License-Identifier: CC-BY-SA-3.0
 
 # "Introduction":#introduction
 # "Hosts preparation":#hosts_preparation
-## "Hosts setup using terraform (experimental)":#hosts_setup_using_terraform
 ## "Create a compute image":#create_a_compute_image
 # "Multi host install using the provision.sh script":#multi_host
 # "Choose the desired configuration":#choose_configuration
@@ -65,14 +64,6 @@ Note that these hosts can be virtual machines in your infrastructure and they do
 
 Again, if your infrastructure differs from the setup proposed above (ie, using RDS or an existing DB server), remember that you will need to edit the configuration files for the scripts so they work with your infrastructure.
 
-
-h3(#hosts_setup_using_terraform). Hosts setup using terraform (AWS, experimental)
-
-We added a few "terraform":https://terraform.io/ scripts (https://github.com/arvados/arvados/tree/main/tools/terraform) to let you create these instances easier in an AWS account. Check "the Arvados terraform documentation":/doc/install/terraform.html for more details.
-
-
-
-
 h2(#multi_host). Multi host install using the provision.sh script
 
 {% include 'branchname' %}
@@ -112,7 +103,7 @@ The <i>multi_host</i> example includes Let's Encrypt salt code to automatically
 
 h3(#further_customization). Further customization of the installation (modifying the salt pillars and states)
 
-You will need further customization to suit your environment, which can be done editing the Saltstack pillars and states files. Pay particular attention to the <i>pillars/arvados.sls</i> file, where you will need to provide some information that can be retrieved as output of the terraform run.
+You will need further customization to suit your environment, which can be done editing the Saltstack pillars and states files. Pay particular attention to the <i>pillars/arvados.sls</i> file, where you will need to provide some information that describes your environment.
 
 Any extra <i>state</i> file you add under <i>local_config_dir/states</i> will be added to the salt run and applied to the hosts.
 
index 26be56782de0633f6a485b9b29624cabd60d4bd7..1f7eede4bb14650a862e1276cf1b8bccbc05e429 100644 (file)
@@ -19,7 +19,7 @@ Every line on the file should have 3 values: a group name, a local user identifi
 
 Users can be identified by their email address or username: the tool will check if every user exist on the system, and report back when not found. Groups on the other hand, are identified by their name.
 
-Permission level can be one of the following: @can_read@, @can_write@ or @can_manage@, giving the group member read, read/write or managing privileges on the group. For backwards compatibility purposes, if any record omits the third (permission) field, it will default to @can_write@ permission. You can read more about permissions on the "group management admin guide":/admin/group-management.html.
+Permission level can be one of the following: @can_read@, @can_write@ or @can_manage@, giving the group member read, read/write or managing privileges on the group. For backwards compatibility purposes, if any record omits the third (permission) field, it will default to @can_write@ permission. You can read more about permissions on the "group management admin guide":{{ site.baseurl }}/admin/group-management.html.
 
 This tool is designed to be run periodically reading a file created by a remote auth system (ie: LDAP) dump script, applying what's included on the file as the source of truth.
 
index 30e1561ee5e917ef8e040c8c38df189021cfa5be..d1bf473d76856abd59bfb35f069e4f47f498e680 100644 (file)
@@ -38,7 +38,7 @@ func New(cluster *arvados.Cluster, healthFuncs *map[string]health.Func) *Conn {
                if !remote.Proxy || id == cluster.ClusterID {
                        continue
                }
-               conn := rpc.NewConn(id, &url.URL{Scheme: remote.Scheme, Host: remote.Host}, remote.Insecure, saltedTokenProvider(local, id))
+               conn := rpc.NewConn(id, &url.URL{Scheme: remote.Scheme, Host: remote.Host}, remote.Insecure, saltedTokenProvider(cluster, local, id))
                // Older versions of controller rely on the Via header
                // to detect loops.
                conn.SendHeader = http.Header{"Via": {"HTTP/1.1 arvados-controller"}}
@@ -61,7 +61,7 @@ func New(cluster *arvados.Cluster, healthFuncs *map[string]health.Func) *Conn {
 // tokens from an incoming request context, determines whether they
 // should (and can) be salted for the given remoteID, and returns the
 // resulting tokens.
-func saltedTokenProvider(local backend, remoteID string) rpc.TokenProvider {
+func saltedTokenProvider(cluster *arvados.Cluster, local backend, remoteID string) rpc.TokenProvider {
        return func(ctx context.Context) ([]string, error) {
                var tokens []string
                incoming, ok := auth.FromContext(ctx)
@@ -69,6 +69,16 @@ func saltedTokenProvider(local backend, remoteID string) rpc.TokenProvider {
                        return nil, errors.New("no token provided")
                }
                for _, token := range incoming.Tokens {
+                       if strings.HasPrefix(token, "v2/"+cluster.ClusterID+"-") && remoteID == cluster.Login.LoginCluster {
+                               // If we did this, the login cluster
+                               // would call back to us and then
+                               // reject our response because the
+                               // user UUID prefix (i.e., the
+                               // LoginCluster prefix) won't match
+                               // the token UUID prefix (i.e., our
+                               // prefix).
+                               return nil, httpErrorf(http.StatusUnauthorized, "cannot use a locally issued token to forward a request to our login cluster (%s)", remoteID)
+                       }
                        salted, err := auth.SaltToken(token, remoteID)
                        switch err {
                        case nil:
index 929d09bc845f51a4851c05a1360a3b5595f115f2..5460e938a66348ec2a98f2a478372ea901c4c235 100644 (file)
@@ -93,5 +93,5 @@ func (s *FederationSuite) addHTTPRemote(c *check.C, id string, backend backend)
                Host:   srv.Addr,
                Proxy:  true,
        }
-       s.fed.remotes[id] = rpc.NewConn(id, &url.URL{Scheme: "http", Host: srv.Addr}, true, saltedTokenProvider(s.fed.local, id))
+       s.fed.remotes[id] = rpc.NewConn(id, &url.URL{Scheme: "http", Host: srv.Addr}, true, saltedTokenProvider(s.cluster, s.fed.local, id))
 }
index 02061547bf5b826b1618ac37298a876cd205b30b..4cf6a683287ae211f58f13cdb664d087f2ceff00 100644 (file)
@@ -959,3 +959,63 @@ func (s *IntegrationSuite) TestOIDCAccessTokenAuth(c *check.C) {
                }
        }
 }
+
+// z3333 should not forward a locally-issued container runtime token,
+// associated with a z1111 user, to its login cluster z1111. z1111
+// would only call back to z3333 and then reject the response because
+// the user ID does not match the token prefix. See
+// dev.arvados.org/issues/18346
+func (s *IntegrationSuite) TestForwardRuntimeTokenToLoginCluster(c *check.C) {
+       db3, db3conn := s.dbConn(c, "z3333")
+       defer db3.Close()
+       defer db3conn.Close()
+       rootctx1, _, _ := s.testClusters["z1111"].RootClients()
+       rootctx3, _, _ := s.testClusters["z3333"].RootClients()
+       conn1 := s.testClusters["z1111"].Conn()
+       conn3 := s.testClusters["z3333"].Conn()
+       userctx1, _, _, _ := s.testClusters["z1111"].UserClients(rootctx1, c, conn1, "user@example.com", true)
+
+       user1, err := conn1.UserGetCurrent(userctx1, arvados.GetOptions{})
+       c.Assert(err, check.IsNil)
+       c.Logf("user1 %+v", user1)
+
+       imageColl, err := conn3.CollectionCreate(userctx1, arvados.CreateOptions{Attrs: map[string]interface{}{
+               "manifest_text": ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.tar\n",
+       }})
+       c.Assert(err, check.IsNil)
+       c.Logf("imageColl %+v", imageColl)
+
+       cr, err := conn3.ContainerRequestCreate(userctx1, arvados.CreateOptions{Attrs: map[string]interface{}{
+               "state":           "Committed",
+               "command":         []string{"echo"},
+               "container_image": imageColl.PortableDataHash,
+               "cwd":             "/",
+               "output_path":     "/",
+               "priority":        1,
+               "runtime_constraints": arvados.RuntimeConstraints{
+                       VCPUs: 1,
+                       RAM:   1000000000,
+               },
+       }})
+       c.Assert(err, check.IsNil)
+       c.Logf("container request %+v", cr)
+       ctr, err := conn3.ContainerLock(rootctx3, arvados.GetOptions{UUID: cr.ContainerUUID})
+       c.Assert(err, check.IsNil)
+       c.Logf("container %+v", ctr)
+
+       // We could use conn3.ContainerAuth() here, but that API
+       // hasn't been added to sdk/go/arvados/api.go yet.
+       row := db3conn.QueryRowContext(context.Background(), `SELECT api_token from api_client_authorizations where uuid=$1`, ctr.AuthUUID)
+       c.Check(row, check.NotNil)
+       var val sql.NullString
+       row.Scan(&val)
+       c.Assert(val.Valid, check.Equals, true)
+       runtimeToken := "v2/" + ctr.AuthUUID + "/" + val.String
+       ctrctx, _, _ := s.testClusters["z3333"].ClientsWithToken(runtimeToken)
+       c.Logf("container runtime token %+v", runtimeToken)
+
+       _, err = conn3.UserGet(ctrctx, arvados.GetOptions{UUID: user1.UUID})
+       c.Assert(err, check.NotNil)
+       c.Check(err, check.ErrorMatches, `request failed: .* 401 Unauthorized: cannot use a locally issued token to forward a request to our login cluster \(z1111\)`)
+       c.Check(err, check.Not(check.ErrorMatches), `(?ms).*127\.0\.0\.11.*`)
+}
index 384bebb5997ee86b1b1be2396498f1554ee32ecc..7c68bdb20222f59067b5c5f1d89bad8ea6fef5fe 100644 (file)
@@ -36,6 +36,7 @@ type Container struct {
        RuntimeUserUUID           string                 `json:"runtime_user_uuid"`
        RuntimeAuthScopes         []string               `json:"runtime_auth_scopes"`
        RuntimeToken              string                 `json:"runtime_token"`
+       AuthUUID                  string                 `json:"auth_uuid"`
 }
 
 // ContainerRequest is an arvados#container_request resource.
index a74616604814488ed9c54fa3e5026f2d4f37c907..f076ccf18419675499e12eed0e3d017824af8e57 100644 (file)
@@ -135,6 +135,7 @@ func (v *UnixVolume) GetDeviceID() string {
        if err != nil {
                return giveup("opening %q: %s", udir, err)
        }
+       defer d.Close()
        uuids, err := d.Readdirnames(0)
        if err != nil {
                return giveup("reading %q: %s", udir, err)
@@ -274,29 +275,25 @@ func (v *UnixVolume) WriteBlock(ctx context.Context, loc string, rdr io.Reader)
                return fmt.Errorf("error creating directory %s: %s", bdir, err)
        }
 
-       tmpfile, tmperr := v.os.TempFile(bdir, "tmp"+loc)
-       if tmperr != nil {
-               return fmt.Errorf("TempFile(%s, tmp%s) failed: %s", bdir, loc, tmperr)
-       }
-
        bpath := v.blockPath(loc)
+       tmpfile, err := v.os.TempFile(bdir, "tmp"+loc)
+       if err != nil {
+               return fmt.Errorf("TempFile(%s, tmp%s) failed: %s", bdir, loc, err)
+       }
+       defer v.os.Remove(tmpfile.Name())
+       defer tmpfile.Close()
 
-       if err := v.lock(ctx); err != nil {
+       if err = v.lock(ctx); err != nil {
                return err
        }
        defer v.unlock()
        n, err := io.Copy(tmpfile, rdr)
        v.os.stats.TickOutBytes(uint64(n))
        if err != nil {
-               err = fmt.Errorf("error writing %s: %s", bpath, err)
-               tmpfile.Close()
-               v.os.Remove(tmpfile.Name())
-               return err
+               return fmt.Errorf("error writing %s: %s", bpath, err)
        }
-       if err := tmpfile.Close(); err != nil {
-               err = fmt.Errorf("error closing %s: %s", tmpfile.Name(), err)
-               v.os.Remove(tmpfile.Name())
-               return err
+       if err = tmpfile.Close(); err != nil {
+               return fmt.Errorf("error closing %s: %s", tmpfile.Name(), err)
        }
        // ext4 uses a low-precision clock and effectively backdates
        // files by up to 10 ms, sometimes across a 1-second boundary,
@@ -307,14 +304,10 @@ func (v *UnixVolume) WriteBlock(ctx context.Context, loc string, rdr io.Reader)
        v.os.stats.TickOps("utimes")
        v.os.stats.Tick(&v.os.stats.UtimesOps)
        if err = os.Chtimes(tmpfile.Name(), ts, ts); err != nil {
-               err = fmt.Errorf("error setting timestamps on %s: %s", tmpfile.Name(), err)
-               v.os.Remove(tmpfile.Name())
-               return err
+               return fmt.Errorf("error setting timestamps on %s: %s", tmpfile.Name(), err)
        }
-       if err := v.os.Rename(tmpfile.Name(), bpath); err != nil {
-               err = fmt.Errorf("error renaming %s to %s: %s", tmpfile.Name(), bpath, err)
-               v.os.Remove(tmpfile.Name())
-               return err
+       if err = v.os.Rename(tmpfile.Name(), bpath); err != nil {
+               return fmt.Errorf("error renaming %s to %s: %s", tmpfile.Name(), bpath, err)
        }
        return nil
 }