15003: Merge branch 'master' into 15003-preprocess-config
authorTom Clegg <tclegg@veritasgenetics.com>
Wed, 15 May 2019 13:57:36 +0000 (09:57 -0400)
committerTom Clegg <tclegg@veritasgenetics.com>
Wed, 15 May 2019 13:57:36 +0000 (09:57 -0400)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg@veritasgenetics.com>

23 files changed:
build/rails-package-scripts/arvados-api-server.sh
build/run-library.sh
services/api/Gemfile
services/api/Gemfile.lock
services/api/app/assets/images/logo.png
services/api/app/assets/stylesheets/application.css
services/api/app/controllers/arvados/v1/schema_controller.rb
services/api/app/controllers/arvados/v1/users_controller.rb
services/api/app/controllers/user_sessions_controller.rb
services/api/app/views/layouts/application.html.erb
services/api/app/views/static/login_failure.html.erb
services/api/app/views/user_sessions/create.html.erb [new file with mode: 0644]
services/api/config/arvados_config.rb
services/api/test/functional/arvados/v1/users_controller_test.rb
services/keepstore/unix_volume.go
services/nodemanager/doc/ec2.example.cfg
services/nodemanager/setup.py
tools/arvbox/bin/arvbox
tools/arvbox/lib/arvbox/docker/service/certificate/run
tools/arvbox/lib/arvbox/docker/service/controller/run
tools/arvbox/lib/arvbox/docker/service/crunch-dispatch-local/run-service
tools/arvbox/lib/arvbox/docker/service/workbench2/run-service
tools/keep-xref/keep-xref.py [new file with mode: 0755]

index 6d11ea864ccf30496123cae696e09a3246d1c5be..82bc9898aa87c350b38774db6db349294330bc9f 100644 (file)
@@ -19,7 +19,7 @@ setup_before_nginx_restart() {
   # initialize git_internal_dir
   # usually /var/lib/arvados/internal.git (set in application.default.yml )
   if [ "$APPLICATION_READY" = "1" ]; then
-      GIT_INTERNAL_DIR=$($COMMAND_PREFIX bundle exec rake config:check 2>&1 | grep git_internal_dir | awk '{ print $2 }')
+      GIT_INTERNAL_DIR=$($COMMAND_PREFIX bundle exec rake config:dump 2>&1 | grep GitInternalDir | awk '{ print $2 }' |tr -d '"')
       if [ ! -e "$GIT_INTERNAL_DIR" ]; then
         run_and_report "Creating git_internal_dir '$GIT_INTERNAL_DIR'" \
           mkdir -p "$GIT_INTERNAL_DIR"
index 01a6a06c14afffa2806673a3c7ac0f98d8009ab5..141c49e62182a28030ce9690727993dfe06e6610 100755 (executable)
@@ -11,7 +11,7 @@
 LICENSE_PACKAGE_TS=20151208015500
 
 if [[ -z "$ARVADOS_BUILDING_VERSION" ]]; then
-    RAILS_PACKAGE_ITERATION=8
+    RAILS_PACKAGE_ITERATION=1
 else
     RAILS_PACKAGE_ITERATION="$ARVADOS_BUILDING_ITERATION"
 fi
index 6d42956940972da3ba776637345b6f321258a769..804d2a479d3d4701489c8d1bed812c7a6873c252 100644 (file)
@@ -71,6 +71,8 @@ gem 'rails-observers'
 gem 'rails-perftest'
 gem 'rails-controller-testing'
 
+gem 'sass-rails'
+
 # Install any plugin gems
 Dir.glob(File.join(File.dirname(__FILE__), 'lib', '**', "Gemfile")) do |f|
     eval(IO.read(f), binding)
index 13f7564be86576c231d35a6f04da416738a59954..078b2b7f418d1e94ca2b4ab424be702cdad1197b 100644 (file)
@@ -110,6 +110,7 @@ GEM
     faye-websocket (0.10.7)
       eventmachine (>= 0.12.0)
       websocket-driver (>= 0.5.1)
+    ffi (1.9.25)
     globalid (0.4.2)
       activesupport (>= 4.2.0)
     googleauth (0.8.0)
@@ -220,6 +221,9 @@ GEM
       rake (>= 0.8.7)
       thor (>= 0.18.1, < 2.0)
     rake (12.3.2)
+    rb-fsevent (0.10.3)
+    rb-inotify (0.9.10)
+      ffi (>= 0.5.0, < 2)
     ref (2.0.0)
     request_store (1.4.1)
       rack (>= 1.4)
@@ -231,6 +235,17 @@ GEM
     rvm-capistrano (1.5.6)
       capistrano (~> 2.15.4)
     safe_yaml (1.0.5)
+    sass (3.5.5)
+      sass-listen (~> 4.0.0)
+    sass-listen (4.0.0)
+      rb-fsevent (~> 0.9, >= 0.9.4)
+      rb-inotify (~> 0.9, >= 0.9.7)
+    sass-rails (5.0.7)
+      railties (>= 4.0.0, < 6)
+      sass (~> 3.1)
+      sprockets (>= 2.8, < 4.0)
+      sprockets-rails (>= 2.0, < 4.0)
+      tilt (>= 1.1, < 3)
     signet (0.11.0)
       addressable (~> 2.3)
       faraday (~> 0.9)
@@ -257,6 +272,7 @@ GEM
       ref
     thor (0.20.3)
     thread_safe (0.3.6)
+    tilt (2.0.8)
     tzinfo (1.2.5)
       thread_safe (~> 0.1)
     uglifier (2.7.2)
@@ -299,6 +315,7 @@ DEPENDENCIES
   ruby-prof (~> 0.15.0)
   rvm-capistrano
   safe_yaml
+  sass-rails
   simplecov (~> 0.7.1)
   simplecov-rcov
   sshkey
index 4db96efabdb542ad26ca3cb66a9320854bd73035..c511f0ec514289d128cdc4beb6aedfe2c0bb3863 100644 (file)
Binary files a/services/api/app/assets/images/logo.png and b/services/api/app/assets/images/logo.png differ
index 742a575a93bb95a31791438936df00e99c97b0c4..721ff801c91c5aba35337fbd7a8efab7729d9f14 100644 (file)
@@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0 */
  * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
  * the top of the compiled file, but it's generally better to create a new file per style scope.
  *= require_self
- *= require_tree . 
+ *= require_tree .
 */
 
 .contain-align-left {
@@ -63,8 +63,7 @@ div#header span.beta > span {
     font-size: 0.8em;
 }
 img.curoverse-logo {
-    width: 221px;
-    height: 44px;
+    height: 66px;
 }
 #intropage {
     font-family: Verdana,Arial,sans-serif;
@@ -180,4 +179,3 @@ div#header a.sudo-logout {
     color: #000;
     font-weight: bold;
 }
-
index 13e47f76cdf88b17c2ee659dafce1417678ab2ee..313fe5d0a086241ba9ca9cef95c8e29db60ad843 100644 (file)
@@ -26,7 +26,7 @@ class Arvados::V1::SchemaController < ApplicationController
     Rails.cache.fetch 'arvados_v1_rest_discovery' do
       Rails.application.eager_load!
       remoteHosts = {}
-      Rails.configuration.RemoteClusters.each {|k,v| if k != "*" then remoteHosts[k] = v["Host"] end }
+      Rails.configuration.RemoteClusters.each {|k,v| if k != :"*" then remoteHosts[k] = v["Host"] end }
       discovery = {
         kind: "discovery#restDescription",
         discoveryVersion: "v1",
@@ -67,6 +67,7 @@ class Arvados::V1::SchemaController < ApplicationController
         remoteHostsViaDNS: Rails.configuration.RemoteClusters["*"].Proxy,
         websocketUrl: Rails.configuration.Services.Websocket.ExternalURL.to_s,
         workbenchUrl: Rails.configuration.Services.Workbench1.ExternalURL.to_s,
+        workbench2Url: Rails.configuration.Services.Workbench2.ExternalURL.to_s,
         keepWebServiceUrl: Rails.configuration.Services.WebDAV.ExternalURL.to_s,
         gitUrl: Rails.configuration.Services.GitHTTP.ExternalURL.to_s,
         parameters: {
index 18b6b46d2678df8b8094c5f273d8db55a7f9e2a3..4a345f363be8da15055f52d54dcfb929f6687298 100644 (file)
@@ -126,37 +126,65 @@ class Arvados::V1::UsersController < ApplicationController
   end
 
   def merge
-    if !Thread.current[:api_client].andand.is_trusted
-      return send_error("supplied API token is not from a trusted client", status: 403)
-    elsif Thread.current[:api_client_authorization].scopes != ['all']
-      return send_error("cannot merge with a scoped token", status: 403)
-    end
+    if (params[:old_user_uuid] || params[:new_user_uuid])
+      if !current_user.andand.is_admin
+        return send_error("Must be admin to use old_user_uuid/new_user_uuid", status: 403)
+      end
+      if !params[:old_user_uuid] || !params[:new_user_uuid]
+        return send_error("Must supply both old_user_uuid and new_user_uuid", status: 422)
+      end
+      new_user = User.find_by_uuid(params[:new_user_uuid])
+      if !new_user
+        return send_error("User in new_user_uuid not found", status: 422)
+      end
+      @object = User.find_by_uuid(params[:old_user_uuid])
+      if !@object
+        return send_error("User in old_user_uuid not found", status: 422)
+      end
+    else
+      if !Thread.current[:api_client].andand.is_trusted
+        return send_error("supplied API token is not from a trusted client", status: 403)
+      elsif Thread.current[:api_client_authorization].scopes != ['all']
+        return send_error("cannot merge with a scoped token", status: 403)
+      end
 
-    new_auth = ApiClientAuthorization.validate(token: params[:new_user_token])
-    if !new_auth
-      return send_error("invalid new_user_token", status: 401)
-    end
-    if !new_auth.api_client.andand.is_trusted
-      return send_error("supplied new_user_token is not from a trusted client", status: 403)
-    elsif new_auth.scopes != ['all']
-      return send_error("supplied new_user_token has restricted scope", status: 403)
+      new_auth = ApiClientAuthorization.validate(token: params[:new_user_token])
+      if !new_auth
+        return send_error("invalid new_user_token", status: 401)
+      end
+
+      if new_auth.user.uuid[0..4] == Rails.configuration.ClusterID
+        if !new_auth.api_client.andand.is_trusted
+          return send_error("supplied new_user_token is not from a trusted client", status: 403)
+        elsif new_auth.scopes != ['all']
+          return send_error("supplied new_user_token has restricted scope", status: 403)
+        end
+      end
+      new_user = new_auth.user
+      @object = current_user
     end
-    new_user = new_auth.user
 
-    if current_user.uuid == new_user.uuid
+    if @object.uuid == new_user.uuid
       return send_error("cannot merge user to self", status: 422)
     end
 
+    if !params[:new_owner_uuid]
+      return send_error("missing new_owner_uuid", status: 422)
+    end
+
     if !new_user.can?(write: params[:new_owner_uuid])
       return send_error("cannot move objects into supplied new_owner_uuid: new user does not have write permission", status: 403)
     end
 
     redirect = params[:redirect_to_new_user]
+    if @object.uuid[0..4] != Rails.configuration.ClusterID && redirect
+      return send_error("cannot merge remote user to other with redirect_to_new_user=true", status: 422)
+    end
+
     if !redirect
       return send_error("merge with redirect_to_new_user=false is not yet supported", status: 422)
     end
 
-    @object = current_user
     act_as_system_user do
       @object.merge(new_owner_uuid: params[:new_owner_uuid], redirect_to_user_uuid: redirect && new_user.uuid)
     end
@@ -171,11 +199,17 @@ class Arvados::V1::UsersController < ApplicationController
         type: 'string', required: true,
       },
       new_user_token: {
-        type: 'string', required: true,
+        type: 'string', required: false,
       },
       redirect_to_new_user: {
         type: 'boolean', required: false,
       },
+      old_user_uuid: {
+        type: 'string', required: false,
+      },
+      new_user_uuid: {
+        type: 'string', required: false,
+      }
     }
   end
 
index 6e18cdd4607bb5aa6e5b49b608f1d15882891167..ef0f8868666dfb3bb786dab263270c8911df45e6 100644 (file)
@@ -80,6 +80,16 @@ class UserSessionsController < ApplicationController
     # For the benefit of functional and integration tests:
     @user = user
 
+    if user.uuid[0..4] != Rails.configuration.ClusterID
+      # Actually a remote user
+      # Send them to their home cluster's login
+      rh = Rails.configuration.RemoteClusters[user.uuid[0..4]]
+      remote, return_to_url = params[:return_to].split(',', 2)
+      @remotehomeurl = "#{rh.Scheme || "https"}://#{rh.Host}/login?remote=#{Rails.configuration.ClusterID}&return_to=#{return_to_url}"
+      render
+      return
+    end
+
     # prevent ArvadosModel#before_create and _update from throwing
     # "unauthorized":
     Thread.current[:user] = user
index 302859543c5dd246ff29d4f84e2e2b051e091871..a99b6f165dd74864c160df8597c06eecc15f5477 100644 (file)
@@ -5,14 +5,15 @@ SPDX-License-Identifier: AGPL-3.0 %>
 <!DOCTYPE html>
 <html>
 <head>
-  <title>Server</title>
+  <title>Arvados API Server (<%= Rails.configuration.ClusterID %>)</title>
   <%= stylesheet_link_tag    "application" %>
   <%= javascript_include_tag "application" %>
   <%= csrf_meta_tags %>
 </head>
 <body>
 <div id="header">
-  <div class="apptitle">ARVADOS <span class="beta"><span>BETA</span></span></div>
+  <div class="apptitle">ARVADOS</div>
+  <div>(<%= Rails.configuration.ClusterID %>)</div>
   <div style="float:right">
     <% if current_user %>
     <%= current_user.full_name %>
@@ -23,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0 %>
     &nbsp;&bull;&nbsp;
     <a class="logout" href="/logout">Log out</a>
     <% else %>
-    <a class="logout" href="/auth/joshid">Log in</a>
+      <!--<a class="logout" href="/auth/joshid">Log in</a>-->
     <% end %>
 
     <% if current_user and session[:real_uid] and session[:switch_back_to] and User.find(session[:real_uid].to_i).verify_userswitch_cookie(session[:switch_back_to]) %>
index 0f3141e0eff0b9fd6c873b0921516a7af94dc89f..b3c6e70d907f4e460096ecbb06aaa6ccc7ddcd87 100644 (file)
@@ -17,9 +17,9 @@ $(function(){
 
     <p>Sorry, something went wrong logging you in. Please try again.</p>
 
-    <p style="float:right;margin-top:1em">
-      <a href="/auth/joshid">Log in here.</a>
-    </p>
+    <!--<p style="float:right;margin-top:1em">
+      <a href="/login">Log in here.</a>
+    </p>-->
 
     <div style="clear:both;height:8em"></div>
   </div>
diff --git a/services/api/app/views/user_sessions/create.html.erb b/services/api/app/views/user_sessions/create.html.erb
new file mode 100644 (file)
index 0000000..2cb6948
--- /dev/null
@@ -0,0 +1,7 @@
+<div style="width:30em; margin:2em auto 0 auto">
+  <h1>Login redirect</h1>
+  <p>This login is linked to federated user <b><%= @user.uuid %></b> on cluster <b><%= @user.uuid[0..4] %></b>.</p>
+  <p><a href="<%=@remotehomeurl%>">Click here log in on cluster <%= @user.uuid[0..4] %>.</a></p>
+  <p>After logging in, you will be returned to this cluster (<%=Rails.configuration.ClusterID%>).</p>
+  <p>To avoid seeing this page, choose <b><%= @user.uuid[0..4] %></b> as the cluster that hosts your user account on the Workbench login page.</p>
+</div>
index cb76b68dc984e71155a0ebcc2bfaf7363a60d638..c114bb95a3eec80aa49af7a7990cdb839ebdffaa 100644 (file)
@@ -107,7 +107,7 @@ arvcfg.declare_config "Collections.PreserveVersionIfIdle", ActiveSupport::Durati
 arvcfg.declare_config "Collections.TrashSweepInterval", ActiveSupport::Duration, :trash_sweep_interval
 arvcfg.declare_config "Collections.BlobSigningKey", NonemptyString, :blob_signing_key
 arvcfg.declare_config "Collections.BlobSigningTTL", Integer, :blob_signature_ttl
-arvcfg.declare_config "Collections.BlobSigning", Boolean, :permit_create_collection_with_unsigned_manifest
+arvcfg.declare_config "Collections.BlobSigning", Boolean, :permit_create_collection_with_unsigned_manifest, ->(cfg, k, v) { ConfigLoader.set_cfg cfg, "Collections.BlobSigning", !v }
 arvcfg.declare_config "Containers.SupportedDockerImageFormats", Array, :docker_image_formats
 arvcfg.declare_config "Containers.LogReuseDecisions", Boolean, :log_reuse_decisions
 arvcfg.declare_config "Containers.DefaultKeepCacheRAM", Integer, :container_default_keep_cache_ram
index 0501da1673ebdff87c5c9900b205dfdde96dce42..60696b98a9c998be7e270fe8bd3fea8cc72bd450 100644 (file)
@@ -927,7 +927,7 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
            redirect_to_new_user: true,
          })
     assert_response(:success)
-    assert_equal(users(:project_viewer).redirect_to_user_uuid, users(:active).uuid)
+    assert_equal(users(:active).uuid, User.unscoped.find_by_uuid(users(:project_viewer).uuid).redirect_to_user_uuid)
 
     auth = ApiClientAuthorization.validate(token: api_client_authorizations(:project_viewer).api_token)
     assert_not_nil(auth)
@@ -935,6 +935,82 @@ class Arvados::V1::UsersControllerTest < ActionController::TestCase
     assert_equal(users(:active).uuid, auth.user.uuid)
   end
 
+
+  test "merge 'project_viewer' account into 'active' account using uuids" do
+    authorize_with(:admin)
+    post(:merge, params: {
+           old_user_uuid: users(:project_viewer).uuid,
+           new_user_uuid: users(:active).uuid,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(:success)
+    assert_equal(users(:active).uuid, User.unscoped.find_by_uuid(users(:project_viewer).uuid).redirect_to_user_uuid)
+
+    auth = ApiClientAuthorization.validate(token: api_client_authorizations(:project_viewer).api_token)
+    assert_not_nil(auth)
+    assert_not_nil(auth.user)
+    assert_equal(users(:active).uuid, auth.user.uuid)
+  end
+
+  test "merge 'project_viewer' account into 'active' account using uuids denied for non-admin" do
+    authorize_with(:active)
+    post(:merge, params: {
+           old_user_uuid: users(:project_viewer).uuid,
+           new_user_uuid: users(:active).uuid,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(403)
+    assert_nil(users(:project_viewer).redirect_to_user_uuid)
+  end
+
+  test "merge 'project_viewer' account into 'active' account using uuids denied missing old_user_uuid" do
+    authorize_with(:admin)
+    post(:merge, params: {
+           new_user_uuid: users(:active).uuid,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+    assert_nil(users(:project_viewer).redirect_to_user_uuid)
+  end
+
+  test "merge 'project_viewer' account into 'active' account using uuids denied missing new_user_uuid" do
+    authorize_with(:admin)
+    post(:merge, params: {
+           old_user_uuid: users(:project_viewer).uuid,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+    assert_nil(users(:project_viewer).redirect_to_user_uuid)
+  end
+
+  test "merge 'project_viewer' account into 'active' account using uuids denied bogus old_user_uuid" do
+    authorize_with(:admin)
+    post(:merge, params: {
+           old_user_uuid: "zzzzz-tpzed-bogusbogusbogus",
+           new_user_uuid: users(:active).uuid,
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+    assert_nil(users(:project_viewer).redirect_to_user_uuid)
+  end
+
+  test "merge 'project_viewer' account into 'active' account using uuids denied bogus new_user_uuid" do
+    authorize_with(:admin)
+    post(:merge, params: {
+           old_user_uuid: users(:project_viewer).uuid,
+           new_user_uuid: "zzzzz-tpzed-bogusbogusbogus",
+           new_owner_uuid: users(:active).uuid,
+           redirect_to_new_user: true,
+         })
+    assert_response(422)
+    assert_nil(users(:project_viewer).redirect_to_user_uuid)
+  end
+
   NON_ADMIN_USER_DATA = ["uuid", "kind", "is_active", "email", "first_name",
                          "last_name", "username"].sort
 
index 96f458720d38b56b97fa51fd63e76faa798987bf..4d9e798ac67c71c2a81f51abeb2128b340a6cda6 100644 (file)
@@ -169,7 +169,7 @@ func (v *UnixVolume) DeviceID() string {
 
        fi, err := os.Stat(dev)
        if err != nil {
-               return giveup("stat %q: %s\n", dev, err)
+               return giveup("stat %q: %s", dev, err)
        }
        ino := fi.Sys().(*syscall.Stat_t).Ino
 
@@ -377,18 +377,18 @@ func (v *UnixVolume) WriteBlock(ctx context.Context, loc string, rdr io.Reader)
        n, err := io.Copy(tmpfile, rdr)
        v.os.stats.TickOutBytes(uint64(n))
        if err != nil {
-               log.Printf("%s: writing to %s: %s\n", v, bpath, err)
+               log.Printf("%s: writing to %s: %s", v, bpath, err)
                tmpfile.Close()
                v.os.Remove(tmpfile.Name())
                return err
        }
        if err := tmpfile.Close(); err != nil {
-               log.Printf("closing %s: %s\n", tmpfile.Name(), err)
+               log.Printf("closing %s: %s", tmpfile.Name(), err)
                v.os.Remove(tmpfile.Name())
                return err
        }
        if err := v.os.Rename(tmpfile.Name(), bpath); err != nil {
-               log.Printf("rename %s %s: %s\n", tmpfile.Name(), bpath, err)
+               log.Printf("rename %s %s: %s", tmpfile.Name(), bpath, err)
                return v.os.Remove(tmpfile.Name())
        }
        return nil
@@ -400,14 +400,14 @@ func (v *UnixVolume) WriteBlock(ctx context.Context, loc string, rdr io.Reader)
 func (v *UnixVolume) Status() *VolumeStatus {
        fi, err := v.os.Stat(v.Root)
        if err != nil {
-               log.Printf("%s: os.Stat: %s\n", v, err)
+               log.Printf("%s: os.Stat: %s", v, err)
                return nil
        }
        devnum := fi.Sys().(*syscall.Stat_t).Dev
 
        var fs syscall.Statfs_t
        if err := syscall.Statfs(v.Root, &fs); err != nil {
-               log.Printf("%s: statfs: %s\n", v, err)
+               log.Printf("%s: statfs: %s", v, err)
                return nil
        }
        // These calculations match the way df calculates disk usage:
@@ -620,7 +620,7 @@ func (v *UnixVolume) IsFull() (isFull bool) {
        if avail, err := v.FreeDiskSpace(); err == nil {
                isFull = avail < MinFreeKilobytes
        } else {
-               log.Printf("%s: FreeDiskSpace: %s\n", v, err)
+               log.Printf("%s: FreeDiskSpace: %s", v, err)
                isFull = false
        }
 
@@ -679,6 +679,7 @@ func (v *UnixVolume) lock(ctx context.Context) error {
        if v.locker == nil {
                return nil
        }
+       t0 := time.Now()
        locked := make(chan struct{})
        go func() {
                v.locker.Lock()
@@ -686,6 +687,7 @@ func (v *UnixVolume) lock(ctx context.Context) error {
        }()
        select {
        case <-ctx.Done():
+               log.Printf("%s: client hung up while waiting for Serialize lock (%s)", v, time.Since(t0))
                go func() {
                        <-locked
                        v.locker.Unlock()
index f5329ebe16213ad1d7fa37aff09212efce299603..3bc905b0857f0bf52ba71944aeab5e2eea2242a6 100644 (file)
@@ -176,7 +176,7 @@ security_groups = idstring1, idstring2
 # size class (since libcloud does not provide any consistent API for exposing
 # this setting).
 # You may also want to define the amount of scratch space (expressed
-# in GB) for Crunch jobs.  You can also override Amazon's provided
+# in MB) for Crunch jobs.  You can also override Amazon's provided
 # data fields (such as price per hour) by setting them here.
 #
 # Additionally, you can ask for a preemptible instance (AWS's spot instance)
@@ -184,19 +184,22 @@ security_groups = idstring1, idstring2
 # both spot & reserved versions of the same size, you can do so by renaming
 # the Size section and specifying the instance type inside it.
 
+# 100 GB scratch space
 [Size m4.large]
 cores = 2
 price = 0.126
-scratch = 100
+scratch = 100000
 
+# 10 GB scratch space
 [Size m4.large.spot]
 instance_type = m4.large
 preemptible = true
 cores = 2
 price = 0.126
-scratch = 100
+scratch = 10000
 
+# 200 GB scratch space
 [Size m4.xlarge]
 cores = 4
 price = 0.252
-scratch = 100
+scratch = 200000
index 4f00d54e7e28d10eb366e47da1e0b2f1957d017f..ef05467810a79a88e1e4f27149fd30531804d318 100644 (file)
@@ -38,7 +38,7 @@ setup(name='arvados-node-manager',
           'apache-libcloud>=2.3.1.dev1',
           'arvados-python-client>=0.1.20170731145219',
           'future',
-          'pykka',
+          'pykka < 2',
           'python-daemon',
           'setuptools',
           'subprocess32>=3.5.1',
index 878119634bbaf23fca3183ab37651e3274147e3e..3e829522af24de67e134166e8dc227b2ba7b9b61 100755 (executable)
@@ -564,7 +564,7 @@ case "$subcmd" in
         ;;
 
     root-cert)
-       CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.pem
+       CERT=$PWD/${ARVBOX_CONTAINER}-root-cert.crt
        if test -n "$1" ; then
            CERT="$1"
        fi
index 1b062ad8d131c141dd55a18bf0a474a6991a0186..6cd2de501e857e03edce332f618f6bc63f80de9b 100755 (executable)
@@ -8,6 +8,8 @@ set -ex -o pipefail
 
 . /usr/local/lib/arvbox/common.sh
 
+uuid_prefix=$(cat /var/lib/arvados/api_uuid_prefix)
+
 if test ! -s /var/lib/arvados/root-cert.pem ; then
     # req           signing request sub-command
     # -new          new certificate request
@@ -26,7 +28,7 @@ if test ! -s /var/lib/arvados/root-cert.pem ; then
            -nodes \
            -sha256 \
            -x509 \
-           -subj "/C=US/ST=MA/O=Arvados testing/OU=arvbox/CN=arvbox testing root CA for ${uuid_prefix}" \
+           -subj "/C=US/ST=MA/O=Arvados testing/OU=arvbox/CN=test root CA for ${uuid_prefix} generated $(date --rfc-3339=seconds)" \
            -extensions x509_ext \
            -config <(cat /etc/ssl/openssl.cnf \
                          <(printf "\n[x509_ext]\nbasicConstraints=critical,CA:true,pathlen:0\nkeyUsage=critical,keyCertSign,cRLSign")) \
@@ -59,7 +61,7 @@ if test ! -s /var/lib/arvados/server-cert-${localip}.pem ; then
            -new \
            -nodes \
            -sha256 \
-           -subj "/C=US/ST=MA/O=Arvados testing for ${uuid_prefix}/OU=arvbox/CN=localhost" \
+           -subj "/C=US/ST=MA/O=Arvados testing/OU=arvbox/CN=test server cert for ${uuid_prefix} generated $(date --rfc-3339=seconds)" \
            -reqexts x509_ext \
            -extensions x509_ext \
            -config <(cat /etc/ssl/openssl.cnf \
index 06a9ba7087892e12e1daeab396d82f463c43409b..37052e1233c70879a1b5db928cd243158249a91b 100755 (executable)
@@ -18,6 +18,11 @@ if test "$1" = "--only-deps" ; then
 fi
 
 uuid_prefix=$(cat /var/lib/arvados/api_uuid_prefix)
+secret_token=$(cat /var/lib/arvados/api_secret_token)
+blob_signing_key=$(cat /var/lib/arvados/blob_signing_key)
+management_token=$(cat /var/lib/arvados/management_token)
+sso_app_secret=$(cat /var/lib/arvados/sso_app_secret)
+vm_uuid=$(cat /var/lib/arvados/vm-uuid)
 database_pw=$(cat /var/lib/arvados/api_database_pw)
 
 if test -s /var/lib/arvados/api_rails_env ; then
@@ -31,7 +36,23 @@ mkdir -p /etc/arvados
 cat >/var/lib/arvados/cluster_config.yml <<EOF
 Clusters:
   ${uuid_prefix}:
-    NodeProfiles:
+    ManagementToken: $management_token
+    Services:
+      Workbench1:
+        ExternalURL: "https://$localip:${services[workbench]}"
+      Workbench2:
+        ExternalURL: "https://$localip:${services[workbench2-ssl]}"
+      SSO:
+        ExternalURL: "https://$localip:${services[sso]}"
+      Websocket:
+        ExternalURL: "wss://$localip:${services[websockets-ssl]}/websocket"
+      GitSSH:
+        ExternalURL: "ssh://git@$localip:"
+      GitHTTP:
+        ExternalURL: "http://$localip:${services[arv-git-httpd]}/"
+      WebDAV:
+        ExternalURL: "https://$localip:${services[keep-web-ssl]}/"
+    NodeProfiles:  # to be deprecated in favor of "Services" section
       "*":
         arvados-controller:
           Listen: ":${services[controller]}" # choose a port
@@ -47,6 +68,22 @@ Clusters:
         Password: ${database_pw}
         DBName: arvados_${database_env}
         client_encoding: utf8
+    API:
+      RailsSessionSecretToken: $secret_token
+    Collections:
+      BlobSigningKey: $blob_signing_key
+      DefaultReplication: 1
+    Containers:
+      SupportedDockerImageFormats: ["v2"]
+    Login:
+      ProviderAppSecret: $sso_app_secret
+      ProviderAppID: arvados-server
+    Users:
+      NewUsersAreActive: true
+      AutoAdminFirstUser: true
+      AutoSetupNewUsers: true
+      AutoSetupNewUsersWithVmUUID: $vm_uuid
+      AutoSetupNewUsersWithRepository: true
 EOF
 
 /usr/local/lib/arvbox/yml_override.py /var/lib/arvados/cluster_config.yml
index 87c427cd29ae0140b34d086f788a2df6e7aa4a48..4330157937410fe08658e28c8235fad697f2de2d 100755 (executable)
@@ -19,7 +19,7 @@ fi
 
 cat > /usr/local/bin/crunch-run.sh <<EOF
 #!/bin/sh
-exec /usr/local/bin/crunch-run -container-enable-networking=always -container-network-mode=host \$@
+exec /usr/local/bin/crunch-run -container-enable-networking=default -container-network-mode=host \$@
 EOF
 chmod +x /usr/local/bin/crunch-run.sh
 
index 2dbef4ab876ab1911c518eded2b17478cd8acca4..e9e1ca4f8c8b0901c1e3792f2eb50d25f74c8fc3 100755 (executable)
@@ -26,6 +26,27 @@ cat <<EOF > /usr/src/workbench2/public/config.json
 }
 EOF
 
+export ARVADOS_API_HOST=$localip:${services[controller-ssl]}
+export ARVADOS_API_TOKEN=$(cat /var/lib/arvados/superuser_token)
+
+url_prefix="https://$localip:${services[workbench2-ssl]}/"
+
+set +e
+read -rd $'\000' apiclient <<EOF
+{
+   "url_prefix": "$url_prefix",
+   "is_trusted": true
+}
+EOF
+set -e
+
+clientuuid=$(arv --format=uuid api_client list --filters '[["url_prefix", "=", "'$url_prefix'"]]')
+if [[ -n "$clientuuid" ]] ; then
+    arv api_client update --uuid $clientuuid --api-client "$apiclient"
+else
+    arv api_client create --api-client "$apiclient"
+fi
+
 export HTTPS=false
 # Can't use "yarn start", need to run the dev server script
 # directly so that the TERM signal from "sv restart" gets to the
diff --git a/tools/keep-xref/keep-xref.py b/tools/keep-xref/keep-xref.py
new file mode 100755 (executable)
index 0000000..7bc4158
--- /dev/null
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+#
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+#
+
+from __future__ import print_function, absolute_import
+import argparse
+import arvados
+import arvados.util
+import csv
+import sys
+import logging
+
+lglvl = logging.INFO+1
+logging.basicConfig(level=lglvl, format='%(message)s')
+
+"""
+ Given a list of collections missing blocks (as produced by
+keep-balance), produce a report listing affected collections and
+container requests.
+"""
+
+def rerun_request(arv, container_requests_to_rerun, ct):
+    requests = arvados.util.list_all(arv.container_requests().list, filters=[["container_uuid", "=", ct["uuid"]]])
+    for cr in requests:
+        if cr["requesting_container_uuid"]:
+            rerun_request(arv, container_requests_to_rerun, arv.containers().get(uuid=cr["requesting_container_uuid"]).execute())
+        else:
+            container_requests_to_rerun[cr["uuid"]] = cr
+
+def get_owner(arv, owners, record):
+    uuid = record["owner_uuid"]
+    if uuid not in owners:
+        if uuid[6:11] == "tpzed":
+            owners[uuid] = (arv.users().get(uuid=uuid).execute()["full_name"], uuid)
+        else:
+            grp = arv.groups().get(uuid=uuid).execute()
+            _, ou = get_owner(arv, owners, grp)
+            owners[uuid] = (grp["name"], ou)
+    return owners[uuid]
+
+def main():
+    parser = argparse.ArgumentParser(description='Re-run containers associated with missing blocks')
+    parser.add_argument('inp')
+    args = parser.parse_args()
+
+    arv = arvados.api('v1')
+
+    busted_collections = set()
+
+    logging.log(lglvl, "Reading %s", args.inp)
+
+    # Get the list of bad collection PDHs
+    blocksfile = open(args.inp, "rt")
+    for line in blocksfile:
+        # Ignore the first item, that's the block id
+        collections = line.rstrip().split(" ")[1:]
+        for c in collections:
+            busted_collections.add(c)
+
+    out = csv.writer(sys.stdout)
+
+    out.writerow(("collection uuid", "container request uuid", "record name", "modified at", "owner uuid", "owner name", "root owner uuid", "root owner name", "notes"))
+
+    logging.log(lglvl, "Finding collections")
+
+    owners = {}
+    collections_to_delete = {}
+    container_requests_to_rerun = {}
+    # Get containers that produced these collections
+    i = 0
+    for b in busted_collections:
+        if (i % 100) == 0:
+            logging.log(lglvl, "%d/%d", i, len(busted_collections))
+        i += 1
+        collections_to_delete = arvados.util.list_all(arv.collections().list, filters=[["portable_data_hash", "=", b]])
+        for d in collections_to_delete:
+            t = ""
+            if d["properties"].get("type") not in ("output", "log"):
+                t = "\"type\" was '%s', expected one of 'output' or 'log'" % d["properties"].get("type")
+            ou = get_owner(arv, owners, d)
+            out.writerow((d["uuid"], "", d["name"], d["modified_at"], d["owner_uuid"], ou[0], ou[1], owners[ou[1]][0], t))
+
+        maybe_containers_to_rerun = arvados.util.list_all(arv.containers().list, filters=[["output", "=", b]])
+        for ct in maybe_containers_to_rerun:
+            rerun_request(arv, container_requests_to_rerun, ct)
+
+    logging.log(lglvl, "%d/%d", i, len(busted_collections))
+    logging.log(lglvl, "Finding container requests")
+
+    i = 0
+    for _, cr in container_requests_to_rerun.items():
+        if (i % 100) == 0:
+            logging.log(lglvl, "%d/%d", i, len(container_requests_to_rerun))
+        i += 1
+        ou = get_owner(arv, owners, cr)
+        out.writerow(("", cr["uuid"], cr["name"], cr["modified_at"], cr["owner_uuid"], ou[0], ou[1], owners[ou[1]][0], ""))
+
+    logging.log(lglvl, "%d/%d", i, len(container_requests_to_rerun))
+
+if __name__ == "__main__":
+    main()