Merge branch '19692-quieter-runtime-status' refs #19692
authorPeter Amstutz <peter.amstutz@curii.com>
Tue, 15 Nov 2022 14:31:15 +0000 (09:31 -0500)
committerPeter Amstutz <peter.amstutz@curii.com>
Tue, 15 Nov 2022 14:31:15 +0000 (09:31 -0500)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

50 files changed:
.gitignore
apps/workbench/Gemfile.lock
apps/workbench/app/helpers/version_helper.rb
apps/workbench/app/views/users/_tables.html.erb
apps/workbench/test/integration/report_issue_test.rb
build/package-build-dockerfiles/centos7/Dockerfile
build/run-build-packages-one-target.sh
build/run-build-packages.sh
build/run-library.sh
build/run-tests.sh
doc/_config.yml
doc/admin/federation.html.textile.liquid
doc/admin/upgrading.html.textile.liquid
doc/architecture/federation.html.textile.liquid
doc/install/configure-s3-object-storage.html.textile.liquid
doc/sdk/index.html.textile.liquid
doc/sdk/perl/example.html.textile.liquid [deleted file]
doc/sdk/perl/index.html.textile.liquid [deleted file]
lib/config/config.default.yml
lib/config/export.go
lib/controller/federation/list.go
lib/controller/federation/login_test.go
lib/controller/handler_test.go
lib/controller/localdb/conn.go
lib/controller/localdb/login.go
lib/controller/localdb/login_oidc.go
lib/controller/localdb/login_oidc_test.go
lib/controller/localdb/login_testuser_test.go
lib/controller/localdb/logout.go
lib/dispatchcloud/node_size.go
lib/dispatchcloud/node_size_test.go
lib/install/deps.go
lib/lsf/dispatch_test.go
sdk/go/arvados/config.go
sdk/perl/.gitignore [deleted file]
sdk/perl/Makefile.PL [deleted file]
sdk/perl/lib/Arvados.pm [deleted file]
sdk/perl/lib/Arvados/Request.pm [deleted file]
sdk/perl/lib/Arvados/ResourceAccessor.pm [deleted file]
sdk/perl/lib/Arvados/ResourceMethod.pm [deleted file]
sdk/perl/lib/Arvados/ResourceProxy.pm [deleted file]
sdk/perl/lib/Arvados/ResourceProxyList.pm [deleted file]
sdk/python/README.rst
sdk/ruby/lib/arvados/keep.rb
services/api/Gemfile.lock
services/api/app/models/api_client.rb
services/fuse/README.rst
services/keepstore/s3_volume.go
services/keepstore/s3aws_volume.go
tools/arvbox/lib/arvbox/docker/common.sh

index 07482bde73e01d82f590b6b3fa1d9e1f95719001..c156018036e74a3582e922d97b610d450d5fbac9 100644 (file)
@@ -14,10 +14,6 @@ doc/.site
 doc/sdk/python/arvados
 doc/sdk/R/arvados
 doc/sdk/java-v2/javadoc
-sdk/perl/MYMETA.*
-sdk/perl/Makefile
-sdk/perl/blib
-sdk/perl/pm_to_blib
 */vendor
 */*/vendor
 sdk/java/target
index c46568b726130fcb8978eebcb3bc5d7e20a589d7..c66272cd3f965ebe198ec9fea8d70f455c8cb270 100644 (file)
@@ -186,7 +186,7 @@ GEM
       rails (>= 3.2)
     oj (3.7.12)
     os (1.1.1)
-    passenger (6.0.2)
+    passenger (6.0.15)
       rack
       rake (>= 0.8.1)
     piwik_analytics (1.0.2)
index e673c812102143d451fa48887b4cdf9d28e060a6..d11071272b28728038710969543c5ec908d4e958 100644 (file)
@@ -17,6 +17,6 @@ module VersionHelper
 
   # URL for browsing source code for the given version.
   def version_link_target version
-    "https://arvados.org/projects/arvados/repository/changes?rev=#{version.sub(/-.*/, "")}"
+    "https://dev.arvados.org/projects/arvados/repository/changes?rev=#{version.sub(/-.*/, "")}"
   end
 end
index 01a77cdd6188fd35ea409e9c8e90c7f5babb29b4..6e3d9e3437ad34abde3be6ef3166d8dc6bf20f02 100644 (file)
@@ -254,7 +254,7 @@ SPDX-License-Identifier: AGPL-3.0 %>
           <%= link_to "contact us", Rails.configuration.Workbench.ActivationContactLink %>.
           You should receive an email at the address you used to log in when
           your account is activated.  In the mean time, you can
-          <%= link_to "learn more about Arvados", "https://arvados.org/projects/arvados/wiki/Introduction_to_Arvados" %>,
+          <%= link_to "learn more about Arvados", "https://arvados.org/" %>,
           and <%= link_to "read the Arvados user guide", "http://doc.arvados.org/user" %>.
         </p>
         <p style="padding-bottom: 1em">
index d2c4372bce0de489954afa620fabd861f1b42948..98ce8aad141f1627a466ba87ccbe98da0fef9817 100644 (file)
@@ -37,7 +37,7 @@ class ReportIssueTest < ActionDispatch::IntegrationTest
       assert page.has_button?('Close'), 'No button - Close'
       assert page.has_no_button?('Send problem report'), 'Found button - Send problem report'
       history_links = all('a').select do |a|
-        a[:href] =~ %r!^https://arvados.org/projects/arvados/repository/changes\?rev=[0-9a-f]+$!
+        a[:href] =~ %r!^https://dev.arvados.org/projects/arvados/repository/changes\?rev=[0-9a-f]+$!
       end
       assert_operator(2, :<=, history_links.count,
                       "Should have found two links to revision history " +
index 5bae5f434c32b5eb86bf7c4e496dfb8f08839ba6..f0ae5df3f74eb3655db25988fcf5526fcd59414b 100644 (file)
@@ -32,7 +32,7 @@ ENV DEBIAN_FRONTEND noninteractive
 
 SHELL ["/bin/bash", "-c"]
 # Install dependencies.
-RUN yum -q -y install make automake gcc gcc-c++ libyaml-devel patch readline-devel zlib-devel libffi-devel openssl-devel bzip2 libtool bison sqlite-devel rpm-build git perl-ExtUtils-MakeMaker libattr-devel nss-devel libcurl-devel which tar unzip scl-utils centos-release-scl postgresql-devel fuse-devel xz-libs git wget pam-devel
+RUN yum -q -y install make automake gcc gcc-c++ libyaml-devel patch readline-devel zlib-devel libffi-devel openssl-devel bzip2 libtool bison sqlite-devel rpm-build git libattr-devel nss-devel libcurl-devel which tar unzip scl-utils centos-release-scl postgresql-devel fuse-devel xz-libs git wget pam-devel
 
 # Install RVM
 ADD generated/mpapis.asc /tmp/
index 7d9b5b6a37abb14185a693ff331859137d7f4082..905af1cbc62a76cc314ccba3dcdd9fa1145d2586 100755 (executable)
@@ -232,7 +232,6 @@ if test -z "$packages" ; then
         keep-rsync
         keep-block-check
         keep-web
-        libarvados-perl
         libpam-arvados-go
         python3-cwltest
         python3-arvados-fuse
index d4240d4f26b9120c3477aff6460a66aa3c169955..aded25b592a3a941e794d0223cd0f0c8ea5f412a 100755 (executable)
@@ -207,11 +207,6 @@ fi
 # Required due to CVE-2022-24765
 git config --global --add safe.directory /arvados
 
-# Perl packages
-debug_echo -e "\nPerl packages\n"
-
-handle_libarvados_perl
-
 # Ruby gems
 debug_echo -e "\nRuby gems\n"
 
index 47c5e2a39a22f98cc0ad18631e814ea4f4285c63..c2466faac0f38f66ade7a3e2d3c509a1e9acbbe8 100755 (executable)
@@ -696,40 +696,6 @@ handle_arvados_src () {
   )
 }
 
-# Usage: handle_libarvados_perl
-handle_libarvados_perl () {
-  if [[ -n "$ONLY_BUILD" ]] && [[ "$ONLY_BUILD" != "libarvados-perl" ]] ; then
-    debug_echo -e "Skipping build of libarvados-perl package."
-    return 0
-  fi
-  # The perl sdk subdirectory is so old that it has no tag in its history,
-  # which causes version_at_commit.sh to fail. Just rebuild it every time.
-  cd "$WORKSPACE"
-  libarvados_perl_version="$(version_from_git)"
-  cd "$WORKSPACE/sdk/perl"
-
-  cd $WORKSPACE/packages/$TARGET
-  test_package_presence libarvados-perl "$libarvados_perl_version"
-
-  if [[ "$?" == "0" ]]; then
-    cd "$WORKSPACE/sdk/perl"
-
-    if [[ -e Makefile ]]; then
-      make realclean >"$STDOUT_IF_DEBUG"
-    fi
-    find -maxdepth 1 \( -name 'MANIFEST*' -or -name "libarvados-perl*.$FORMAT" \) \
-        -delete
-    rm -rf install
-
-    perl Makefile.PL INSTALL_BASE=install >"$STDOUT_IF_DEBUG" && \
-        make install INSTALLDIRS=perl >"$STDOUT_IF_DEBUG" && \
-        fpm_build "$WORKSPACE/sdk/perl" install/lib/=/usr/share libarvados-perl \
-        dir "$libarvados_perl_version" install/man/=/usr/share/man \
-        "$WORKSPACE/apache-2.0.txt=/usr/share/doc/libarvados-perl/apache-2.0.txt" && \
-        mv --no-clobber libarvados-perl*.$FORMAT "$WORKSPACE/packages/$TARGET/"
-  fi
-}
-
 # Build python packages with a virtualenv built-in
 # Usage: fpm_build_virtualenv arvados-python-client sdk/python [deb|rpm] [amd64|arm64]
 fpm_build_virtualenv () {
index c8d1b7745f038a40f96b519551772c3fc6bbd78e..a5c7277580496cd1fe4748aed040ce2261bd3e95 100755 (executable)
@@ -58,7 +58,7 @@ defaults to $HOME/arvados-api-server if that directory exists.
 
 More information and background:
 
-https://arvados.org/projects/arvados/wiki/Running_tests
+https://dev.arvados.org/projects/arvados/wiki/Running_tests
 
 Available tests:
 
@@ -150,7 +150,6 @@ VENVDIR=
 VENV3DIR=
 PYTHONPATH=
 GEMHOME=
-PERLINSTALLBASE=
 R_LIBS=
 export LANG=en_US.UTF-8
 
@@ -232,14 +231,6 @@ sanity_checks() {
     echo -n 'nginx: '
     PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" nginx -v \
         || fatal "No nginx. Try: apt-get install nginx"
-    echo -n 'perl: '
-    perl -v | grep version \
-        || fatal "No perl. Try: apt-get install perl"
-    for mod in ExtUtils::MakeMaker JSON LWP Net::SSL; do
-        echo -n "perl $mod: "
-        perl -e "use $mod; print \"\$$mod::VERSION\\n\"" \
-            || fatal "No $mod. Try: apt-get install perl-modules libcrypt-ssleay-perl libjson-perl libwww-perl"
-    done
     echo -n 'gitolite: '
     which gitolite \
         || fatal "No gitolite. Try: apt-get install gitolite3"
@@ -621,7 +612,7 @@ initialize() {
     fi
 
     # Set up temporary install dirs (unless existing dirs were supplied)
-    for tmpdir in VENV3DIR GOPATH GEMHOME PERLINSTALLBASE R_LIBS
+    for tmpdir in VENV3DIR GOPATH GEMHOME R_LIBS
     do
         if [[ -z "${!tmpdir}" ]]; then
             eval "$tmpdir"="$temp/$tmpdir"
@@ -633,9 +624,6 @@ initialize() {
 
     rm -vf "${WORKSPACE}/tmp/*.log"
 
-    export PERLINSTALLBASE
-    export PERL5LIB="$PERLINSTALLBASE/lib/perl5${PERL5LIB:+:$PERL5LIB}"
-
     export R_LIBS
 
     export GOPATH
@@ -928,12 +916,6 @@ install_sdk/R() {
   fi
 }
 
-install_sdk/perl() {
-    cd "$WORKSPACE/sdk/perl" \
-        && perl Makefile.PL INSTALL_BASE="$PERLINSTALLBASE" \
-        && make install INSTALLDIRS=perl
-}
-
 install_sdk/cli() {
     install_gem arvados-cli sdk/cli
 }
@@ -1097,7 +1079,6 @@ install_deps() {
     do_install env
     do_install cmd/arvados-server go
     do_install sdk/cli
-    do_install sdk/perl
     do_install sdk/python pip "${VENV3DIR}/bin/"
     do_install sdk/ruby
     do_install services/api
@@ -1110,7 +1091,6 @@ install_all() {
     do_install doc
     do_install sdk/ruby
     do_install sdk/R
-    do_install sdk/perl
     do_install sdk/cli
     do_install services/login-sync
     for p in "${pythonstuff[@]}"
index aac4256b175d7d6e2d94f28f9a4b9baf4834917d..35ec4838878edcb11cf3722d5345120872da8317 100644 (file)
@@ -103,9 +103,6 @@ navbar:
       - sdk/java-v2/index.html.textile.liquid
       - sdk/java-v2/example.html.textile.liquid
       - sdk/java-v2/javadoc.html.textile.liquid
-    - Perl:
-      - sdk/perl/index.html.textile.liquid
-      - sdk/perl/example.html.textile.liquid
   api:
     - Concepts:
       - api/index.html.textile.liquid
index 74480e7dee5000c14815475ea74d5e65d301ac13..acc7f6fbe61fe7563bbf2a818c2af74c0c628b51 100644 (file)
@@ -25,11 +25,11 @@ Clusters:
   clsr1:
     RemoteClusters:
       clsr2:
-        Host: api.cluster2.com
+        Host: api.cluster2.example
         Proxy: true
        ActivateUsers: true
       clsr3:
-        Host: api.cluster3.com
+        Host: api.cluster3.example
         Proxy: true
        ActivateUsers: false
 </pre>
@@ -82,8 +82,10 @@ Clusters:
   clsr1:
     Login:
       TrustedClients:
-        "https://workbench.cluster2.com": {}
-        "https://workbench.cluster3.com": {}
+        "https://workbench.cluster2.example": {}
+        "https://workbench2.cluster2.example": {}
+        "https://workbench.cluster3.example": {}
+        "https://workbench2.cluster3.example": {}
 </pre>
 
 h2. Testing
@@ -91,7 +93,7 @@ h2. Testing
 Following the above example, let's suppose @clsr1@ is our "home cluster", that is to say, we use our @clsr1@ user account as our federated identity and both @clsr2@ and @clsr3@ remote clusters are set up to allow users from @clsr1@ and to auto-activate them. The first thing to do would be to log into a remote workbench using the local user token. This can be done following these steps:
 
 1. Log into the local workbench and get the user token
-2. Visit the remote workbench specifying the local user token by URL: @https://workbench.cluster2.com?api_token=token_from_clsr1@
+2. Visit the remote workbench specifying the local user token by URL: @https://workbench.cluster2.example?api_token=token_from_clsr1@
 3. You should now be logged into @clsr2@ with your account from @clsr1@
 
 To further test the federation setup, you can create a collection on @clsr2@, uploading some files and copying its UUID. Next, logged into a shell node on your home cluster you should be able to get that collection by running:
index 5fbbda2aef1ac171eb1d743327be2ef33c7561c4..5a88ba50d091f96b29c64108279a09e06e8e5259 100644 (file)
@@ -33,6 +33,10 @@ h2(#main). development main (as of 2022-10-31)
 
 "previous: Upgrading to 2.4.3":#v2_4_3
 
+h3. Google or OpenID Connect login restricted to trusted clients
+
+If you use OpenID Connect or Google login, and your cluster serves as the @LoginCluster@ in a federation _or_ your users log in from a web application other than the Workbench1 and Workbench2 @ExternalURL@ addresses in your configuration file, the additional web application URLs (e.g., the other clusters' Workbench addresses) must be listed explicitly in @Login.TrustedClients@, otherwise login will fail. Previously, login would succeed with a less-privileged token.
+
 h3. New keepstore S3 driver enabled by default
 
 A more actively maintained S3 client library is now enabled by default for keeepstore services. The previous driver is still available for use in case of unknown issues. To use the old driver, set @DriverParameters.UseAWSS3v2Driver@ to @false@ on the appropriate @Volumes@ config entries.
index 1ae8b6006405af727a4d4d22c4ffc99accfd53fa..698e355da626a561448b9ef2814025ded1054620 100644 (file)
@@ -36,14 +36,14 @@ Clusters:
   clsr1:
     RemoteClusters:
       clsr2:
-        Host: api.cluster2.com
+        Host: api.cluster2.example
         Proxy: true
       clsr3:
-        Host: api.cluster3.com
+        Host: api.cluster3.example
         Proxy: true
 </pre>
 
-In this example, the cluster @clsr1@ is configured to contact @api.cluster2.com@ for requests involving @clsr2@ and @api.cluster3.com@ for requests involving @clsr3@.
+In this example, the cluster @clsr1@ is configured to contact @api.cluster2.example@ for requests involving @clsr2@ and @api.cluster3.example@ for requests involving @clsr3@.
 
 h2(#identity). Identity
 
index e9866d510344da4e9a58ba7c8a5deee268540da1..746c1d40231bc5ad26b60da5736c564059a0e984 100644 (file)
@@ -46,8 +46,9 @@ Volumes are configured in the @Volumes@ section of the cluster configuration fil
           AccessKeyID: <span class="userinput">""</span>
           SecretAccessKey: <span class="userinput">""</span>
 
-          # Storage provider region. For Google Cloud Storage, use ""
-          # or omit.
+          # Storage provider region. If Endpoint is specified, the
+          # region determines the request signing method, and defaults
+          # to "us-east-1".
           Region: <span class="userinput">us-east-1</span>
 
           # Storage provider endpoint. For Amazon S3, use "" or
index 0bfe7ea72aa2a94380aad4c9b7180c2ecbf35aed..b733d03bfc37d5152afdb3a3d515a9e66e4e4d23 100644 (file)
@@ -17,6 +17,5 @@ This section documents language bindings for the "Arvados API":{{site.baseurl}}/
 * "R SDK":{{site.baseurl}}/sdk/R/index.html
 * "Ruby SDK":{{site.baseurl}}/sdk/ruby/index.html
 * "Java SDK v2":{{site.baseurl}}/sdk/java-v2/index.html
-* "Perl SDK":{{site.baseurl}}/sdk/perl/index.html
 
 Many Arvados Workbench pages, under the *Advanced* tab, provide examples of API and SDK use for accessing the current resource .
diff --git a/doc/sdk/perl/example.html.textile.liquid b/doc/sdk/perl/example.html.textile.liquid
deleted file mode 100644 (file)
index b51cfe4..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
----
-layout: default
-navsection: sdk
-navmenu: Perl
-title: "Examples"
-...
-{% comment %}
-Copyright (C) The Arvados Authors. All rights reserved.
-
-SPDX-License-Identifier: CC-BY-SA-3.0
-{% endcomment %}
-
-h2. Initialize SDK
-
-Set up an API client user agent:
-
-{% codeblock as perl %}
-use Arvados;
-my $arv = Arvados->new('apiVersion' => 'v1');
-{% endcodeblock %}
-
-The SDK retrieves the list of API methods from the server at run time. Therefore, the set of available methods is determined by the server version rather than the SDK version.
-
-h2. create
-
-Create an object:
-
-{% codeblock as perl %}
-my $test_link = $arv->{'links'}->{'create'}->execute('link' => { 'link_class' => 'test', 'name' => 'test' });
-{% endcodeblock %}
-
-h2. delete
-
-{% codeblock as perl %}
-my $some_user = $arv->{'collections'}->{'get'}->execute('uuid' => $collection_uuid);
-{% endcodeblock %}
-
-h2. get
-
-Retrieve an object by ID:
-
-{% codeblock as perl %}
-my $some_user = $arv->{'users'}->{'get'}->execute('uuid' => $current_user_uuid);
-{% endcodeblock %}
-
-Get the UUID of an object that was retrieved using the SDK:
-
-{% codeblock as perl %}
-my $current_user_uuid = $current_user->{'uuid'}
-{% endcodeblock %}
-
-h2. list
-
-Get a list of objects:
-
-{% codeblock as perl %}
-my $repos = $arv->{'repositories'}->{'list'}->execute;
-print ("UUID of first repo returned is ", $repos->{'items'}->[0], "\n");
-{% endcodeblock %}
-
-h2. update
-
-Update an object:
-
-{% codeblock as perl %}
-my $test_link = $arv->{'links'}->{'update'}->execute(
-        'uuid' => $test_link->{'uuid'},
-        'link' => { 'properties' => { 'foo' => 'bar' } });
-{% endcodeblock %}
-
-h2. Get current user
-
-Get the User object for the current user:
-
-{% codeblock as perl %}
-my $current_user = $arv->{'users'}->{'current'}->execute;
-{% endcodeblock %}
diff --git a/doc/sdk/perl/index.html.textile.liquid b/doc/sdk/perl/index.html.textile.liquid
deleted file mode 100644 (file)
index ba01352..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
----
-layout: default
-navsection: sdk
-navmenu: Perl
-title: "Installation"
-...
-{% comment %}
-Copyright (C) The Arvados Authors. All rights reserved.
-
-SPDX-License-Identifier: CC-BY-SA-3.0
-{% endcomment %}
-
-The Perl SDK provides a generic set of wrappers so you can make API calls easily.
-
-This is a legacy SDK.  It is no longer used or maintained regularly.
-
-h3. Installation
-
-h4. Option 1: Install from distribution packages
-
-First, "add the appropriate package repository for your distribution":{{ site.baseurl }}/install/install-manual-prerequisites.html#repos.
-
-On Debian-based systems:
-
-<notextile>
-<pre><code>~$ <span class="userinput">sudo apt-get install libjson-perl libio-socket-ssl-perl libwww-perl libipc-system-simple-perl libarvados-perl</code>
-</code></pre>
-</notextile>
-
-On Red Hat-based systems:
-
-<notextile>
-<pre><code>~$ <span class="userinput">sudo yum install perl-ExtUtils-MakeMaker perl-JSON perl-IO-Socket-SSL perl-Crypt-SSLeay perl-WWW-Curl libarvados-perl</code>
-</code></pre>
-</notextile>
-
-h4. Option 2: Install from source
-
-First, install dependencies from your distribution.  Refer to the package lists above, but don't install @libarvados-perl@.
-
-Then run the following:
-
-<notextile>
-<pre><code>~$ <span class="userinput">git clone https://github.com/arvados/arvados.git</span>
-~$ <span class="userinput">cd arvados/sdk/perl</span>
-~$ <span class="userinput">perl Makefile.PL</span>
-~$ <span class="userinput">sudo make install</span>
-</code></pre>
-</notextile>
-
-h3. Test installation
-
-If the SDK is installed, @perl -MArvados -e ''@ should produce no errors.
-
-If your @ARVADOS_API_HOST@ and @ARVADOS_API_TOKEN@ environment variables are set up correctly (see "api-tokens":{{site.baseurl}}/user/reference/api-tokens.html for details), the following test script should work:
-
-<notextile>
-<pre>~$ <code class="userinput">perl &lt;&lt;'EOF'
-use Arvados;
-my $arv = Arvados-&gt;new('apiVersion' => 'v1');
-my $me = $arv-&gt;{'users'}-&gt;{'current'}-&gt;execute;
-print ("arvados.v1.users.current.full_name = '", $me-&gt;{'full_name'}, "'\n");
-EOF</code>
-arvados.v1.users.current.full_name = 'Your Name'
-</pre>
-</notextile>
index 5e46c290da6424f15870ac4bb6cf03731e21e338..0246cb88d5736e158bb1f502d91423b7b7072832 100644 (file)
@@ -878,16 +878,28 @@ Clusters:
       # by going through login again.
       IssueTrustedTokens: true
 
-      # When the token is returned to a client, the token itself may
-      # be restricted from viewing/creating other tokens based on whether
-      # the client is "trusted" or not.  The local Workbench1 and
-      # Workbench2 are trusted by default, but if this is a
-      # LoginCluster, you probably want to include the other Workbench
-      # instances in the federation in this list.
+      # Origins (scheme://host[:port]) of clients trusted to receive
+      # new tokens via login process.  The ExternalURLs of the local
+      # Workbench1 and Workbench2 are trusted implicitly and do not
+      # need to be listed here.  If this is a LoginCluster, you
+      # probably want to include the other Workbench instances in the
+      # federation in this list.
+      #
+      # Example:
+      #
+      # TrustedClients:
+      #   "https://workbench.other-cluster.example": {}
+      #   "https://workbench2.other-cluster.example": {}
       TrustedClients:
-        SAMPLE:
-          "https://workbench.federate1.example": {}
-          "https://workbench.federate2.example": {}
+        SAMPLE: {}
+
+      # Treat any origin whose host part is "localhost" or a private
+      # IP address (e.g., http://10.0.0.123:3000/) as if it were
+      # listed in TrustedClients.
+      #
+      # Intended only for test/development use. Not appropriate for
+      # production use.
+      TrustPrivateNetworks: false
 
     Git:
       # Path to git or gitolite-shell executable. Each authenticated
@@ -1016,7 +1028,7 @@ Clusters:
 
       # Extra RAM to reserve on the node, in addition to
       # the amount specified in the container's RuntimeConstraints
-      ReserveExtraRAM: 256MiB
+      ReserveExtraRAM: 550MiB
 
       # Minimum time between two attempts to run the same container
       MinRetryPeriod: 0s
index e7cf094eb02b63f8a613b881696940e2cec505ab..6352406e90e95dc255d9eb43ff1ca13f0e721fd1 100644 (file)
@@ -193,6 +193,7 @@ var whitelist = map[string]bool{
        "Login.Test.Users":                                    false,
        "Login.TokenLifetime":                                 false,
        "Login.TrustedClients":                                false,
+       "Login.TrustPrivateNetworks":                          false,
        "Mail":                                                true,
        "Mail.EmailFrom":                                      false,
        "Mail.IssueReporterEmailFrom":                         false,
@@ -264,6 +265,7 @@ var whitelist = map[string]bool{
        "Workbench.ApplicationMimetypesWithViewIcon.*":        true,
        "Workbench.ArvadosDocsite":                            true,
        "Workbench.ArvadosPublicDataDocURL":                   true,
+       "Workbench.BannerURL":                                 true,
        "Workbench.DefaultOpenIdPrefix":                       false,
        "Workbench.DisableSharingURLsUI":                      true,
        "Workbench.EnableGettingStartedPopup":                 true,
@@ -291,7 +293,6 @@ var whitelist = map[string]bool{
        "Workbench.UserProfileFormFields.*.*.*":               true,
        "Workbench.UserProfileFormMessage":                    true,
        "Workbench.WelcomePageHTML":                           true,
-       "Workbench.BannerURL":                                 true,
 }
 
 func redactUnsafe(m map[string]interface{}, mPrefix, lookupPrefix string) error {
index 039caac574e479bdad181dfeed745dd3255640cf..329066d1dcf767ecb03ae13d803858ff715747a0 100644 (file)
@@ -65,13 +65,13 @@ func (conn *Conn) generated_CollectionList(ctx context.Context, options arvados.
 // Call fn on one or more local/remote backends if opts indicates a
 // federation-wide list query, i.e.:
 //
-// * There is at least one filter of the form
-//   ["uuid","in",[a,b,c,...]] or ["uuid","=",a]
+//   - There is at least one filter of the form
+//     ["uuid","in",[a,b,c,...]] or ["uuid","=",a]
 //
-// * One or more of the supplied UUIDs (a,b,c,...) has a non-local
-//   prefix.
+//   - One or more of the supplied UUIDs (a,b,c,...) has a non-local
+//     prefix.
 //
-// * There are no other filters
+//   - There are no other filters
 //
 // (If opts doesn't indicate a federation-wide list query, fn is just
 // called once with the local backend.)
@@ -79,29 +79,29 @@ func (conn *Conn) generated_CollectionList(ctx context.Context, options arvados.
 // fn is called more than once only if the query meets the following
 // restrictions:
 //
-// * Count=="none"
+//   - Count=="none"
 //
-// * Limit<0
+//   - Limit<0
 //
-// * len(Order)==0
+//   - len(Order)==0
 //
-// * Each filter is either "uuid = ..." or "uuid in [...]".
+//   - Each filter is either "uuid = ..." or "uuid in [...]".
 //
-// * The maximum possible response size (total number of objects that
-//   could potentially be matched by all of the specified filters)
-//   exceeds the local cluster's response page size limit.
+//   - The maximum possible response size (total number of objects
+//     that could potentially be matched by all of the specified
+//     filters) exceeds the local cluster's response page size limit.
 //
 // If the query involves multiple backends but doesn't meet these
 // restrictions, an error is returned without calling fn.
 //
 // Thus, the caller can assume that either:
 //
-// * splitListRequest() returns an error, or
+//   - splitListRequest() returns an error, or
 //
-// * fn is called exactly once, or
+//   - fn is called exactly once, or
 //
-// * fn is called more than once, with options that satisfy the above
-//   restrictions.
+//   - fn is called more than once, with options that satisfy the above
+//     restrictions.
 //
 // Each call to fn indicates a single (local or remote) backend and a
 // corresponding options argument suitable for sending to that
index c05ebfce69820b3be781a3d18be8a591aaa94eb2..e1114bf7eb21fd6752598ee7f31fe08199f9ef74 100644 (file)
@@ -41,25 +41,27 @@ func (s *LoginSuite) TestDeferToLoginCluster(c *check.C) {
 }
 
 func (s *LoginSuite) TestLogout(c *check.C) {
+       otherOrigin := arvados.URL{Scheme: "https", Host: "app.example.com", Path: "/"}
+       otherURL := "https://app.example.com/foo"
        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.TrustedClients = map[arvados.URL]struct{}{otherOrigin: {}}
        s.addHTTPRemote(c, "zhome", &arvadostest.APIStub{})
        s.cluster.Login.LoginCluster = "zhome"
        // s.fed is already set by SetUpTest, but we need to
        // reinitialize with the above config changes.
        s.fed = New(s.cluster, nil)
 
-       returnTo := "https://app.example.com/foo?bar"
        for _, trial := range []struct {
                token    string
                returnTo string
                target   string
        }{
                {token: "", returnTo: "", target: s.cluster.Services.Workbench2.ExternalURL.String()},
-               {token: "", returnTo: returnTo, target: returnTo},
-               {token: "zzzzzzzzzzzzzzzzzzzzz", returnTo: returnTo, target: returnTo},
-               {token: "v2/zzzzz-aaaaa-aaaaaaaaaaaaaaa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", returnTo: returnTo, target: returnTo},
-               {token: "v2/zhome-aaaaa-aaaaaaaaaaaaaaa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", returnTo: returnTo, target: "http://" + s.cluster.RemoteClusters["zhome"].Host + "/logout?" + url.Values{"return_to": {returnTo}}.Encode()},
+               {token: "", returnTo: otherURL, target: otherURL},
+               {token: "zzzzzzzzzzzzzzzzzzzzz", returnTo: otherURL, target: otherURL},
+               {token: "v2/zzzzz-aaaaa-aaaaaaaaaaaaaaa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", returnTo: otherURL, target: otherURL},
+               {token: "v2/zhome-aaaaa-aaaaaaaaaaaaaaa/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", returnTo: otherURL, target: "http://" + s.cluster.RemoteClusters["zhome"].Host + "/logout?" + url.Values{"return_to": {otherURL}}.Encode()},
        } {
                c.Logf("trial %#v", trial)
                ctx := s.ctx
index a240b195ea9ff583eede71720ab8c9dfdf3c3798..1af3ba3626c94dc517fd657270a24ed067eaace5 100644 (file)
@@ -272,15 +272,16 @@ func (s *HandlerSuite) TestProxyNotFound(c *check.C) {
 }
 
 func (s *HandlerSuite) TestLogoutGoogle(c *check.C) {
+       s.cluster.Services.Workbench2.ExternalURL = arvados.URL{Scheme: "https", Host: "wb2.example", Path: "/"}
        s.cluster.Login.Google.Enable = true
        s.cluster.Login.Google.ClientID = "test"
-       req := httptest.NewRequest("GET", "https://0.0.0.0:1/logout?return_to=https://example.com/foo", nil)
+       req := httptest.NewRequest("GET", "https://0.0.0.0:1/logout?return_to=https://wb2.example/", nil)
        resp := httptest.NewRecorder()
        s.handler.ServeHTTP(resp, req)
        if !c.Check(resp.Code, check.Equals, http.StatusFound) {
                c.Log(resp.Body.String())
        }
-       c.Check(resp.Header().Get("Location"), check.Equals, "https://example.com/foo")
+       c.Check(resp.Header().Get("Location"), check.Equals, "https://wb2.example/")
 }
 
 func (s *HandlerSuite) TestValidateV1APIToken(c *check.C) {
index 5a3faa72790899aa69ba4408fbf47df7997c27af..5b6964de00d105ec89938e3c2f4e556688fd4722 100644 (file)
@@ -8,6 +8,7 @@ import (
        "context"
        "encoding/json"
        "fmt"
+       "net"
        "net/http"
        "os"
        "sync"
@@ -165,6 +166,26 @@ func (conn *Conn) UserAuthenticate(ctx context.Context, opts arvados.UserAuthent
        return conn.loginController.UserAuthenticate(ctx, opts)
 }
 
+var privateNetworks = func() (nets []*net.IPNet) {
+       for _, s := range []string{
+               "127.0.0.0/8",
+               "10.0.0.0/8",
+               "172.16.0.0/12",
+               "192.168.0.0/16",
+               "169.254.0.0/16",
+               "::1/128",
+               "fe80::/10",
+               "fc00::/7",
+       } {
+               _, n, err := net.ParseCIDR(s)
+               if err != nil {
+                       panic(fmt.Sprintf("privateNetworks: %q: %s", s, err))
+               }
+               nets = append(nets, n)
+       }
+       return
+}()
+
 func httpErrorf(code int, format string, args ...interface{}) error {
        return httpserver.ErrorWithStatus(fmt.Errorf(format, args...), code)
 }
index 2b20491a04a426f50dbb354b9c8e0a7e86f833ea..a1ac2c55b02657462ce1c78d860df4a4fdc94186 100644 (file)
@@ -10,6 +10,7 @@ import (
        "encoding/json"
        "errors"
        "fmt"
+       "net"
        "net/http"
        "net/url"
        "strings"
@@ -162,3 +163,39 @@ func (conn *Conn) CreateAPIClientAuthorization(ctx context.Context, rootToken st
        }
        return
 }
+
+func validateLoginRedirectTarget(cluster *arvados.Cluster, returnTo string) error {
+       u, err := url.Parse(returnTo)
+       if err != nil {
+               return err
+       }
+       u, err = u.Parse("/")
+       if err != nil {
+               return err
+       }
+       if u.Port() == "80" && u.Scheme == "http" {
+               u.Host = u.Hostname()
+       } else if u.Port() == "443" && u.Scheme == "https" {
+               u.Host = u.Hostname()
+       }
+       if _, ok := cluster.Login.TrustedClients[arvados.URL(*u)]; ok {
+               return nil
+       }
+       if u.String() == cluster.Services.Workbench1.ExternalURL.String() ||
+               u.String() == cluster.Services.Workbench2.ExternalURL.String() {
+               return nil
+       }
+       if cluster.Login.TrustPrivateNetworks {
+               if u.Hostname() == "localhost" {
+                       return nil
+               }
+               if ip := net.ParseIP(u.Hostname()); len(ip) > 0 {
+                       for _, n := range privateNetworks {
+                               if n.Contains(ip) {
+                                       return nil
+                               }
+                       }
+               }
+       }
+       return fmt.Errorf("requesting site is not listed in TrustedClients config")
+}
index 6d6f80f39c70ac5427578ddd6ed5eb3e78b6a136..05e5e243b99d574fa4956e41cfcaee8c24cbe5ab 100644 (file)
@@ -116,6 +116,9 @@ func (ctrl *oidcLoginController) Login(ctx context.Context, opts arvados.LoginOp
                if opts.ReturnTo == "" {
                        return loginError(errors.New("missing return_to parameter"))
                }
+               if err := validateLoginRedirectTarget(ctrl.Parent.cluster, opts.ReturnTo); err != nil {
+                       return loginError(fmt.Errorf("invalid return_to parameter: %s", err))
+               }
                state := ctrl.newOAuth2State([]byte(ctrl.Cluster.SystemRootToken), opts.Remote, opts.ReturnTo)
                var authparams []oauth2.AuthCodeOption
                for k, v := range ctrl.AuthParams {
index b9f0f56e058482eb74eb527b038136e56979feff..0fe3bdf7f6b684652cad9c71f3c0a63fba15b925 100644 (file)
@@ -42,6 +42,7 @@ type OIDCLoginSuite struct {
        cluster      *arvados.Cluster
        localdb      *Conn
        railsSpy     *arvadostest.Proxy
+       trustedURL   *arvados.URL
        fakeProvider *arvadostest.OIDCProvider
 }
 
@@ -53,6 +54,8 @@ func (s *OIDCLoginSuite) TearDownSuite(c *check.C) {
 }
 
 func (s *OIDCLoginSuite) SetUpTest(c *check.C) {
+       s.trustedURL = &arvados.URL{Scheme: "https", Host: "app.example.com", Path: "/"}
+
        s.fakeProvider = arvadostest.NewOIDCProvider(c)
        s.fakeProvider.AuthEmail = "active-user@arvados.local"
        s.fakeProvider.AuthEmailVerified = true
@@ -70,6 +73,7 @@ func (s *OIDCLoginSuite) SetUpTest(c *check.C) {
        s.cluster.Login.Google.Enable = true
        s.cluster.Login.Google.ClientID = "test%client$id"
        s.cluster.Login.Google.ClientSecret = "test#client/secret"
+       s.cluster.Login.TrustedClients = map[arvados.URL]struct{}{*s.trustedURL: {}}
        s.cluster.Users.PreferDomainForUsername = "PreferDomainForUsername.example.com"
        s.fakeProvider.ValidClientID = "test%client$id"
        s.fakeProvider.ValidClientSecret = "test#client/secret"
@@ -88,9 +92,26 @@ func (s *OIDCLoginSuite) TearDownTest(c *check.C) {
 }
 
 func (s *OIDCLoginSuite) TestGoogleLogout(c *check.C) {
+       s.cluster.Login.TrustedClients[arvados.URL{Scheme: "https", Host: "foo.example", Path: "/"}] = struct{}{}
+       s.cluster.Login.TrustPrivateNetworks = false
+
        resp, err := s.localdb.Logout(context.Background(), arvados.LogoutOptions{ReturnTo: "https://foo.example.com/bar"})
+       c.Check(err, check.NotNil)
+       c.Check(resp.RedirectLocation, check.Equals, "")
+
+       resp, err = s.localdb.Logout(context.Background(), arvados.LogoutOptions{ReturnTo: "https://127.0.0.1/bar"})
+       c.Check(err, check.NotNil)
+       c.Check(resp.RedirectLocation, check.Equals, "")
+
+       resp, err = s.localdb.Logout(context.Background(), arvados.LogoutOptions{ReturnTo: "https://foo.example/bar"})
+       c.Check(err, check.IsNil)
+       c.Check(resp.RedirectLocation, check.Equals, "https://foo.example/bar")
+
+       s.cluster.Login.TrustPrivateNetworks = true
+
+       resp, err = s.localdb.Logout(context.Background(), arvados.LogoutOptions{ReturnTo: "https://192.168.1.1/bar"})
        c.Check(err, check.IsNil)
-       c.Check(resp.RedirectLocation, check.Equals, "https://foo.example.com/bar")
+       c.Check(resp.RedirectLocation, check.Equals, "https://192.168.1.1/bar")
 }
 
 func (s *OIDCLoginSuite) TestGoogleLogin_Start_Bogus(c *check.C) {
@@ -118,6 +139,13 @@ func (s *OIDCLoginSuite) TestGoogleLogin_Start(c *check.C) {
        }
 }
 
+func (s *OIDCLoginSuite) TestGoogleLogin_UnknownClient(c *check.C) {
+       resp, err := s.localdb.Login(context.Background(), arvados.LoginOptions{ReturnTo: "https://bad-app.example.com/foo?bar"})
+       c.Check(err, check.IsNil)
+       c.Check(resp.RedirectLocation, check.Equals, "")
+       c.Check(resp.HTML.String(), check.Matches, `(?ms).*requesting site is not listed in TrustedClients.*`)
+}
+
 func (s *OIDCLoginSuite) TestGoogleLogin_InvalidCode(c *check.C) {
        state := s.startLogin(c)
        resp, err := s.localdb.Login(context.Background(), arvados.LoginOptions{
@@ -613,10 +641,14 @@ func (s *OIDCLoginSuite) startLogin(c *check.C, checks ...func(url.Values)) (sta
        // the provider, just grab state from the redirect URL.
        resp, err := s.localdb.Login(context.Background(), arvados.LoginOptions{ReturnTo: "https://app.example.com/foo?bar"})
        c.Check(err, check.IsNil)
+       c.Check(resp.HTML.String(), check.Not(check.Matches), `(?ms).*error:.*`)
        target, err := url.Parse(resp.RedirectLocation)
        c.Check(err, check.IsNil)
        state = target.Query().Get("state")
-       c.Check(state, check.Not(check.Equals), "")
+       if !c.Check(state, check.Not(check.Equals), "") {
+               c.Logf("Redirect target: %q", target)
+               c.Logf("HTML: %q", resp.HTML)
+       }
        for _, fn := range checks {
                fn(target.Query())
        }
@@ -624,6 +656,56 @@ func (s *OIDCLoginSuite) startLogin(c *check.C, checks ...func(url.Values)) (sta
        return
 }
 
+func (s *OIDCLoginSuite) TestValidateLoginRedirectTarget(c *check.C) {
+       for _, trial := range []struct {
+               permit       bool
+               trustPrivate bool
+               url          string
+       }{
+               // wb1, wb2 => accept
+               {true, false, s.cluster.Services.Workbench1.ExternalURL.String()},
+               {true, false, s.cluster.Services.Workbench2.ExternalURL.String()},
+               // explicitly listed host => accept
+               {true, false, "https://app.example.com/"},
+               {true, false, "https://app.example.com:443/foo?bar=baz"},
+               // non-listed hostname => deny (regardless of TrustPrivateNetworks)
+               {false, false, "https://bad.example/"},
+               {false, true, "https://bad.example/"},
+               // non-listed non-private IP addr => deny (regardless of TrustPrivateNetworks)
+               {false, true, "https://1.2.3.4/"},
+               {false, true, "https://1.2.3.4/"},
+               {false, true, "https://[ab::cd]:1234/"},
+               // localhost or non-listed private IP addr => accept only if TrustPrivateNetworks is set
+               {false, false, "https://localhost/"},
+               {true, true, "https://localhost/"},
+               {false, false, "https://[10.9.8.7]:80/foo"},
+               {true, true, "https://[10.9.8.7]:80/foo"},
+               {false, false, "https://[::1]:80/foo"},
+               {true, true, "https://[::1]:80/foo"},
+               {true, true, "http://192.168.1.1/"},
+               {true, true, "http://172.17.2.0/"},
+               // bad url => deny
+               {false, true, "https://10.1.1.1:blorp/foo"},        // non-numeric port
+               {false, true, "https://app.example.com:blorp/foo"}, // non-numeric port
+               {false, true, "https://]:443"},
+               {false, true, "https://"},
+               {false, true, "https:"},
+               {false, true, ""},
+               // explicitly listed host but different port, protocol, or user/pass => deny
+               {false, true, "http://app.example.com/"},
+               {false, true, "http://app.example.com:443/"},
+               {false, true, "https://app.example.com:80/"},
+               {false, true, "https://app.example.com:4433/"},
+               {false, true, "https://u:p@app.example.com:443/foo?bar=baz"},
+       } {
+               c.Logf("trial %+v", trial)
+               s.cluster.Login.TrustPrivateNetworks = trial.trustPrivate
+               err := validateLoginRedirectTarget(s.cluster, trial.url)
+               c.Check(err == nil, check.Equals, trial.permit)
+       }
+
+}
+
 func getCallbackAuthInfo(c *check.C, railsSpy *arvadostest.Proxy) (authinfo rpc.UserSessionAuthInfo) {
        for _, dump := range railsSpy.RequestDumps {
                c.Logf("spied request: %q", dump)
index 51c2416f59bcb7c2c7f55e9425489ae003653ee5..8717617889bcd8d8fbf5a3e8e43c4d6852834a70 100644 (file)
@@ -103,7 +103,8 @@ func (s *TestUserSuite) TestLoginForm(c *check.C) {
 }
 
 func (s *TestUserSuite) TestExpireTokenOnLogout(c *check.C) {
-       returnTo := "https://localhost:12345/logout"
+       s.cluster.Login.TrustPrivateNetworks = true
+       returnTo := "https://[::1]:12345/logout"
        for _, trial := range []struct {
                requestToken      string
                expiringTokenUUID string
index e1603f14485eb0a4f664a2a00b080a1497c64d2a..04e7681ad7bef728bb11e5c745c2b8391094b2d5 100644 (file)
@@ -33,6 +33,8 @@ func logout(ctx context.Context, cluster *arvados.Cluster, opts arvados.LogoutOp
                } else {
                        target = cluster.Services.Workbench1.ExternalURL.String()
                }
+       } else if err := validateLoginRedirectTarget(cluster, target); err != nil {
+               return arvados.LogoutResponse{}, httpserver.ErrorWithStatus(fmt.Errorf("invalid return_to parameter: %s", err), http.StatusBadRequest)
        }
        return arvados.LogoutResponse{RedirectLocation: target}, nil
 }
index 7c7643bfc7622fc8c876eba9c2e01d9203385074..8cc63dc208c8c48e3afc47a1dab1435b11a12996 100644 (file)
@@ -110,7 +110,12 @@ func ChooseInstanceType(cc *arvados.Cluster, ctr *arvados.Container) (best arvad
 
        needRAM := ctr.RuntimeConstraints.RAM + ctr.RuntimeConstraints.KeepCacheRAM
        needRAM += int64(cc.Containers.ReserveExtraRAM)
-       needRAM += int64(cc.Containers.LocalKeepBlobBuffersPerVCPU * needVCPUs * (1 << 26))
+       if cc.Containers.LocalKeepBlobBuffersPerVCPU > 0 {
+               // + 200 MiB for keepstore process + 10% for GOGC=10
+               needRAM += 220 << 20
+               // + 64 MiB for each blob buffer + 10% for GOGC=10
+               needRAM += int64(cc.Containers.LocalKeepBlobBuffersPerVCPU * needVCPUs * (1 << 26) * 11 / 10)
+       }
        needRAM = (needRAM * 100) / int64(100-discountConfiguredRAMPercent)
 
        ok := false
index eb3648e8ac13265995bf98b040c47106ea380ea3..86bfbec7b629dc731e309740346dec85a24ae2d7 100644 (file)
@@ -80,7 +80,10 @@ func (*NodeSizeSuite) TestChoose(c *check.C) {
                        "costly": {Price: 4.4, RAM: 4000000000, VCPUs: 8, Scratch: 2 * GiB, Name: "costly"},
                },
        } {
-               best, err := ChooseInstanceType(&arvados.Cluster{InstanceTypes: menu, Containers: arvados.ContainersConfig{ReserveExtraRAM: 268435456}}, &arvados.Container{
+               best, err := ChooseInstanceType(&arvados.Cluster{InstanceTypes: menu, Containers: arvados.ContainersConfig{
+                       LocalKeepBlobBuffersPerVCPU: 1,
+                       ReserveExtraRAM:             268435456,
+               }}, &arvados.Container{
                        Mounts: map[string]arvados.Mount{
                                "/tmp": {Kind: "tmp", Capacity: 2 * int64(GiB)},
                        },
@@ -98,7 +101,30 @@ func (*NodeSizeSuite) TestChoose(c *check.C) {
        }
 }
 
-func (*NodeSizeSuite) TestChoosePreemptable(c *check.C) {
+func (*NodeSizeSuite) TestChooseWithBlobBuffersOverhead(c *check.C) {
+       menu := map[string]arvados.InstanceType{
+               "nearly": {Price: 2.2, RAM: 4000000000, VCPUs: 4, Scratch: 2 * GiB, Name: "small"},
+               "best":   {Price: 3.3, RAM: 8000000000, VCPUs: 4, Scratch: 2 * GiB, Name: "best"},
+               "costly": {Price: 4.4, RAM: 12000000000, VCPUs: 8, Scratch: 2 * GiB, Name: "costly"},
+       }
+       best, err := ChooseInstanceType(&arvados.Cluster{InstanceTypes: menu, Containers: arvados.ContainersConfig{
+               LocalKeepBlobBuffersPerVCPU: 16, // 1 GiB per vcpu => 2 GiB
+               ReserveExtraRAM:             268435456,
+       }}, &arvados.Container{
+               Mounts: map[string]arvados.Mount{
+                       "/tmp": {Kind: "tmp", Capacity: 2 * int64(GiB)},
+               },
+               RuntimeConstraints: arvados.RuntimeConstraints{
+                       VCPUs:        2,
+                       RAM:          987654321,
+                       KeepCacheRAM: 123456789,
+               },
+       })
+       c.Check(err, check.IsNil)
+       c.Check(best.Name, check.Equals, "best")
+}
+
+func (*NodeSizeSuite) TestChoosePreemptible(c *check.C) {
        menu := map[string]arvados.InstanceType{
                "costly":      {Price: 4.4, RAM: 4000000000, VCPUs: 8, Scratch: 2 * GiB, Preemptible: true, Name: "costly"},
                "almost best": {Price: 2.2, RAM: 2000000000, VCPUs: 4, Scratch: 2 * GiB, Name: "almost best"},
index e02c3743e71809a40053983d1e753e238577f2ec..06b07ec6da060f982d6be87d59e16eb44038d482 100644 (file)
@@ -155,17 +155,14 @@ func (inst *installCommand) RunCommand(prog string, args []string, stdin io.Read
                        "default-jre-headless",
                        "gettext",
                        "libattr1-dev",
-                       "libcrypt-ssleay-perl",
                        "libfuse-dev",
                        "libgbm1", // cypress / workbench2 tests
                        "libgnutls28-dev",
-                       "libjson-perl",
                        "libpam-dev",
                        "libpcre3-dev",
                        "libpq-dev",
                        "libreadline-dev",
                        "libssl-dev",
-                       "libwww-perl",
                        "libxml2-dev",
                        "libxslt1-dev",
                        "linkchecker",
@@ -206,11 +203,11 @@ func (inst *installCommand) RunCommand(prog string, args []string, stdin io.Read
                }
                switch {
                case osv.Debian && osv.Major >= 11:
-                       pkgs = append(pkgs, "g++", "libcurl4", "libcurl4-openssl-dev", "perl-modules-5.32")
+                       pkgs = append(pkgs, "g++", "libcurl4", "libcurl4-openssl-dev")
                case osv.Debian && osv.Major >= 10:
-                       pkgs = append(pkgs, "g++", "libcurl4", "libcurl4-openssl-dev", "perl-modules")
+                       pkgs = append(pkgs, "g++", "libcurl4", "libcurl4-openssl-dev")
                case osv.Debian || osv.Ubuntu:
-                       pkgs = append(pkgs, "g++", "libcurl3", "libcurl3-openssl-dev", "perl-modules")
+                       pkgs = append(pkgs, "g++", "libcurl3", "libcurl3-openssl-dev")
                case osv.Centos:
                        pkgs = append(pkgs, "gcc", "gcc-c++", "libcurl-devel", "postgresql-devel")
                }
index e51e719066cbdf2b3f71d245eea9a7fc326fcbc3..a09a941ffb0333db432d4475801f9e5d0d5142cd 100644 (file)
@@ -45,6 +45,7 @@ func (s *suite) SetUpTest(c *check.C) {
        c.Assert(err, check.IsNil)
        cluster, err := cfg.GetCluster("")
        c.Assert(err, check.IsNil)
+       cluster.Containers.ReserveExtraRAM = 256 << 20
        cluster.Containers.CloudVMs.PollInterval = arvados.Duration(time.Second / 4)
        cluster.Containers.MinRetryPeriod = arvados.Duration(time.Second / 4)
        cluster.InstanceTypes = arvados.InstanceTypeMap{
index 64b7fab8d2267b4f9d4f96cbdad15954965c58db..2871356e9827059352026432082c5fcdee2f3fce 100644 (file)
@@ -200,11 +200,12 @@ type Cluster struct {
                        Enable bool
                        Users  map[string]TestUser
                }
-               LoginCluster       string
-               RemoteTokenRefresh Duration
-               TokenLifetime      Duration
-               TrustedClients     map[string]struct{}
-               IssueTrustedTokens bool
+               LoginCluster         string
+               RemoteTokenRefresh   Duration
+               TokenLifetime        Duration
+               TrustedClients       map[URL]struct{}
+               TrustPrivateNetworks bool
+               IssueTrustedTokens   bool
        }
        Mail struct {
                MailchimpAPIKey                string
@@ -395,7 +396,7 @@ func (su *URL) UnmarshalText(text []byte) error {
 }
 
 func (su URL) MarshalText() ([]byte, error) {
-       return []byte(fmt.Sprintf("%s", (*url.URL)(&su).String())), nil
+       return []byte(su.String()), nil
 }
 
 func (su URL) String() string {
diff --git a/sdk/perl/.gitignore b/sdk/perl/.gitignore
deleted file mode 100644 (file)
index 7c32f55..0000000
+++ /dev/null
@@ -1 +0,0 @@
-install
diff --git a/sdk/perl/Makefile.PL b/sdk/perl/Makefile.PL
deleted file mode 100644 (file)
index ec903f3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#! /usr/bin/perl
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-use strict;
-
-use ExtUtils::MakeMaker;
-
-WriteMakefile(
-    NAME            => 'Arvados',
-    VERSION_FROM    => 'lib/Arvados.pm',
-    PREREQ_PM       => {
-        'JSON'     => 0,
-        'LWP'      => 0,
-        'Net::SSL' => 0,
-    },
-);
diff --git a/sdk/perl/lib/Arvados.pm b/sdk/perl/lib/Arvados.pm
deleted file mode 100644 (file)
index 9eb04b4..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-=head1 NAME
-
-Arvados -- client library for Arvados services
-
-=head1 SYNOPSIS
-
-  use Arvados;
-  $arv = Arvados->new(apiHost => 'arvados.local');
-
-  my $instances = $arv->{'pipeline_instances'}->{'list'}->execute();
-  print "UUID is ", $instances->{'items'}->[0]->{'uuid'}, "\n";
-
-  $uuid = 'eiv0u-arx5y-2c5ovx43zw90gvh';
-  $instance = $arv->{'pipeline_instances'}->{'get'}->execute('uuid' => $uuid);
-  print "ETag is ", $instance->{'etag'}, "\n";
-
-  $instance->{'active'} = 1;
-  $instance->{'name'} = '';
-  $instance->save();
-  print "ETag is ", $instance->{'etag'}, "\n";
-
-=head1 METHODS
-
-=head2 new()
-
- my $whc = Arvados->new( %OPTIONS );
-
-Set up a client and retrieve the schema from the server.
-
-=head3 Options
-
-=over
-
-=item apiHost
-
-Hostname of API discovery service. Default: C<ARVADOS_API_HOST>
-environment variable, or C<arvados>
-
-=item apiProtocolScheme
-
-Protocol scheme. Default: C<ARVADOS_API_PROTOCOL_SCHEME> environment
-variable, or C<https>
-
-=item authToken
-
-Authorization token. Default: C<ARVADOS_API_TOKEN> environment variable
-
-=item apiService
-
-Default C<arvados>
-
-=item apiVersion
-
-Default C<v1>
-
-=back
-
-=cut
-
-package Arvados;
-
-use Net::SSL (); # From Crypt-SSLeay
-BEGIN {
-  $Net::HTTPS::SSL_SOCKET_CLASS = "Net::SSL"; # Force use of Net::SSL
-}
-
-use JSON;
-use Carp;
-use Arvados::ResourceAccessor;
-use Arvados::ResourceMethod;
-use Arvados::ResourceProxy;
-use Arvados::ResourceProxyList;
-use Arvados::Request;
-use Data::Dumper;
-
-$Arvados::VERSION = 0.1;
-
-sub new
-{
-    my $class = shift;
-    my %self = @_;
-    my $self = \%self;
-    bless ($self, $class);
-    return $self->build(@_);
-}
-
-sub build
-{
-    my $self = shift;
-
-    $config = load_config_file("$ENV{HOME}/.config/arvados/settings.conf");
-
-    $self->{'authToken'} ||=
-       $ENV{ARVADOS_API_TOKEN} || $config->{ARVADOS_API_TOKEN};
-
-    $self->{'apiHost'} ||=
-       $ENV{ARVADOS_API_HOST} || $config->{ARVADOS_API_HOST};
-
-    $self->{'noVerifyHostname'} ||=
-       $ENV{ARVADOS_API_HOST_INSECURE};
-
-    $self->{'apiProtocolScheme'} ||=
-       $ENV{ARVADOS_API_PROTOCOL_SCHEME} ||
-       $config->{ARVADOS_API_PROTOCOL_SCHEME};
-
-    $self->{'ua'} = new Arvados::Request;
-
-    my $host = $self->{'apiHost'} || 'arvados';
-    my $service = $self->{'apiService'} || 'arvados';
-    my $version = $self->{'apiVersion'} || 'v1';
-    my $scheme = $self->{'apiProtocolScheme'} || 'https';
-    my $uri = "$scheme://$host/discovery/v1/apis/$service/$version/rest";
-    my $r = $self->new_request;
-    $r->set_uri($uri);
-    $r->set_method("GET");
-    $r->process_request();
-    my $data, $headers;
-    my ($status_number, $status_phrase) = $r->get_status();
-    $data = $r->get_body() if $status_number == 200;
-    $headers = $r->get_headers();
-    if ($data) {
-        my $doc = $self->{'discoveryDocument'} = JSON::decode_json($data);
-        print STDERR Dumper $doc if $ENV{'DEBUG_ARVADOS_API_DISCOVERY'};
-        my $k, $v;
-        while (($k, $v) = each %{$doc->{'resources'}}) {
-            $self->{$k} = Arvados::ResourceAccessor->new($self, $k);
-        }
-    } else {
-        croak "No discovery doc at $uri - $status_number $status_phrase";
-    }
-    $self;
-}
-
-sub new_request
-{
-    my $self = shift;
-    local $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'};
-    if ($self->{'noVerifyHostname'} || ($host =~ /\.local$/)) {
-        $ENV{'PERL_LWP_SSL_VERIFY_HOSTNAME'} = 0;
-    }
-    Arvados::Request->new();
-}
-
-sub load_config_file ($)
-{
-    my $config_file = shift;
-    my %config;
-
-    if (open (CONF, $config_file)) {
-       while (<CONF>) {
-           next if /^\s*#/ || /^\s*$/;  # skip comments and blank lines
-           chomp;
-           my ($key, $val) = split /\s*=\s*/, $_, 2;
-           $config{$key} = $val;
-       }
-    }
-    close CONF;
-    return \%config;
-}
-
-1;
diff --git a/sdk/perl/lib/Arvados/Request.pm b/sdk/perl/lib/Arvados/Request.pm
deleted file mode 100644 (file)
index 4523f7d..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-package Arvados::Request;
-use Data::Dumper;
-use LWP::UserAgent;
-use URI::Escape;
-use Encode;
-use strict;
-@Arvados::HTTP::ISA = qw(LWP::UserAgent);
-
-sub new
-{
-    my $class = shift;
-    my $self = {};
-    bless ($self, $class);
-    return $self->_init(@_);
-}
-
-sub _init
-{
-    my $self = shift;
-    $self->{'ua'} = new LWP::UserAgent(@_);
-    $self->{'ua'}->agent ("libarvados-perl/".$Arvados::VERSION);
-    $self;
-}
-
-sub set_uri
-{
-    my $self = shift;
-    $self->{'uri'} = shift;
-}
-
-sub process_request
-{
-    my $self = shift;
-    my %req;
-    my %content;
-    my $method = $self->{'method'};
-    if ($method eq 'GET' || $method eq 'HEAD') {
-        $content{'_method'} = $method;
-        $method = 'POST';
-    }
-    $req{$method} = $self->{'uri'};
-    $self->{'req'} = new HTTP::Request (%req);
-    $self->{'req'}->header('Authorization' => ('OAuth2 ' . $self->{'authToken'})) if $self->{'authToken'};
-    $self->{'req'}->header('Accept' => 'application/json');
-
-    # allow_nonref lets us encode JSON::true and JSON::false, see #12078
-    my $json = JSON->new->allow_nonref;
-    my ($p, $v);
-    while (($p, $v) = each %{$self->{'queryParams'}}) {
-        $content{$p} = (ref($v) eq "") ? $v : $json->encode($v);
-    }
-    my $content;
-    while (($p, $v) = each %content) {
-        $content .= '&' unless $content eq '';
-        $content .= uri_escape($p);
-        $content .= '=';
-        $content .= uri_escape($v);
-    }
-    $self->{'req'}->content_type("application/x-www-form-urlencoded; charset='utf8'");
-    $self->{'req'}->content(Encode::encode('utf8', $content));
-    $self->{'res'} = $self->{'ua'}->request ($self->{'req'});
-}
-
-sub get_status
-{
-    my $self = shift;
-    return ($self->{'res'}->code(),
-           $self->{'res'}->message());
-}
-
-sub get_body
-{
-    my $self = shift;
-    return $self->{'res'}->content;
-}
-
-sub set_method
-{
-    my $self = shift;
-    $self->{'method'} = shift;
-}
-
-sub set_query_params
-{
-    my $self = shift;
-    $self->{'queryParams'} = shift;
-}
-
-sub set_auth_token
-{
-    my $self = shift;
-    $self->{'authToken'} = shift;
-}
-
-sub get_headers
-{
-    ""
-}
-
-1;
diff --git a/sdk/perl/lib/Arvados/ResourceAccessor.pm b/sdk/perl/lib/Arvados/ResourceAccessor.pm
deleted file mode 100644 (file)
index 8b235fc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-package Arvados::ResourceAccessor;
-use Carp;
-use Data::Dumper;
-
-sub new
-{
-    my $class = shift;
-    my $self = {};
-    bless ($self, $class);
-
-    $self->{'api'} = shift;
-    $self->{'resourcesName'} = shift;
-    $self->{'methods'} = $self->{'api'}->{'discoveryDocument'}->{'resources'}->{$self->{'resourcesName'}}->{'methods'};
-    my $method_name, $method;
-    while (($method_name, $method) = each %{$self->{'methods'}}) {
-        $self->{$method_name} = Arvados::ResourceMethod->new($self, $method);
-    }
-    $self;
-}
-
-1;
diff --git a/sdk/perl/lib/Arvados/ResourceMethod.pm b/sdk/perl/lib/Arvados/ResourceMethod.pm
deleted file mode 100644 (file)
index d7e86ff..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-package Arvados::ResourceMethod;
-use Carp;
-use Data::Dumper;
-
-sub new
-{
-    my $class = shift;
-    my $self = {};
-    bless ($self, $class);
-    return $self->_init(@_);
-}
-
-sub _init
-{
-    my $self = shift;
-    $self->{'resourceAccessor'} = shift;
-    $self->{'method'} = shift;
-    return $self;
-}
-
-sub execute
-{
-    my $self = shift;
-    my $method = $self->{'method'};
-
-    my $path = $method->{'path'};
-
-    my %body_params;
-    my %given_params = @_;
-    my %extra_params = %given_params;
-    my %method_params = %{$method->{'parameters'}};
-    if ($method->{'request'}->{'properties'}) {
-        while (my ($prop_name, $prop_value) =
-               each %{$method->{'request'}->{'properties'}}) {
-            if (ref($prop_value) eq 'HASH' && $prop_value->{'$ref'}) {
-                $method_params{$prop_name} = { 'type' => 'object' };
-            }
-        }
-    }
-    while (my ($param_name, $param) = each %method_params) {
-        delete $extra_params{$param_name};
-        if ($param->{'required'} && !exists $given_params{$param_name}) {
-            croak("Required parameter not supplied: $param_name");
-        }
-        elsif ($param->{'location'} eq 'path') {
-            $path =~ s/{\Q$param_name\E}/$given_params{$param_name}/eg;
-        }
-        elsif (!exists $given_params{$param_name}) {
-            ;
-        }
-        elsif ($param->{'type'} eq 'object') {
-            my %param_value;
-            my ($p, $v);
-            if (exists $param->{'properties'}) {
-                while (my ($property_name, $property) =
-                       each %{$param->{'properties'}}) {
-                    # if the discovery doc specifies object structure,
-                    # convert to true/false depending on supplied type
-                    if (!exists $given_params{$param_name}->{$property_name}) {
-                        ;
-                    }
-                    elsif (!defined $given_params{$param_name}->{$property_name}) {
-                        $param_value{$property_name} = JSON::null;
-                    }
-                    elsif ($property->{'type'} eq 'boolean') {
-                        $param_value{$property_name} = $given_params{$param_name}->{$property_name} ? JSON::true : JSON::false;
-                    }
-                    else {
-                        $param_value{$property_name} = $given_params{$param_name}->{$property_name};
-                    }
-                }
-            }
-            else {
-                while (my ($property_name, $property) =
-                       each %{$given_params{$param_name}}) {
-                    if (ref $property eq '' || $property eq undef) {
-                        $param_value{$property_name} = $property;
-                    }
-                    elsif (ref $property eq 'HASH') {
-                        $param_value{$property_name} = {};
-                        while (my ($k, $v) = each %$property) {
-                            $param_value{$property_name}->{$k} = $v;
-                        }
-                    }
-                }
-            }
-            $body_params{$param_name} = \%param_value;
-        } elsif ($param->{'type'} eq 'boolean') {
-            $body_params{$param_name} = $given_params{$param_name} ? JSON::true : JSON::false;
-        } else {
-            $body_params{$param_name} = $given_params{$param_name};
-        }
-    }
-    if (%extra_params) {
-        croak("Unsupported parameter(s) passed to API call /$path: \"" . join('", "', keys %extra_params) . '"');
-    }
-    my $r = $self->{'resourceAccessor'}->{'api'}->new_request;
-    my $base_uri = $self->{'resourceAccessor'}->{'api'}->{'discoveryDocument'}->{'baseUrl'};
-    $base_uri =~ s:/$::;
-    $r->set_uri($base_uri . "/" . $path);
-    $r->set_method($method->{'httpMethod'});
-    $r->set_auth_token($self->{'resourceAccessor'}->{'api'}->{'authToken'});
-    $r->set_query_params(\%body_params) if %body_params;
-    $r->process_request();
-    my $data, $headers;
-    my ($status_number, $status_phrase) = $r->get_status();
-    if ($status_number != 200) {
-        croak("API call /$path failed: $status_number $status_phrase\n". $r->get_body());
-    }
-    $data = $r->get_body();
-    $headers = $r->get_headers();
-    my $result = JSON::decode_json($data);
-    if ($method->{'response'}->{'$ref'} =~ /List$/) {
-        Arvados::ResourceProxyList->new($result, $self->{'resourceAccessor'});
-    } else {
-        Arvados::ResourceProxy->new($result, $self->{'resourceAccessor'});
-    }
-}
-
-1;
diff --git a/sdk/perl/lib/Arvados/ResourceProxy.pm b/sdk/perl/lib/Arvados/ResourceProxy.pm
deleted file mode 100644 (file)
index d3be468..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-package Arvados::ResourceProxy;
-
-sub new
-{
-    my $class = shift;
-    my $self = shift;
-    $self->{'resourceAccessor'} = shift;
-    bless ($self, $class);
-    $self;
-}
-
-sub save
-{
-    my $self = shift;
-    $response = $self->{'resourceAccessor'}->{'update'}->execute('uuid' => $self->{'uuid'}, $self->resource_parameter_name() => $self);
-    foreach my $param (keys %$self) {
-        if (exists $response->{$param}) {
-            $self->{$param} = $response->{$param};
-        }
-    }
-    $self;
-}
-
-sub update_attributes
-{
-    my $self = shift;
-    my %updates = @_;
-    $response = $self->{'resourceAccessor'}->{'update'}->execute('uuid' => $self->{'uuid'}, $self->resource_parameter_name() => \%updates);
-    foreach my $param (keys %updates) {
-        if (exists $response->{$param}) {
-            $self->{$param} = $response->{$param};
-        }
-    }
-    $self;
-}
-
-sub reload
-{
-    my $self = shift;
-    $response = $self->{'resourceAccessor'}->{'get'}->execute('uuid' => $self->{'uuid'});
-    foreach my $param (keys %$self) {
-        if (exists $response->{$param}) {
-            $self->{$param} = $response->{$param};
-        }
-    }
-    $self;
-}
-
-sub resource_parameter_name
-{
-    my $self = shift;
-    my $pname = $self->{'resourceAccessor'}->{'resourcesName'};
-    $pname =~ s/s$//;           # XXX not a very good singularize()
-    $pname;
-}
-
-1;
diff --git a/sdk/perl/lib/Arvados/ResourceProxyList.pm b/sdk/perl/lib/Arvados/ResourceProxyList.pm
deleted file mode 100644 (file)
index 7d8e187..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: Apache-2.0
-
-package Arvados::ResourceProxyList;
-
-sub new
-{
-    my $class = shift;
-    my $self = {};
-    bless ($self, $class);
-    $self->_init(@_);
-}
-
-sub _init
-{
-    my $self = shift;
-    $self->{'serverResponse'} = shift;
-    $self->{'resourceAccessor'} = shift;
-    $self->{'items'} = [ map { Arvados::ResourceProxy->new($_, $self->{'resourceAccessor'}) } @{$self->{'serverResponse'}->{'items'}} ];
-    $self;
-}
-
-1;
index 570e398a2895ffb61ff021e0f7a618e3c21051d6..5e9bf64c4f724a7cd90f4e8f40ff75ea67efd177 100644 (file)
@@ -63,5 +63,5 @@ Testing and Development
 This package is one part of the Arvados source package, and it has
 integration tests to check interoperability with other Arvados
 components.  Our `hacking guide
-<https://arvados.org/projects/arvados/wiki/Hacking_Python_SDK>`_
+<https://dev.arvados.org/projects/arvados/wiki/Hacking_Python_SDK>`_
 describes how to set up a development environment and run tests.
index 458af53a748834f6f0eb22942b07c16a6187e029..e391b7a6ca027aacad81a38d85ef7ddd05133c43 100644 (file)
@@ -248,7 +248,7 @@ module Keep
     end
 
     # Verify that a given manifest is valid according to
-    # https://arvados.org/projects/arvados/wiki/Keep_manifest_format
+    # https://dev.arvados.org/projects/arvados/wiki/Keep_manifest_format
     def self.validate! manifest
       raise ArgumentError.new "No manifest found" if !manifest
 
index 6bc53be4f886286103023537dd3b335fae8f34b1..811aa0cc2e06d9f3e80718db8e21d6e2199f32fa 100644 (file)
@@ -146,7 +146,7 @@ GEM
     oj (3.9.2)
     optimist (3.0.0)
     os (1.1.1)
-    passenger (6.0.2)
+    passenger (6.0.15)
       rack
       rake (>= 0.8.1)
     pg (1.1.4)
index c914051a349685aa5f73dc419a16a17449a4b2f5..55a4c6706c7ccb802f50bdd8a2c2fbe3cee4fdee 100644 (file)
@@ -43,11 +43,10 @@ class ApiClient < ArvadosModel
   def norm url
     # normalize URL for comparison
     url = URI(url.to_s)
-    if url.scheme == "https"
-      url.port == "443"
-    end
-    if url.scheme == "http"
-      url.port == "80"
+    if url.scheme == "https" && url.port == ""
+      url.port = "443"
+    elsif url.scheme == "http" && url.port == ""
+      url.port = "80"
     end
     url.path = "/"
     url
index 0416d3dbd2cc6eaddcf780326bca845c2cb55710..e0d5046ae25e9cb7058e9bd85ba6673d2cbc8de8 100644 (file)
@@ -66,5 +66,5 @@ $ apt-get install python-dev pkg-config libfuse-dev libattr1-dev
 This package is one part of the Arvados source package, and it has
 integration tests to check interoperability with other Arvados
 components.  Our `hacking guide
-<https://arvados.org/projects/arvados/wiki/Hacking_Python_SDK>`_
+<https://dev.arvados.org/projects/arvados/wiki/Hacking_Python_SDK>`_
 describes how to set up a development environment and run tests.
index ee89b156f796b49395fc6ec151de6ab12127e176..78737640045db53691f03f27742ffc4f495debd0 100644 (file)
@@ -56,15 +56,12 @@ func (v *S3Volume) check() error {
                return errors.New("DriverParameters: RaceWindow must not be negative")
        }
 
-       var ok bool
-       v.region, ok = aws.Regions[v.Region]
        if v.Endpoint == "" {
+               r, ok := aws.Regions[v.Region]
                if !ok {
                        return fmt.Errorf("unrecognized region %+q; try specifying endpoint instead", v.Region)
                }
-       } else if ok {
-               return fmt.Errorf("refusing to use AWS region name %+q with endpoint %+q; "+
-                       "specify empty endpoint or use a different region name", v.Region, v.Endpoint)
+               v.region = r
        } else {
                v.region = aws.Region{
                        Name:                 v.Region,
index f7cff6d33ea4d7c764ba74f06e49c8815f021fa9..d068dde074ea254ef814aea38eefa6f63102d7e3 100644 (file)
@@ -184,19 +184,25 @@ func (v *S3AWSVolume) check(ec2metadataHostname string) error {
                        if v.Endpoint != "" && service == "s3" {
                                return aws.Endpoint{
                                        URL:           v.Endpoint,
-                                       SigningRegion: v.Region,
+                                       SigningRegion: region,
                                }, nil
                        } else if service == "ec2metadata" && ec2metadataHostname != "" {
                                return aws.Endpoint{
                                        URL: ec2metadataHostname,
                                }, nil
+                       } else {
+                               return defaultResolver.ResolveEndpoint(service, region)
                        }
-
-                       return defaultResolver.ResolveEndpoint(service, region)
                }
                cfg.EndpointResolver = aws.EndpointResolverFunc(myCustomResolver)
        }
-
+       if v.Region == "" {
+               // Endpoint is already specified (otherwise we would
+               // have errored out above), but Region is also
+               // required by the aws sdk, in order to determine
+               // SignatureVersions.
+               v.Region = "us-east-1"
+       }
        cfg.Region = v.Region
 
        // Zero timeouts mean "wait forever", which is a bad
index 4e95bdedfc465ac0c3c25065e2dd778f0b949775..ba81426f0bfc35a7b916496970edf0cbb9648300 100644 (file)
@@ -74,6 +74,11 @@ run_bundler() {
        # If present, use the one associated with rails workbench or API
        BUNDLER=$PWD/bin/bundle
     fi
+
+    if test -z "$(flock $GEMLOCK /var/lib/arvados/bin/gem list | grep 'arvados[[:blank:]].*[0-9.]*dev')" ; then
+        (cd /usr/src/arvados/sdk/ruby && \
+        /var/lib/arvados/bin/gem build arvados.gemspec && flock $GEMLOCK /var/lib/arvados/bin/gem install $(ls -1 *.gem | sort -r | head -n1))
+    fi
     if ! flock $GEMLOCK $BUNDLER install --verbose --local --no-deployment $frozen "$@" ; then
         flock $GEMLOCK $BUNDLER install --verbose --no-deployment $frozen "$@"
     fi