[ARVADOS] updated: 1.3.0-737-g2ea729f97

Git user git at public.curoverse.com
Thu Apr 11 15:43:20 UTC 2019


Summary of changes:
 lib/config/config.default.yml                      |  5 +++
 .../api/app/controllers/application_controller.rb  |  9 ++---
 .../controllers/arvados/v1/groups_controller.rb    |  2 +-
 .../controllers/arvados/v1/schema_controller.rb    | 42 ++++++++++-----------
 services/api/app/controllers/static_controller.rb  |  4 +-
 .../app/controllers/user_sessions_controller.rb    |  4 +-
 services/api/app/mailers/admin_notifier.rb         | 16 ++++----
 services/api/app/mailers/profile_notifier.rb       |  2 +-
 services/api/app/mailers/user_notifier.rb          |  2 +-
 .../api/app/models/api_client_authorization.rb     |  4 +-
 services/api/app/models/arvados_model.rb           |  6 +--
 services/api/app/models/blob.rb                    | 10 ++---
 services/api/app/models/collection.rb              | 14 +++----
 services/api/app/models/commit.rb                  |  2 +-
 services/api/app/models/commit_ancestor.rb         |  2 +-
 services/api/app/models/container.rb               |  4 +-
 services/api/app/models/container_request.rb       |  6 +--
 services/api/app/models/job.rb                     |  8 ++--
 services/api/app/models/node.rb                    | 44 +++++++++++-----------
 services/api/app/models/repository.rb              |  6 +--
 services/api/app/models/user.rb                    | 18 ++++-----
 .../admin_notifier/new_inactive_user.text.erb      |  4 +-
 .../api/app/views/admin_notifier/new_user.text.erb |  6 +--
 .../views/user_notifier/account_is_setup.text.erb  |  4 +-
 services/api/config/arvados_config.rb              |  6 +++
 services/api/db/structure.sql                      |  1 +
 services/api/lib/audit_logs.rb                     |  4 +-
 services/api/lib/config_loader.rb                  |  4 +-
 services/api/lib/crunch_dispatch.rb                | 44 +++++++++++-----------
 services/api/lib/enable_jobs_api.rb                |  6 +--
 services/api/lib/josh_id.rb                        |  2 +-
 services/api/lib/load_param.rb                     |  2 +-
 services/api/lib/log_reuse_info.rb                 |  2 +-
 services/api/lib/refresh_permission_view.rb        |  4 +-
 services/api/lib/sweep_trashed_objects.rb          |  4 +-
 services/api/lib/tasks/config_check.rake           | 28 --------------
 services/api/lib/tasks/config_dump.rake            | 12 ------
 .../api/lib/tasks/delete_old_container_logs.rake   |  2 +-
 services/api/lib/tasks/delete_old_job_logs.rake    |  2 +-
 services/api/lib/trashable.rb                      |  6 +--
 40 files changed, 162 insertions(+), 191 deletions(-)
 delete mode 100644 services/api/lib/tasks/config_check.rake
 delete mode 100644 services/api/lib/tasks/config_dump.rake

       via  2ea729f97166cb5fda4a6ca0818f0a0ab15388ab (commit)
       via  dee79c4cf4eb34d80b925168e76d1114dfc02c2a (commit)
      from  0e5e80d054cc19c145f5bc02dfc3bd6271fde316 (commit)

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


commit 2ea729f97166cb5fda4a6ca0818f0a0ab15388ab
Author: Peter Amstutz <pamstutz at veritasgenetics.com>
Date:   Thu Apr 11 11:42:58 2019 -0400

    13996: Tweak rake tasks
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>

diff --git a/lib/config/config.default.yml b/lib/config/config.default.yml
index d46c5c0ae..bea638753 100644
--- a/lib/config/config.default.yml
+++ b/lib/config/config.default.yml
@@ -109,6 +109,11 @@ Clusters:
       # update on the permission view in the future, if not already scheduled.
       AsyncPermissionsUpdateInterval: 20
 
+      # RailsSessionSecretToken is a string of alphanumeric characters
+      # used by Rails to sign session tokens. IMPORTANT: This is a
+      # site secret. It should be at least 50 characters.
+      RailsSessionSecretToken: ""
+
     Users:
       # Config parameters to automatically setup new users.  If enabled,
       # this users will be able to self-activate.  Enable this if you want
diff --git a/services/api/config/arvados_config.rb b/services/api/config/arvados_config.rb
index f0eb55a8f..8817b8b10 100644
--- a/services/api/config/arvados_config.rb
+++ b/services/api/config/arvados_config.rb
@@ -67,6 +67,7 @@ arvcfg.declare_config "API.MaxRequestSize", Integer, :max_request_size
 arvcfg.declare_config "API.MaxIndexDatabaseRead", Integer, :max_index_database_read
 arvcfg.declare_config "API.MaxItemsPerResponse", Integer, :max_items_per_response
 arvcfg.declare_config "API.AsyncPermissionsUpdateInterval", ActiveSupport::Duration, :async_permissions_update_interval
+arvcfg.declare_config "API.RailsSessionSecretToken", NonemptyString, :secret_token
 arvcfg.declare_config "Users.AutoSetupNewUsers", Boolean, :auto_setup_new_users
 arvcfg.declare_config "Users.AutoSetupNewUsersWithVmUUID", String, :auto_setup_new_users_with_vm_uuid
 arvcfg.declare_config "Users.AutoSetupNewUsersWithRepository", Boolean, :auto_setup_new_users_with_repository
@@ -191,9 +192,14 @@ end
 
 # Checks for wrongly typed configuration items, and essential items
 # that can't be empty
+arvcfg.coercion_and_check $base_arvados_config, check_nonempty: false
 arvcfg.coercion_and_check $arvados_config
 dbcfg.coercion_and_check $arvados_config
 
+if $arvados_config["Collections"]["DefaultTrashLifetime"] < 86400.seconds then
+  raise "default_trash_lifetime is %d, must be at least 86400" % Rails.configuration.Collections.DefaultTrashLifetime
+end
+
 #
 # Special case for test database where there's no database.yml,
 # because the Arvados config.yml doesn't have a concept of multiple
diff --git a/services/api/lib/config_loader.rb b/services/api/lib/config_loader.rb
index 5cb6e2841..87bfd93fc 100644
--- a/services/api/lib/config_loader.rb
+++ b/services/api/lib/config_loader.rb
@@ -76,7 +76,7 @@ class ConfigLoader
     remainders
   end
 
-  def coercion_and_check check_cfg
+  def coercion_and_check check_cfg, check_nonempty: true
     @config_types.each do |cfgkey, cfgtype|
       cfg = check_cfg
       k = cfgkey
@@ -114,7 +114,7 @@ class ConfigLoader
       end
 
       if cfgtype == NonemptyString
-        if (!cfg[k] || cfg[k] == "")
+        if (!cfg[k] || cfg[k] == "") && check_nonempty
           raise "#{cfgkey} cannot be empty"
         end
         if cfg[k].is_a? String
diff --git a/services/api/lib/tasks/config_check.rake b/services/api/lib/tasks/config_check.rake
deleted file mode 100644
index 12e6dd91c..000000000
--- a/services/api/lib/tasks/config_check.rake
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-namespace :config do
-  desc 'Ensure site configuration has all required settings'
-  task check: :environment do
-    $stderr.puts "%-32s %s" % ["AppVersion (discovered)", AppVersion.hash]
-    $application_config.sort.each do |k, v|
-      if ENV.has_key?('QUIET') then
-        # Make sure we still check for the variable to exist
-        eval("Rails.configuration.#{k}")
-      else
-        if /(password|secret|signing_key)/.match(k) then
-          # Make sure we still check for the variable to exist, but don't print the value
-          eval("Rails.configuration.#{k}")
-          $stderr.puts "%-32s %s" % [k, '*********']
-        else
-          $stderr.puts "%-32s %s" % [k, eval("Rails.configuration.#{k}")]
-        end
-      end
-    end
-    # default_trash_lifetime cannot be less than 24 hours
-    if Rails.configuration.Collections.DefaultTrashLifetime < 86400 then
-      raise "default_trash_lifetime is %d, must be at least 86400" % Rails.configuration.Collections.DefaultTrashLifetime
-    end
-  end
-end
diff --git a/services/api/lib/tasks/config_dump.rake b/services/api/lib/tasks/config_dump.rake
deleted file mode 100644
index 1790a7950..000000000
--- a/services/api/lib/tasks/config_dump.rake
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) The Arvados Authors. All rights reserved.
-#
-# SPDX-License-Identifier: AGPL-3.0
-
-namespace :config do
-  desc 'Print active site configuration'
-  task dump: :environment do
-    combined = $arvados_config.deep_dup
-    combined.update $remaining_config
-    puts combined.to_yaml
-  end
-end

commit dee79c4cf4eb34d80b925168e76d1114dfc02c2a
Author: Peter Amstutz <pamstutz at veritasgenetics.com>
Date:   Thu Apr 11 10:34:14 2019 -0400

    13996: Update rest of code for cleaner config access
    
    Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz at veritasgenetics.com>

diff --git a/services/api/app/controllers/application_controller.rb b/services/api/app/controllers/application_controller.rb
index 5c97735f2..e1cb1ba8e 100644
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@ -81,8 +81,8 @@ class ApplicationController < ActionController::Base
 
   def default_url_options
     options = {}
-    if Rails.configuration.Services["Controller"]["ExternalURL"] != ""
-      exturl = URI.parse(Rails.configuration.Services["Controller"]["ExternalURL"])
+    if Rails.configuration.Services.Controller.ExternalURL != ""
+      exturl = URI.parse(Rails.configuration.Services.Controller.ExternalURL)
       options[:host] = exturl.host
       options[:port] = exturl.port
       options[:protocol] = exturl.scheme
@@ -301,7 +301,7 @@ class ApplicationController < ActionController::Base
       limit_query.each do |record|
         new_limit += 1
         read_total += record.read_length.to_i
-        if read_total >= Rails.configuration.API["MaxIndexDatabaseRead"]
+        if read_total >= Rails.configuration.API.MaxIndexDatabaseRead
           new_limit -= 1 if new_limit > 1
           @limit = new_limit
           break
@@ -414,8 +414,7 @@ class ApplicationController < ActionController::Base
   end
 
   def disable_api_methods
-    if Rails.configuration.API["DisabledAPIs"].
-        include?(controller_name + "." + action_name)
+    if Rails.configuration.API.DisabledAPIs.include?(controller_name + "." + action_name)
       send_error("Disabled", status: 404)
     end
   end
diff --git a/services/api/app/controllers/arvados/v1/groups_controller.rb b/services/api/app/controllers/arvados/v1/groups_controller.rb
index 825f9950d..1004f0702 100644
--- a/services/api/app/controllers/arvados/v1/groups_controller.rb
+++ b/services/api/app/controllers/arvados/v1/groups_controller.rb
@@ -191,7 +191,7 @@ class Arvados::V1::GroupsController < ApplicationController
 
     table_names = Hash[klasses.collect { |k| [k, k.table_name] }]
 
-    disabled_methods = Rails.configuration.API["DisabledAPIs"]
+    disabled_methods = Rails.configuration.API.DisabledAPIs
     avail_klasses = table_names.select{|k, t| !disabled_methods.include?(t+'.index')}
     klasses = avail_klasses.keys
 
diff --git a/services/api/app/controllers/arvados/v1/schema_controller.rb b/services/api/app/controllers/arvados/v1/schema_controller.rb
index d67568d43..13e47f76c 100644
--- a/services/api/app/controllers/arvados/v1/schema_controller.rb
+++ b/services/api/app/controllers/arvados/v1/schema_controller.rb
@@ -41,7 +41,7 @@ class Arvados::V1::SchemaController < ApplicationController
         title: "Arvados API",
         description: "The API to interact with Arvados.",
         documentationLink: "http://doc.arvados.org/api/index.html",
-        defaultCollectionReplication: Rails.configuration.Collections["DefaultReplication"],
+        defaultCollectionReplication: Rails.configuration.Collections.DefaultReplication,
         protocol: "rest",
         baseUrl: root_url + "arvados/v1/",
         basePath: "/arvados/v1/",
@@ -49,26 +49,26 @@ class Arvados::V1::SchemaController < ApplicationController
         servicePath: "arvados/v1/",
         batchPath: "batch",
         uuidPrefix: Rails.configuration.ClusterID,
-        defaultTrashLifetime: Rails.configuration.Collections["DefaultTrashLifetime"],
-        blobSignatureTtl: Rails.configuration.Collections["BlobSigningTTL"],
-        maxRequestSize: Rails.configuration.API["MaxRequestSize"],
-        maxItemsPerResponse: Rails.configuration.API["MaxItemsPerResponse"],
-        dockerImageFormats: Rails.configuration.Containers["SupportedDockerImageFormats"],
-        crunchLogBytesPerEvent: Rails.configuration.Containers["Logging"]["LogBytesPerEvent"],
-        crunchLogSecondsBetweenEvents: Rails.configuration.Containers["Logging"]["LogSecondsBetweenEvents"],
-        crunchLogThrottlePeriod: Rails.configuration.Containers["Logging"]["LogThrottlePeriod"],
-        crunchLogThrottleBytes: Rails.configuration.Containers["Logging"]["LogThrottleBytes"],
-        crunchLogThrottleLines: Rails.configuration.Containers["Logging"]["LogThrottleLines"],
-        crunchLimitLogBytesPerJob: Rails.configuration.Containers["Logging"]["LimitLogBytesPerJob"],
-        crunchLogPartialLineThrottlePeriod: Rails.configuration.Containers["Logging"]["LogPartialLineThrottlePeriod"],
-        crunchLogUpdatePeriod: Rails.configuration.Containers["Logging"]["LogUpdatePeriod"],
-        crunchLogUpdateSize: Rails.configuration.Containers["Logging"]["LogUpdateSize"],
+        defaultTrashLifetime: Rails.configuration.Collections.DefaultTrashLifetime,
+        blobSignatureTtl: Rails.configuration.Collections.BlobSigningTTL,
+        maxRequestSize: Rails.configuration.API.MaxRequestSize,
+        maxItemsPerResponse: Rails.configuration.API.MaxItemsPerResponse,
+        dockerImageFormats: Rails.configuration.Containers.SupportedDockerImageFormats,
+        crunchLogBytesPerEvent: Rails.configuration.Containers.Logging.LogBytesPerEvent,
+        crunchLogSecondsBetweenEvents: Rails.configuration.Containers.Logging.LogSecondsBetweenEvents,
+        crunchLogThrottlePeriod: Rails.configuration.Containers.Logging.LogThrottlePeriod,
+        crunchLogThrottleBytes: Rails.configuration.Containers.Logging.LogThrottleBytes,
+        crunchLogThrottleLines: Rails.configuration.Containers.Logging.LogThrottleLines,
+        crunchLimitLogBytesPerJob: Rails.configuration.Containers.Logging.LimitLogBytesPerJob,
+        crunchLogPartialLineThrottlePeriod: Rails.configuration.Containers.Logging.LogPartialLineThrottlePeriod,
+        crunchLogUpdatePeriod: Rails.configuration.Containers.Logging.LogUpdatePeriod,
+        crunchLogUpdateSize: Rails.configuration.Containers.Logging.LogUpdateSize,
         remoteHosts: remoteHosts,
-        remoteHostsViaDNS: Rails.configuration.RemoteClusters["*"]["Proxy"],
-        websocketUrl: Rails.configuration.Services["Websocket"]["ExternalURL"].to_s,
-        workbenchUrl: Rails.configuration.Services["Workbench1"]["ExternalURL"].to_s,
-        keepWebServiceUrl: Rails.configuration.Services["WebDAV"]["ExternalURL"].to_s,
-        gitUrl: Rails.configuration.Services["GitHTTP"]["ExternalURL"].to_s,
+        remoteHostsViaDNS: Rails.configuration.RemoteClusters["*"].Proxy,
+        websocketUrl: Rails.configuration.Services.Websocket.ExternalURL.to_s,
+        workbenchUrl: Rails.configuration.Services.Workbench1.ExternalURL.to_s,
+        keepWebServiceUrl: Rails.configuration.Services.WebDAV.ExternalURL.to_s,
+        gitUrl: Rails.configuration.Services.GitHTTP.ExternalURL.to_s,
         parameters: {
           alt: {
             type: "string",
@@ -400,7 +400,7 @@ class Arvados::V1::SchemaController < ApplicationController
           end
         end
       end
-      Rails.configuration.API["DisabledAPIs"].each do |method|
+      Rails.configuration.API.DisabledAPIs.each do |method|
         ctrl, action = method.split('.', 2)
         discovery[:resources][ctrl][:methods].delete(action.to_sym)
       end
diff --git a/services/api/app/controllers/static_controller.rb b/services/api/app/controllers/static_controller.rb
index 6923f43cb..736557787 100644
--- a/services/api/app/controllers/static_controller.rb
+++ b/services/api/app/controllers/static_controller.rb
@@ -12,8 +12,8 @@ class StaticController < ApplicationController
   def home
     respond_to do |f|
       f.html do
-        if !Rails.configuration.Services["Workbench1"]["ExternalURL"].to_s.empty?
-          redirect_to Rails.configuration.Services["Workbench1"]["ExternalURL"]
+        if !Rails.configuration.Services.Workbench1.ExternalURL.to_s.empty?
+          redirect_to Rails.configuration.Services.Workbench1.ExternalURL
         else
           render_not_found "Oops, this is an API endpoint. You probably want to point your browser to an Arvados Workbench site instead."
         end
diff --git a/services/api/app/controllers/user_sessions_controller.rb b/services/api/app/controllers/user_sessions_controller.rb
index cab544263..6e18cdd46 100644
--- a/services/api/app/controllers/user_sessions_controller.rb
+++ b/services/api/app/controllers/user_sessions_controller.rb
@@ -52,7 +52,7 @@ class UserSessionsController < ApplicationController
                       :first_name => omniauth['info']['first_name'],
                       :last_name => omniauth['info']['last_name'],
                       :identity_url => omniauth['info']['identity_url'],
-                      :is_active => Rails.configuration.Users["NewUsersAreActive"],
+                      :is_active => Rails.configuration.Users.NewUsersAreActive,
                       :owner_uuid => system_user_uuid)
       if omniauth['info']['username']
         user.set_initial_username(requested: omniauth['info']['username'])
@@ -120,7 +120,7 @@ class UserSessionsController < ApplicationController
 
     flash[:notice] = 'You have logged off'
     return_to = params[:return_to] || root_url
-    redirect_to "#{Rails.configuration.Services["SSO"]["ExternalURL"]}/users/sign_out?redirect_uri=#{CGI.escape return_to}"
+    redirect_to "#{Rails.configuration.Services.SSO.ExternalURL}/users/sign_out?redirect_uri=#{CGI.escape return_to}"
   end
 
   # login - Just bounce to /auth/joshid. The only purpose of this function is
diff --git a/services/api/app/mailers/admin_notifier.rb b/services/api/app/mailers/admin_notifier.rb
index e454d64e0..45e329030 100644
--- a/services/api/app/mailers/admin_notifier.rb
+++ b/services/api/app/mailers/admin_notifier.rb
@@ -5,32 +5,32 @@
 class AdminNotifier < ActionMailer::Base
   include AbstractController::Callbacks
 
-  default from: Rails.configuration.Users["AdminNotifierEmailFrom"]
+  default from: Rails.configuration.Users.AdminNotifierEmailFrom
 
   def new_user(user)
     @user = user
-    if not Rails.configuration.Users["NewUserNotificationRecipients"].empty? then
-      @recipients = Rails.configuration.Users["NewUserNotificationRecipients"]
+    if not Rails.configuration.Users.NewUserNotificationRecipients.empty? then
+      @recipients = Rails.configuration.Users.NewUserNotificationRecipients
       logger.info "Sending mail to #{@recipients} about new user #{@user.uuid} (#{@user.full_name} <#{@user.email}>)"
 
       add_to_subject = ''
-      if Rails.configuration.Users["AutoSetupNewUsers"]
+      if Rails.configuration.Users.AutoSetupNewUsers
         add_to_subject = @user.is_invited ? ' and setup' : ', but not setup'
       end
 
       mail(to: @recipients,
-           subject: "#{Rails.configuration.Users["EmailSubjectPrefix"]}New user created#{add_to_subject} notification"
+           subject: "#{Rails.configuration.Users.EmailSubjectPrefix}New user created#{add_to_subject} notification"
           )
     end
   end
 
   def new_inactive_user(user)
     @user = user
-    if not Rails.configuration.Users["NewInactiveUserNotificationRecipients"].empty? then
-      @recipients = Rails.configuration.Users["NewInactiveUserNotificationRecipients"]
+    if not Rails.configuration.Users.NewInactiveUserNotificationRecipients.empty? then
+      @recipients = Rails.configuration.Users.NewInactiveUserNotificationRecipients
       logger.info "Sending mail to #{@recipients} about new user #{@user.uuid} (#{@user.full_name} <#{@user.email}>)"
       mail(to: @recipients,
-           subject: "#{Rails.configuration.Users["EmailSubjectPrefix"]}New inactive user notification"
+           subject: "#{Rails.configuration.Users.EmailSubjectPrefix}New inactive user notification"
           )
     end
   end
diff --git a/services/api/app/mailers/profile_notifier.rb b/services/api/app/mailers/profile_notifier.rb
index a23d5f345..849eefe8e 100644
--- a/services/api/app/mailers/profile_notifier.rb
+++ b/services/api/app/mailers/profile_notifier.rb
@@ -3,7 +3,7 @@
 # SPDX-License-Identifier: AGPL-3.0
 
 class ProfileNotifier < ActionMailer::Base
-  default from: Rails.configuration.Users["AdminNotifierEmailFrom"]
+  default from: Rails.configuration.Users.AdminNotifierEmailFrom
 
   def profile_created(user, address)
     @user = user
diff --git a/services/api/app/mailers/user_notifier.rb b/services/api/app/mailers/user_notifier.rb
index dbde7a973..3d1b91f20 100644
--- a/services/api/app/mailers/user_notifier.rb
+++ b/services/api/app/mailers/user_notifier.rb
@@ -5,7 +5,7 @@
 class UserNotifier < ActionMailer::Base
   include AbstractController::Callbacks
 
-  default from: Rails.configuration.Users["UserNotifierEmailFrom"]
+  default from: Rails.configuration.Users.UserNotifierEmailFrom
 
   def account_is_setup(user)
     @user = user
diff --git a/services/api/app/models/api_client_authorization.rb b/services/api/app/models/api_client_authorization.rb
index 4aaa2ef44..69d2945fc 100644
--- a/services/api/app/models/api_client_authorization.rb
+++ b/services/api/app/models/api_client_authorization.rb
@@ -153,7 +153,7 @@ class ApiClientAuthorization < ArvadosModel
       # [re]validate it.
       begin
         clnt = HTTPClient.new
-        if Rails.configuration.TLS["Insecure"]
+        if Rails.configuration.TLS.Insecure
           clnt.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
         else
           # Use system CA certificates
@@ -187,7 +187,7 @@ class ApiClientAuthorization < ArvadosModel
           end
         end
 
-        if Rails.configuration.Users["NewUsersAreActive"] ||
+        if Rails.configuration.Users.NewUsersAreActive ||
            Rails.configuration.RemoteClusters[remote_user['uuid'][0..4]].andand["ActivateUsers"]
           # Update is_active to whatever it is at the remote end
           user.is_active = remote_user['is_active']
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 00f60e6fb..339bc9e23 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -411,7 +411,7 @@ class ArvadosModel < ApplicationRecord
   end
 
   def logged_attributes
-    attributes.except(*Rails.configuration.AuditLogs["UnloggedAttributes"])
+    attributes.except(*Rails.configuration.AuditLogs.UnloggedAttributes)
   end
 
   def self.full_text_searchable_columns
@@ -814,8 +814,8 @@ class ArvadosModel < ApplicationRecord
   end
 
   def is_audit_logging_enabled?
-    return !(Rails.configuration.AuditLogs["MaxAge"].to_i == 0 &&
-             Rails.configuration.AuditLogs["MaxDeleteBatch"].to_i > 0)
+    return !(Rails.configuration.AuditLogs.MaxAge.to_i == 0 &&
+             Rails.configuration.AuditLogs.MaxDeleteBatch.to_i > 0)
   end
 
   def log_start_state
diff --git a/services/api/app/models/blob.rb b/services/api/app/models/blob.rb
index 500a66279..54a4f369d 100644
--- a/services/api/app/models/blob.rb
+++ b/services/api/app/models/blob.rb
@@ -51,15 +51,15 @@ class Blob
       timestamp = opts[:expire]
     else
       timestamp = db_current_time.to_i +
-        (opts[:ttl] || Rails.configuration.Collections["BlobSigningTTL"])
+        (opts[:ttl] || Rails.configuration.Collections.BlobSigningTTL)
     end
     timestamp_hex = timestamp.to_s(16)
     # => "53163cb4"
-    blob_signature_ttl = Rails.configuration.Collections["BlobSigningTTL"].to_s(16)
+    blob_signature_ttl = Rails.configuration.Collections.BlobSigningTTL.to_s(16)
 
     # Generate a signature.
     signature =
-      generate_signature((opts[:key] or Rails.configuration.Collections["BlobSigningKey"]),
+      generate_signature((opts[:key] or Rails.configuration.Collections.BlobSigningKey),
                          blob_hash, opts[:api_token], timestamp_hex, blob_signature_ttl)
 
     blob_locator + '+A' + signature + '@' + timestamp_hex
@@ -103,10 +103,10 @@ class Blob
     if timestamp.to_i(16) < (opts[:now] or db_current_time.to_i)
       raise Blob::InvalidSignatureError.new 'Signature expiry time has passed.'
     end
-    blob_signature_ttl = Rails.configuration.Collections["BlobSigningTTL"].to_s(16)
+    blob_signature_ttl = Rails.configuration.Collections.BlobSigningTTL.to_s(16)
 
     my_signature =
-      generate_signature((opts[:key] or Rails.configuration.Collections["BlobSigningKey"]),
+      generate_signature((opts[:key] or Rails.configuration.Collections.BlobSigningKey),
                          blob_hash, opts[:api_token], timestamp, blob_signature_ttl)
 
     if my_signature != given_signature
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index a7d357ec6..e0f653969 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -125,7 +125,7 @@ class Collection < ArvadosModel
             # Signature provided, but verify_signature did not like it.
             logger.warn "Invalid signature on locator #{tok}"
             raise ArvadosModel::PermissionDeniedError
-          elsif !Rails.configuration.Collections["BlobSigning"]
+          elsif !Rails.configuration.Collections.BlobSigning
             # No signature provided, but we are running in insecure mode.
             logger.debug "Missing signature on locator #{tok} ignored"
           elsif Blob.new(tok).empty?
@@ -323,9 +323,9 @@ class Collection < ArvadosModel
   end
 
   def should_preserve_version?
-    return false unless (Rails.configuration.Collections["CollectionVersioning"] && versionable_updates?(self.changes.keys))
+    return false unless (Rails.configuration.Collections.CollectionVersioning && versionable_updates?(self.changes.keys))
 
-    idle_threshold = Rails.configuration.Collections["PreserveVersionIfIdle"]
+    idle_threshold = Rails.configuration.Collections.PreserveVersionIfIdle
     if !self.preserve_version_was &&
       (idle_threshold < 0 ||
         (idle_threshold > 0 && self.modified_at_was > db_current_time-idle_threshold.seconds))
@@ -371,7 +371,7 @@ class Collection < ArvadosModel
       return manifest_text
     else
       token = Thread.current[:token]
-      exp = [db_current_time.to_i + Rails.configuration.Collections["BlobSigningTTL"],
+      exp = [db_current_time.to_i + Rails.configuration.Collections.BlobSigningTTL,
              trash_at].compact.map(&:to_i).min
       self.class.sign_manifest manifest_text, token, exp
     end
@@ -379,7 +379,7 @@ class Collection < ArvadosModel
 
   def self.sign_manifest manifest, token, exp=nil
     if exp.nil?
-      exp = db_current_time.to_i + Rails.configuration.Collections["BlobSigningTTL"]
+      exp = db_current_time.to_i + Rails.configuration.Collections.BlobSigningTTL
     end
     signing_opts = {
       api_token: token,
@@ -489,7 +489,7 @@ class Collection < ArvadosModel
   #
   # If filter_compatible_format is true (the default), only return image
   # collections which are support by the installation as indicated by
-  # Rails.configuration.Containers["SupportedDockerImageFormats"].  Will follow
+  # Rails.configuration.Containers.SupportedDockerImageFormats.  Will follow
   # 'docker_image_migration' links if search_term resolves to an incompatible
   # image, but an equivalent compatible image is available.
   def self.find_all_for_docker_image(search_term, search_tag=nil, readers=nil, filter_compatible_format: true)
@@ -500,7 +500,7 @@ class Collection < ArvadosModel
       joins("JOIN collections ON links.head_uuid = collections.uuid").
       order("links.created_at DESC")
 
-    docker_image_formats = Rails.configuration.Containers["SupportedDockerImageFormats"]
+    docker_image_formats = Rails.configuration.Containers.SupportedDockerImageFormats
 
     if (docker_image_formats.include? 'v1' and
         docker_image_formats.include? 'v2') or filter_compatible_format == false
diff --git a/services/api/app/models/commit.rb b/services/api/app/models/commit.rb
index ed3c5cd35..a3cef6421 100644
--- a/services/api/app/models/commit.rb
+++ b/services/api/app/models/commit.rb
@@ -148,7 +148,7 @@ class Commit < ActiveRecord::Base
     unless src_gitdir
       raise ArgumentError.new "no local repository for #{repo_name}"
     end
-    dst_gitdir = Rails.configuration.Containers["JobsAPI"]["GitInternalDir"]
+    dst_gitdir = Rails.configuration.Containers.JobsAPI.GitInternalDir
 
     begin
       commit_in_dst = must_git(dst_gitdir, "log -n1 --format=%H #{sha1.shellescape}^{commit}").strip
diff --git a/services/api/app/models/commit_ancestor.rb b/services/api/app/models/commit_ancestor.rb
index 60798f103..59e8552f3 100644
--- a/services/api/app/models/commit_ancestor.rb
+++ b/services/api/app/models/commit_ancestor.rb
@@ -17,7 +17,7 @@ class CommitAncestor < ActiveRecord::Base
   protected
 
   def ask_git_whether_is
-    @gitdirbase = Rails.configuration.Git["Repositories"]
+    @gitdirbase = Rails.configuration.Git.Repositories
     self.is = nil
     Dir.foreach @gitdirbase do |repo|
       next if repo.match(/^\./)
diff --git a/services/api/app/models/container.rb b/services/api/app/models/container.rb
index a95a166dd..95691687e 100644
--- a/services/api/app/models/container.rb
+++ b/services/api/app/models/container.rb
@@ -205,7 +205,7 @@ class Container < ArvadosModel
     rc = {}
     defaults = {
       'keep_cache_ram' =>
-      Rails.configuration.Containers["DefaultKeepCacheRAM"],
+      Rails.configuration.Containers.DefaultKeepCacheRAM,
     }
     defaults.merge(runtime_constraints).each do |k, v|
       if v.is_a? Array
@@ -368,7 +368,7 @@ class Container < ArvadosModel
     transaction do
       reload(lock: 'FOR UPDATE')
       check_unlock_fail
-      if self.lock_count < Rails.configuration.Containers["MaxDispatchAttempts"]
+      if self.lock_count < Rails.configuration.Containers.MaxDispatchAttempts
         update_attributes!(state: Queued)
       else
         update_attributes!(state: Cancelled,
diff --git a/services/api/app/models/container_request.rb b/services/api/app/models/container_request.rb
index f2e3d3122..24882860e 100644
--- a/services/api/app/models/container_request.rb
+++ b/services/api/app/models/container_request.rb
@@ -196,7 +196,7 @@ class ContainerRequest < ArvadosModel
     self.mounts ||= {}
     self.secret_mounts ||= {}
     self.cwd ||= "."
-    self.container_count_max ||= Rails.configuration.Containers["MaxComputeVMs"]
+    self.container_count_max ||= Rails.configuration.Containers.MaxComputeVMs
     self.scheduling_parameters ||= {}
     self.output_ttl ||= 0
     self.priority ||= 0
@@ -252,7 +252,7 @@ class ContainerRequest < ArvadosModel
     if self.state == Committed
       # If preemptible instances (eg: AWS Spot Instances) are allowed,
       # ask them on child containers by default.
-      if Rails.configuration.Containers["UsePreemptibleInstances"] and !c.nil? and
+      if Rails.configuration.Containers.UsePreemptibleInstances and !c.nil? and
         self.scheduling_parameters['preemptible'].nil?
           self.scheduling_parameters['preemptible'] = true
       end
@@ -322,7 +322,7 @@ class ContainerRequest < ArvadosModel
             scheduling_parameters['partitions'].size)
             errors.add :scheduling_parameters, "partitions must be an array of strings"
       end
-      if !Rails.configuration.Containers["UsePreemptibleInstances"] and scheduling_parameters['preemptible']
+      if !Rails.configuration.Containers.UsePreemptibleInstances and scheduling_parameters['preemptible']
         errors.add :scheduling_parameters, "preemptible instances are not allowed"
       end
       if scheduling_parameters.include? 'max_run_time' and
diff --git a/services/api/app/models/job.rb b/services/api/app/models/job.rb
index b24df8cbd..4d63deb99 100644
--- a/services/api/app/models/job.rb
+++ b/services/api/app/models/job.rb
@@ -287,7 +287,7 @@ class Job < ArvadosModel
         log_reuse_info { "job #{j.uuid} has nil output" }
       elsif j.log.nil?
         log_reuse_info { "job #{j.uuid} has nil log" }
-      elsif Rails.configuration.Containers["JobsAPI"]["ReuseJobIfOutputsDiffer"]
+      elsif Rails.configuration.Containers.JobsAPI.ReuseJobIfOutputsDiffer
         if !Collection.readable_by(current_user).find_by_portable_data_hash(j.output)
           # Ignore: keep looking for an incomplete job or one whose
           # output is readable.
@@ -491,9 +491,9 @@ class Job < ArvadosModel
   end
 
   def find_docker_image_locator
-    if runtime_constraints.is_a? Hash and Rails.configuration.Containers["JobsAPI"]["DefaultDockerImage"] != ""
+    if runtime_constraints.is_a? Hash and Rails.configuration.Containers.JobsAPI.DefaultDockerImage != ""
       runtime_constraints['docker_image'] ||=
-        Rails.configuration.Containers["JobsAPI"]["DefaultDockerImage"]
+        Rails.configuration.Containers.JobsAPI.DefaultDockerImage
     end
 
     resolve_runtime_constraint("docker_image",
@@ -569,7 +569,7 @@ class Job < ArvadosModel
 
   def trigger_crunch_dispatch_if_cancelled
     if @need_crunch_dispatch_trigger
-      File.open(Rails.configuration.Containers["JobsAPI"]["CrunchRefreshTrigger"], 'wb') do
+      File.open(Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger, 'wb') do
         # That's all, just create/touch a file for crunch-job to see.
       end
     end
diff --git a/services/api/app/models/node.rb b/services/api/app/models/node.rb
index 0a10be80e..044d83c28 100644
--- a/services/api/app/models/node.rb
+++ b/services/api/app/models/node.rb
@@ -39,7 +39,7 @@ class Node < ArvadosModel
   api_accessible :superuser, :extend => :user do |t|
     t.add :first_ping_at
     t.add :info
-    t.add lambda { |x| Rails.configuration.Containers["SLURM"]["Managed"]["ComputeNodeNameservers"] }, :as => :nameservers
+    t.add lambda { |x| Rails.configuration.Containers.SLURM.Managed.ComputeNodeNameservers }, :as => :nameservers
   end
 
   after_initialize do
@@ -47,7 +47,7 @@ class Node < ArvadosModel
   end
 
   def domain
-    super || Rails.configuration.Containers["SLURM"]["Managed"]["ComputeNodeDomain"]
+    super || Rails.configuration.Containers.SLURM.Managed.ComputeNodeDomain
   end
 
   def api_job_uuid
@@ -143,7 +143,7 @@ class Node < ArvadosModel
   protected
 
   def assign_hostname
-    if self.hostname.nil? and Rails.configuration.Containers["SLURM"]["Managed"]["AssignNodeHostname"]
+    if self.hostname.nil? and Rails.configuration.Containers.SLURM.Managed.AssignNodeHostname
       self.hostname = self.class.hostname_for_slot(self.slot_number)
     end
   end
@@ -159,7 +159,7 @@ class Node < ArvadosModel
                           # query label:
                           'Node.available_slot_number',
                           # [col_id, val] for $1 vars:
-                          [[nil, Rails.configuration.Containers["MaxComputeVMs"]]],
+                          [[nil, Rails.configuration.Containers.MaxComputeVMs]],
                          ).rows.first.andand.first
   end
 
@@ -199,20 +199,20 @@ class Node < ArvadosModel
       ptr_domain: ptr_domain,
     }
 
-    if (!Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"].to_s.empty? and
-        !Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfTemplate"].to_s.empty?)
+    if (!Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir.to_s.empty? and
+        !Rails.configuration.Containers.SLURM.Managed.DNSServerConfTemplate.to_s.empty?)
       tmpfile = nil
       begin
         begin
-          template = IO.read(Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfTemplate"])
+          template = IO.read(Rails.configuration.Containers.SLURM.Managed.DNSServerConfTemplate)
         rescue IOError, SystemCallError => e
-          logger.error "Reading #{Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfTemplate"]}: #{e.message}"
+          logger.error "Reading #{Rails.configuration.Containers.SLURM.Managed.DNSServerConfTemplate}: #{e.message}"
           raise
         end
 
-        hostfile = File.join Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"], "#{hostname}.conf"
+        hostfile = File.join Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir, "#{hostname}.conf"
         Tempfile.open(["#{hostname}-", ".conf.tmp"],
-                                 Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"]) do |f|
+                                 Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir) do |f|
           tmpfile = f.path
           f.puts template % template_vars
         end
@@ -228,21 +228,21 @@ class Node < ArvadosModel
       end
     end
 
-    if !Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerUpdateCommand"].empty?
-      cmd = Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerUpdateCommand"] % template_vars
+    if !Rails.configuration.Containers.SLURM.Managed.DNSServerUpdateCommand.empty?
+      cmd = Rails.configuration.Containers.SLURM.Managed.DNSServerUpdateCommand % template_vars
       if not system cmd
         logger.error "dns_server_update_command #{cmd.inspect} failed: #{$?}"
         ok = false
       end
     end
 
-    if (!Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"].to_s.empty? and
-        !Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerReloadCommand"].to_s.empty?)
-      restartfile = File.join(Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"], 'restart.txt')
+    if (!Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir.to_s.empty? and
+        !Rails.configuration.Containers.SLURM.Managed.DNSServerReloadCommand.to_s.empty?)
+      restartfile = File.join(Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir, 'restart.txt')
       begin
         File.open(restartfile, 'w') do |f|
           # Typically, this is used to trigger a dns server restart
-          f.puts Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerReloadCommand"]
+          f.puts Rails.configuration.Containers.SLURM.Managed.DNSServerReloadCommand
         end
       rescue IOError, SystemCallError => e
         logger.error "Unable to write #{restartfile}: #{e.message}"
@@ -254,7 +254,7 @@ class Node < ArvadosModel
   end
 
   def self.hostname_for_slot(slot_number)
-    config = Rails.configuration.Containers["SLURM"]["Managed"]["AssignNodeHostname"]
+    config = Rails.configuration.Containers.SLURM.Managed.AssignNodeHostname
 
     return nil if !config
 
@@ -263,13 +263,13 @@ class Node < ArvadosModel
 
   # At startup, make sure all DNS entries exist.  Otherwise, slurmctld
   # will refuse to start.
-  if (!Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"].to_s.empty? and
-      !Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfTemplate"].to_s.empty? and
-      !Rails.configuration.Containers["SLURM"]["Managed"]["AssignNodeHostname"].empty?)
+  if (!Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir.to_s.empty? and
+      !Rails.configuration.Containers.SLURM.Managed.DNSServerConfTemplate.to_s.empty? and
+      !Rails.configuration.Containers.SLURM.Managed.AssignNodeHostname.empty?)
 
-    (0..Rails.configuration.Containers["MaxComputeVMs"]-1).each do |slot_number|
+    (0..Rails.configuration.Containers.MaxComputeVMs-1).each do |slot_number|
       hostname = hostname_for_slot(slot_number)
-      hostfile = File.join Rails.configuration.Containers["SLURM"]["Managed"]["DNSServerConfDir"], "#{hostname}.conf"
+      hostfile = File.join Rails.configuration.Containers.SLURM.Managed.DNSServerConfDir, "#{hostname}.conf"
       if !File.exist? hostfile
         n = Node.where(:slot_number => slot_number).first
         if n.nil? or n.ip_address.nil?
diff --git a/services/api/app/models/repository.rb b/services/api/app/models/repository.rb
index 7cb36dcb9..5e0e39f9b 100644
--- a/services/api/app/models/repository.rb
+++ b/services/api/app/models/repository.rb
@@ -49,7 +49,7 @@ class Repository < ArvadosModel
     # prefers bare repositories over checkouts.
     [["%s.git"], ["%s", ".git"]].each do |repo_base, *join_args|
       [:uuid, :name].each do |path_attr|
-        git_dir = File.join(Rails.configuration.Git["Repositories"],
+        git_dir = File.join(Rails.configuration.Git.Repositories,
                             repo_base % send(path_attr), *join_args)
         return git_dir if File.exist?(git_dir)
       end
@@ -98,11 +98,11 @@ class Repository < ArvadosModel
   end
 
   def ssh_clone_url
-    _clone_url Rails.configuration.Services["GitSSH"].andand["ExternalURL"], 'ssh://git@git.%s.arvadosapi.com'
+    _clone_url Rails.configuration.Services.GitSSH.andand.ExternalURL, 'ssh://git@git.%s.arvadosapi.com'
   end
 
   def https_clone_url
-    _clone_url Rails.configuration.Services["GitHTTP"].andand["ExternalURL"], 'https://git.%s.arvadosapi.com/'
+    _clone_url Rails.configuration.Services.GitHTTP.andand.ExternalURL, 'https://git.%s.arvadosapi.com/'
   end
 
   def _clone_url config_var, default_base_fmt
diff --git a/services/api/app/models/user.rb b/services/api/app/models/user.rb
index 17ee4d999..989a97592 100644
--- a/services/api/app/models/user.rb
+++ b/services/api/app/models/user.rb
@@ -34,7 +34,7 @@ class User < ArvadosModel
   after_create :add_system_group_permission_link
   after_create :invalidate_permissions_cache
   after_create :auto_setup_new_user, :if => Proc.new { |user|
-    Rails.configuration.Users["AutoSetupNewUsers"] and
+    Rails.configuration.Users.AutoSetupNewUsers and
     (user.uuid != system_user_uuid) and
     (user.uuid != anonymous_user_uuid)
   }
@@ -81,7 +81,7 @@ class User < ArvadosModel
 
   def is_invited
     !!(self.is_active ||
-       Rails.configuration.Users["NewUsersAreActive"] ||
+       Rails.configuration.Users.NewUsersAreActive ||
        self.groups_i_can(:read).select { |x| x.match(/-f+$/) }.first)
   end
 
@@ -358,15 +358,15 @@ class User < ArvadosModel
     current_user.andand.is_admin or
       (self == current_user &&
        self.redirect_to_user_uuid.nil? &&
-       self.is_active == Rails.configuration.Users["NewUsersAreActive"])
+       self.is_active == Rails.configuration.Users.NewUsersAreActive)
   end
 
   def check_auto_admin
     return if self.uuid.end_with?('anonymouspublic')
     if (User.where("email = ?",self.email).where(:is_admin => true).count == 0 and
-        !Rails.configuration.Users["AutoAdminUserWithEmail"].empty? and self.email == Rails.configuration.Users["AutoAdminUserWithEmail"]) or
+        !Rails.configuration.Users.AutoAdminUserWithEmail.empty? and self.email == Rails.configuration.Users["AutoAdminUserWithEmail"]) or
        (User.where("uuid not like '%-000000000000000'").where(:is_admin => true).count == 0 and
-        Rails.configuration.Users["AutoAdminFirstUser"])
+        Rails.configuration.Users.AutoAdminFirstUser)
       self.is_admin = true
       self.is_active = true
     end
@@ -381,7 +381,7 @@ class User < ArvadosModel
     quoted_name = self.class.connection.quote_string(basename)
     next_username = basename
     next_suffix = 1
-    while Rails.configuration.Users["AutoSetupUsernameBlacklist"].include?(next_username)
+    while Rails.configuration.Users.AutoSetupUsernameBlacklist.include?(next_username)
       next_suffix += 1
       next_username = "%s%i" % [basename, next_suffix]
     end
@@ -563,10 +563,10 @@ class User < ArvadosModel
   def auto_setup_new_user
     setup(openid_prefix: Rails.configuration.default_openid_prefix)
     if username
-      create_vm_login_permission_link(Rails.configuration.Users["AutoSetupNewUsersWithVmUUID"],
+      create_vm_login_permission_link(Rails.configuration.Users.AutoSetupNewUsersWithVmUUID,
                                       username)
       repo_name = "#{username}/#{username}"
-      if Rails.configuration.Users["AutoSetupNewUsersWithRepository"] and
+      if Rails.configuration.Users.AutoSetupNewUsersWithRepository and
           Repository.where(name: repo_name).first.nil?
         repo = Repository.create!(name: repo_name, owner_uuid: uuid)
         Link.create!(tail_uuid: uuid, head_uuid: repo.uuid,
@@ -579,7 +579,7 @@ class User < ArvadosModel
   def send_profile_created_notification
     if self.prefs_changed?
       if self.prefs_was.andand.empty? || !self.prefs_was.andand['profile']
-        profile_notification_address = Rails.configuration.Users["UserProfileNotificationAddress"]
+        profile_notification_address = Rails.configuration.Users.UserProfileNotificationAddress
         ProfileNotifier.profile_created(self, profile_notification_address).deliver_now if profile_notification_address
       end
     end
diff --git a/services/api/app/views/admin_notifier/new_inactive_user.text.erb b/services/api/app/views/admin_notifier/new_inactive_user.text.erb
index fa8652b8a..afcf34da7 100644
--- a/services/api/app/views/admin_notifier/new_inactive_user.text.erb
+++ b/services/api/app/views/admin_notifier/new_inactive_user.text.erb
@@ -7,10 +7,10 @@ A new user landed on the inactive user page:
 
   <%= @user.full_name %> <<%= @user.email %>>
 
-<% if Rails.configuration.Services["Workbench1"]["ExternalURL"] -%>
+<% if Rails.configuration.Services.Workbench1.ExternalURL -%>
 Please see workbench for more information:
 
-  <%= Rails.configuration.Services["Workbench1"]["ExternalURL"] %>
+  <%= Rails.configuration.Services.Workbench1.ExternalURL %>
 
 <% end -%>
 Thanks,
diff --git a/services/api/app/views/admin_notifier/new_user.text.erb b/services/api/app/views/admin_notifier/new_user.text.erb
index a96dfdba9..670b84b7c 100644
--- a/services/api/app/views/admin_notifier/new_user.text.erb
+++ b/services/api/app/views/admin_notifier/new_user.text.erb
@@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0 %>
 
 <%
   add_to_message = ''
-  if Rails.configuration.Users["AutoSetupNewUsers"]
+  if Rails.configuration.Users.AutoSetupNewUsers
     add_to_message = @user.is_invited ? ' and setup' : ', but not setup'
   end
 %>
@@ -14,10 +14,10 @@ A new user has been created<%=add_to_message%>:
 
 This user is <%= @user.is_active ? '' : 'NOT ' %>active.
 
-<% if Rails.configuration.Services["Workbench1"]["ExternalURL"] -%>
+<% if Rails.configuration.Services.Workbench1.ExternalURL -%>
 Please see workbench for more information:
 
-  <%= Rails.configuration.Services["Workbench1"]["ExternalURL"] %>
+  <%= Rails.configuration.Services.Workbench1.ExternalURL %>
 
 <% end -%>
 Thanks,
diff --git a/services/api/app/views/user_notifier/account_is_setup.text.erb b/services/api/app/views/user_notifier/account_is_setup.text.erb
index 357fd91ce..50d164bfa 100644
--- a/services/api/app/views/user_notifier/account_is_setup.text.erb
+++ b/services/api/app/views/user_notifier/account_is_setup.text.erb
@@ -8,9 +8,9 @@ SPDX-License-Identifier: AGPL-3.0 %>
 Hi there,
 <% end -%>
 
-Your Arvados shell account has been set up. Please visit the virtual machines page <% if Rails.configuration.Services["Workbench1"]["ExternalURL"] %>at
+Your Arvados shell account has been set up. Please visit the virtual machines page <% if Rails.configuration.Services.Workbench1.ExternalURL %>at
 
-  <%= Rails.configuration.Services["Workbench1"]["ExternalURL"] %><%= "/" if !Rails.configuration.Services["Workbench1"]["ExternalURL"].to_s.end_with?("/") %>users/<%= @user.uuid%>/virtual_machines <% else %><% end %>
+  <%= Rails.configuration.Services.Workbench1.ExternalURL %><%= "/" if !Rails.configuration.Services.Workbench1.ExternalURL.to_s.end_with?("/") %>users/<%= @user.uuid%>/virtual_machines <% else %><% end %>
 
 for connection instructions.
 
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index ebe06b348..27affcd50 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -3061,3 +3061,4 @@ INSERT INTO "schema_migrations" (version) VALUES
 ('20190214214814'),
 ('20190322174136');
 
+
diff --git a/services/api/lib/audit_logs.rb b/services/api/lib/audit_logs.rb
index 4116ae0df..e97f65a97 100644
--- a/services/api/lib/audit_logs.rb
+++ b/services/api/lib/audit_logs.rb
@@ -44,8 +44,8 @@ module AuditLogs
   end
 
   def self.tidy_in_background
-    max_age = Rails.configuration.AuditLogs["MaxAge"]
-    max_batch = Rails.configuration.AuditLogs["MaxDeleteBatch"]
+    max_age = Rails.configuration.AuditLogs.MaxAge
+    max_batch = Rails.configuration.AuditLogs.MaxDeleteBatch
     return if max_age <= 0 || max_batch <= 0
 
     exp = (max_age/14).seconds
diff --git a/services/api/lib/crunch_dispatch.rb b/services/api/lib/crunch_dispatch.rb
index 0ebb510b5..4e640186d 100644
--- a/services/api/lib/crunch_dispatch.rb
+++ b/services/api/lib/crunch_dispatch.rb
@@ -31,13 +31,13 @@ class CrunchDispatch
     @cgroup_root = ENV['CRUNCH_CGROUP_ROOT']
     @srun_sync_timeout = ENV['CRUNCH_SRUN_SYNC_TIMEOUT']
 
-    @arvados_internal = Rails.configuration.Containers["JobsAPI"]["GitInternalDir"]
+    @arvados_internal = Rails.configuration.Containers.JobsAPI.GitInternalDir
     if not File.exist? @arvados_internal
       $stderr.puts `mkdir -p #{@arvados_internal.shellescape} && git init --bare #{@arvados_internal.shellescape}`
       raise "No internal git repository available" unless ($? == 0)
     end
 
-    @repo_root = Rails.configuration.Git["Repositories"]
+    @repo_root = Rails.configuration.Git.Repositories
     @arvados_repo_path = Repository.where(name: "arvados").first.server_path
     @authorizations = {}
     @did_recently = {}
@@ -110,7 +110,7 @@ class CrunchDispatch
   end
 
   def update_node_status
-    return unless Rails.configuration.Containers["JobsAPI"]["CrunchJobWrapper"].to_s.match(/^slurm/)
+    return unless Rails.configuration.Containers.JobsAPI.CrunchJobWrapper.to_s.match(/^slurm/)
     slurm_status.each_pair do |hostname, slurmdata|
       next if @node_state[hostname] == slurmdata
       begin
@@ -337,7 +337,7 @@ class CrunchDispatch
       next if @running[job.uuid]
 
       cmd_args = nil
-      case Rails.configuration.Containers["JobsAPI"]["CrunchJobWrapper"]
+      case Rails.configuration.Containers.JobsAPI.CrunchJobWrapper
       when "none"
         if @running.size > 0
             # Don't run more than one at a time.
@@ -361,7 +361,7 @@ class CrunchDispatch
                     "--job-name=#{job.uuid}",
                     "--nodelist=#{nodelist.join(',')}"]
       else
-        raise "Unknown crunch_job_wrapper: #{Rails.configuration.Containers["JobsAPI"]["CrunchJobWrapper"]}"
+        raise "Unknown crunch_job_wrapper: #{Rails.configuration.Containers.JobsAPI.CrunchJobWrapper}"
       end
 
       cmd_args = sudo_preface + cmd_args
@@ -460,7 +460,7 @@ class CrunchDispatch
         bytes_logged: 0,
         events_logged: 0,
         log_throttle_is_open: true,
-        log_throttle_reset_time: Time.now + Rails.configuration.Containers["Logging"]["LogThrottlePeriod"],
+        log_throttle_reset_time: Time.now + Rails.configuration.Containers.Logging.LogThrottlePeriod,
         log_throttle_bytes_so_far: 0,
         log_throttle_lines_so_far: 0,
         log_throttle_bytes_skipped: 0,
@@ -485,7 +485,7 @@ class CrunchDispatch
       matches = line.match(/^\S+ \S+ \d+ \d+ stderr (.*)/)
       if matches and matches[1] and matches[1].start_with?('[...]') and matches[1].end_with?('[...]')
         partial_line = true
-        if Time.now > running_job[:log_throttle_partial_line_last_at] + Rails.configuration.Containers["Logging"]["LogPartialLineThrottlePeriod"]
+        if Time.now > running_job[:log_throttle_partial_line_last_at] + Rails.configuration.Containers.Logging.LogPartialLineThrottlePeriod
           running_job[:log_throttle_partial_line_last_at] = Time.now
         else
           skip_counts = true
@@ -499,26 +499,26 @@ class CrunchDispatch
       end
 
       if (running_job[:bytes_logged] >
-          Rails.configuration.Containers["Logging"]["LimitLogBytesPerJob"])
-        message = "Exceeded log limit #{Rails.configuration.Containers["Logging"]["LimitLogBytesPerJob"]} bytes (LimitLogBytesPerJob). Log will be truncated."
+          Rails.configuration.Containers.Logging.LimitLogBytesPerJob)
+        message = "Exceeded log limit #{Rails.configuration.Containers.Logging.LimitLogBytesPerJob} bytes (LimitLogBytesPerJob). Log will be truncated."
         running_job[:log_throttle_reset_time] = Time.now + 100.years
         running_job[:log_throttle_is_open] = false
 
       elsif (running_job[:log_throttle_bytes_so_far] >
-             Rails.configuration.Containers["Logging"]["LogThrottleBytes"])
+             Rails.configuration.Containers.Logging.LogThrottleBytes)
         remaining_time = running_job[:log_throttle_reset_time] - Time.now
-        message = "Exceeded rate #{Rails.configuration.Containers["Logging"]["LogThrottleBytes"]} bytes per #{Rails.configuration.Containers["Logging"]["LogThrottlePeriod"]} seconds (LogThrottleBytes). Logging will be silenced for the next #{remaining_time.round} seconds."
+        message = "Exceeded rate #{Rails.configuration.Containers.Logging.LogThrottleBytes} bytes per #{Rails.configuration.Containers.Logging.LogThrottlePeriod} seconds (LogThrottleBytes). Logging will be silenced for the next #{remaining_time.round} seconds."
         running_job[:log_throttle_is_open] = false
 
       elsif (running_job[:log_throttle_lines_so_far] >
-             Rails.configuration.Containers["Logging"]["LogThrottleLines"])
+             Rails.configuration.Containers.Logging.LogThrottleLines)
         remaining_time = running_job[:log_throttle_reset_time] - Time.now
-        message = "Exceeded rate #{Rails.configuration.Containers["Logging"]["LogThrottleLines"]} lines per #{Rails.configuration.Containers["Logging"]["LogThrottlePeriod"]} seconds (LogThrottleLines), logging will be silenced for the next #{remaining_time.round} seconds."
+        message = "Exceeded rate #{Rails.configuration.Containers.Logging.LogThrottleLines} lines per #{Rails.configuration.Containers.Logging.LogThrottlePeriod} seconds (LogThrottleLines), logging will be silenced for the next #{remaining_time.round} seconds."
         running_job[:log_throttle_is_open] = false
 
       elsif partial_line and running_job[:log_throttle_first_partial_line]
         running_job[:log_throttle_first_partial_line] = false
-        message = "Rate-limiting partial segments of long lines to one every #{Rails.configuration.Containers["Logging"]["LogPartialLineThrottlePeriod"]} seconds."
+        message = "Rate-limiting partial segments of long lines to one every #{Rails.configuration.Containers.Logging.LogPartialLineThrottlePeriod} seconds."
       end
     end
 
@@ -552,7 +552,7 @@ class CrunchDispatch
           j[:stderr_buf_to_flush] << "#{LogTime.now} #{message}\n"
         end
 
-        j[:log_throttle_reset_time] = now + Rails.configuration.Containers["Logging"]["LogThrottlePeriod"]
+        j[:log_throttle_reset_time] = now + Rails.configuration.Containers.Logging.LogThrottlePeriod
         j[:log_throttle_bytes_so_far] = 0
         j[:log_throttle_lines_so_far] = 0
         j[:log_throttle_bytes_skipped] = 0
@@ -592,7 +592,7 @@ class CrunchDispatch
         bufend = ''
         streambuf.each_line do |line|
           if not line.end_with? $/
-            if line.size > Rails.configuration.Containers["Logging"]["LogThrottleBytes"]
+            if line.size > Rails.configuration.Containers.Logging.LogThrottleBytes
               # Without a limit here, we'll use 2x an arbitrary amount
               # of memory, and waste a lot of time copying strings
               # around, all without providing any feedback to anyone
@@ -775,7 +775,7 @@ class CrunchDispatch
 
     # This is how crunch-job child procs know where the "refresh"
     # trigger file is
-    ENV["CRUNCH_REFRESH_TRIGGER"] = Rails.configuration.Containers["JobsAPI"]["CrunchRefreshTrigger"]
+    ENV["CRUNCH_REFRESH_TRIGGER"] = Rails.configuration.Containers.JobsAPI.CrunchRefreshTrigger
 
     # If salloc can't allocate resources immediately, make it use our
     # temporary failure exit code.  This ensures crunch-dispatch won't
@@ -902,9 +902,9 @@ class CrunchDispatch
   end
 
   def sudo_preface
-    return [] if not Rails.configuration.Containers["JobsAPI"]["CrunchJobUser"]
+    return [] if not Rails.configuration.Containers.JobsAPI.CrunchJobUser
     ["sudo", "-E", "-u",
-     Rails.configuration.Containers["JobsAPI"]["CrunchJobUser"],
+     Rails.configuration.Containers.JobsAPI.CrunchJobUser,
      "LD_LIBRARY_PATH=#{ENV['LD_LIBRARY_PATH']}",
      "PATH=#{ENV['PATH']}",
      "PERLLIB=#{ENV['PERLLIB']}",
@@ -937,8 +937,8 @@ class CrunchDispatch
     # Send out to log event if buffer size exceeds the bytes per event or if
     # it has been at least crunch_log_seconds_between_events seconds since
     # the last flush.
-    if running_job[:stderr_buf_to_flush].size > Rails.configuration.Containers["Logging"]["LogBytesPerEvent"] or
-        (Time.now - running_job[:stderr_flushed_at]) >= Rails.configuration.Containers["Logging"]["LogSecondsBetweenEvents"]
+    if running_job[:stderr_buf_to_flush].size > Rails.configuration.Containers.Logging.LogBytesPerEvent or
+        (Time.now - running_job[:stderr_flushed_at]) >= Rails.configuration.Containers.Logging.LogSecondsBetweenEvents
       begin
         log = Log.new(object_uuid: running_job[:job].uuid,
                       event_type: 'stderr',
@@ -957,7 +957,7 @@ class CrunchDispatch
 
   # An array of job_uuids in squeue
   def squeue_jobs
-    if Rails.configuration.Containers["JobsAPI"]["CrunchJobWrapper"] == "slurm_immediate"
+    if Rails.configuration.Containers.JobsAPI.CrunchJobWrapper == "slurm_immediate"
       p = IO.popen(['squeue', '-a', '-h', '-o', '%j'])
       begin
         p.readlines.map {|line| line.strip}
diff --git a/services/api/lib/enable_jobs_api.rb b/services/api/lib/enable_jobs_api.rb
index 9d8709206..c909ae922 100644
--- a/services/api/lib/enable_jobs_api.rb
+++ b/services/api/lib/enable_jobs_api.rb
@@ -31,9 +31,9 @@ Disable_jobs_api_method_list = ["jobs.create",
                                                "job_tasks.show"]
 
 def check_enable_legacy_jobs_api
-  if Rails.configuration.Containers["JobsAPI"]["Enable"] == "false" ||
-     (Rails.configuration.Containers["JobsAPI"]["Enable"] == "auto" &&
+  if Rails.configuration.Containers.JobsAPI.Enable == "false" ||
+     (Rails.configuration.Containers.JobsAPI.Enable == "auto" &&
       Job.count == 0)
-    Rails.configuration.API["DisabledAPIs"] += Disable_jobs_api_method_list
+    Rails.configuration.API.DisabledAPIs += Disable_jobs_api_method_list
   end
 end
diff --git a/services/api/lib/josh_id.rb b/services/api/lib/josh_id.rb
index 396d72444..f18c0edda 100644
--- a/services/api/lib/josh_id.rb
+++ b/services/api/lib/josh_id.rb
@@ -40,7 +40,7 @@ module OmniAuth
         options.client_options[:site] = options[:custom_provider_url]
         options.client_options[:authorize_url] = "#{options[:custom_provider_url]}/auth/josh_id/authorize"
         options.client_options[:access_token_url] = "#{options[:custom_provider_url]}/auth/josh_id/access_token"
-        if Rails.configuration.TLS["Insecure"]
+        if Rails.configuration.TLS.Insecure
           options.client_options[:ssl] = {verify_mode: OpenSSL::SSL::VERIFY_NONE}
         end
         ::OAuth2::Client.new(options.client_id, options.client_secret, deep_symbolize(options.client_options))
diff --git a/services/api/lib/load_param.rb b/services/api/lib/load_param.rb
index 0cc29ded0..7119eb234 100644
--- a/services/api/lib/load_param.rb
+++ b/services/api/lib/load_param.rb
@@ -56,7 +56,7 @@ module LoadParam
         raise ArgumentError.new("Invalid value for limit parameter")
       end
       @limit = [params[:limit].to_i,
-                Rails.configuration.API["MaxItemsPerResponse"]].min
+                Rails.configuration.API.MaxItemsPerResponse].min
     else
       @limit = DEFAULT_LIMIT
     end
diff --git a/services/api/lib/log_reuse_info.rb b/services/api/lib/log_reuse_info.rb
index 01cf6dd78..5c7efd7de 100644
--- a/services/api/lib/log_reuse_info.rb
+++ b/services/api/lib/log_reuse_info.rb
@@ -9,7 +9,7 @@ module LogReuseInfo
   # doing expensive things like database queries, and we want to skip
   # those when logging is disabled.
   def log_reuse_info(candidates=nil)
-    if Rails.configuration.Containers["LogReuseDecisions"]
+    if Rails.configuration.Containers.LogReuseDecisions
       msg = yield
       if !candidates.nil?
         msg = "have #{candidates.count} candidates " + msg
diff --git a/services/api/lib/refresh_permission_view.rb b/services/api/lib/refresh_permission_view.rb
index e7fa263c7..5d6081f26 100644
--- a/services/api/lib/refresh_permission_view.rb
+++ b/services/api/lib/refresh_permission_view.rb
@@ -12,8 +12,8 @@ def do_refresh_permission_view
 end
 
 def refresh_permission_view(async=false)
-  if async and Rails.configuration.API["AsyncPermissionsUpdateInterval"] > 0
-    exp = Rails.configuration.API["AsyncPermissionsUpdateInterval"].seconds
+  if async and Rails.configuration.API.AsyncPermissionsUpdateInterval > 0
+    exp = Rails.configuration.API.AsyncPermissionsUpdateInterval.seconds
     need = false
     Rails.cache.fetch('AsyncRefreshPermissionView', expires_in: exp) do
       need = true
diff --git a/services/api/lib/sweep_trashed_objects.rb b/services/api/lib/sweep_trashed_objects.rb
index 6ade1fc56..8613c749c 100644
--- a/services/api/lib/sweep_trashed_objects.rb
+++ b/services/api/lib/sweep_trashed_objects.rb
@@ -55,8 +55,8 @@ module SweepTrashedObjects
   end
 
   def self.sweep_if_stale
-    return if Rails.configuration.Collections["TrashSweepInterval"] <= 0
-    exp = Rails.configuration.Collections["TrashSweepInterval"].seconds
+    return if Rails.configuration.Collections.TrashSweepInterval <= 0
+    exp = Rails.configuration.Collections.TrashSweepInterval.seconds
     need = false
     Rails.cache.fetch('SweepTrashedObjects', expires_in: exp) do
       need = true
diff --git a/services/api/lib/tasks/config_check.rake b/services/api/lib/tasks/config_check.rake
index c42c37edb..12e6dd91c 100644
--- a/services/api/lib/tasks/config_check.rake
+++ b/services/api/lib/tasks/config_check.rake
@@ -21,8 +21,8 @@ namespace :config do
       end
     end
     # default_trash_lifetime cannot be less than 24 hours
-    if Rails.configuration.Collections["DefaultTrashLifetime"] < 86400 then
-      raise "default_trash_lifetime is %d, must be at least 86400" % Rails.configuration.Collections["DefaultTrashLifetime"]
+    if Rails.configuration.Collections.DefaultTrashLifetime < 86400 then
+      raise "default_trash_lifetime is %d, must be at least 86400" % Rails.configuration.Collections.DefaultTrashLifetime
     end
   end
 end
diff --git a/services/api/lib/tasks/delete_old_container_logs.rake b/services/api/lib/tasks/delete_old_container_logs.rake
index c926c2ae0..c5c5cdc76 100644
--- a/services/api/lib/tasks/delete_old_container_logs.rake
+++ b/services/api/lib/tasks/delete_old_container_logs.rake
@@ -11,7 +11,7 @@ namespace :db do
   desc "Remove old container log entries from the logs table"
 
   task delete_old_container_logs: :environment do
-    delete_sql = "DELETE FROM logs WHERE id in (SELECT logs.id FROM logs JOIN containers ON logs.object_uuid = containers.uuid WHERE event_type IN ('stdout', 'stderr', 'arv-mount', 'crunch-run', 'crunchstat') AND containers.log IS NOT NULL AND clock_timestamp() - containers.finished_at > interval '#{Rails.configuration.Containers["Logging"]["MaxAge"]} seconds')"
+    delete_sql = "DELETE FROM logs WHERE id in (SELECT logs.id FROM logs JOIN containers ON logs.object_uuid = containers.uuid WHERE event_type IN ('stdout', 'stderr', 'arv-mount', 'crunch-run', 'crunchstat') AND containers.log IS NOT NULL AND clock_timestamp() - containers.finished_at > interval '#{Rails.configuration.Containers.Logging.MaxAge} seconds')"
 
     ActiveRecord::Base.connection.execute(delete_sql)
   end
diff --git a/services/api/lib/tasks/delete_old_job_logs.rake b/services/api/lib/tasks/delete_old_job_logs.rake
index 6f195e954..3c1c04999 100644
--- a/services/api/lib/tasks/delete_old_job_logs.rake
+++ b/services/api/lib/tasks/delete_old_job_logs.rake
@@ -9,7 +9,7 @@
 namespace :db do
   desc "Remove old job stderr entries from the logs table"
   task delete_old_job_logs: :environment do
-    delete_sql = "DELETE FROM logs WHERE id in (SELECT logs.id FROM logs JOIN jobs ON logs.object_uuid = jobs.uuid WHERE event_type = 'stderr' AND jobs.log IS NOT NULL AND clock_timestamp() - jobs.finished_at > interval '#{Rails.configuration.Containers["Logging"]["MaxAge"]} seconds')"
+    delete_sql = "DELETE FROM logs WHERE id in (SELECT logs.id FROM logs JOIN jobs ON logs.object_uuid = jobs.uuid WHERE event_type = 'stderr' AND jobs.log IS NOT NULL AND clock_timestamp() - jobs.finished_at > interval '#{Rails.configuration.Containers.Logging.MaxAge} seconds')"
 
     ActiveRecord::Base.connection.execute(delete_sql)
   end
diff --git a/services/api/lib/trashable.rb b/services/api/lib/trashable.rb
index 4981b8cd3..f7faabc4c 100644
--- a/services/api/lib/trashable.rb
+++ b/services/api/lib/trashable.rb
@@ -50,7 +50,7 @@ module Trashable
       if trash_at.nil?
         self.delete_at = nil
       else
-        self.delete_at = trash_at + Rails.configuration.Collections["DefaultTrashLifetime"].seconds
+        self.delete_at = trash_at + Rails.configuration.Collections.DefaultTrashLifetime.seconds
       end
     elsif !trash_at || !delete_at || trash_at > delete_at
       # Not trash, or bogus arguments? Just validate in
@@ -65,7 +65,7 @@ module Trashable
       earliest_delete = [
         @validation_timestamp,
         trash_at_was,
-      ].compact.min + Rails.configuration.Collections["BlobSigningTTL"].seconds
+      ].compact.min + Rails.configuration.Collections.BlobSigningTTL.seconds
 
       # The previous value of delete_at is also an upper bound on the
       # longest-lived permission token. For example, if TTL=14,
@@ -96,7 +96,7 @@ module TrashableController
       @object.update_attributes!(trash_at: db_current_time)
     end
     earliest_delete = (@object.trash_at +
-                       Rails.configuration.Collections["BlobSigningTTL"].seconds)
+                       Rails.configuration.Collections.BlobSigningTTL.seconds)
     if @object.delete_at > earliest_delete
       @object.update_attributes!(delete_at: earliest_delete)
     end

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


hooks/post-receive
-- 




More information about the arvados-commits mailing list