From: Peter Amstutz Date: Thu, 11 Apr 2019 18:36:15 +0000 (-0400) Subject: 13996: Documentation for config migration X-Git-Tag: 1.4.0~65^2~2 X-Git-Url: https://git.arvados.org/arvados.git/commitdiff_plain/b05be6e2d1db4e63074fc28e978c40a271376f1f 13996: Documentation for config migration Arvados-DCO-1.1-Signed-off-by: Peter Amstutz --- diff --git a/.licenseignore b/.licenseignore index 28c9b95c28..405fe8ddf9 100644 --- a/.licenseignore +++ b/.licenseignore @@ -13,6 +13,7 @@ build/package-test-dockerfiles/ubuntu1604/etc-apt-preferences.d-arvados *by-sa-3.0.txt *COPYING doc/fonts/* +doc/_includes/_config_default_yml.liquid doc/user/cwl/federated/* */docker_image docker/jobs/apt.arvados.org*.list diff --git a/doc/_config.yml b/doc/_config.yml index a5b53442ca..57e5ec01bd 100644 --- a/doc/_config.yml +++ b/doc/_config.yml @@ -154,8 +154,11 @@ navbar: admin: - Topics: - admin/index.html.textile.liquid + - Configuration: + - admin/config.html.textile.liquid - Upgrading and migrations: - admin/upgrading.html.textile.liquid + - admin/config-migration.html.textile.liquid - install/migrate-docker19.html.textile.liquid - admin/upgrade-crunch2.html.textile.liquid - Users and Groups: diff --git a/doc/_includes/_config_default_yml.liquid b/doc/_includes/_config_default_yml.liquid new file mode 120000 index 0000000000..457d6fa63f --- /dev/null +++ b/doc/_includes/_config_default_yml.liquid @@ -0,0 +1 @@ +../../lib/config/config.default.yml \ No newline at end of file diff --git a/doc/admin/config-migration.html.textile.liquid b/doc/admin/config-migration.html.textile.liquid new file mode 100644 index 0000000000..13cd7585b4 --- /dev/null +++ b/doc/admin/config-migration.html.textile.liquid @@ -0,0 +1,42 @@ +--- +layout: default +navsection: admin +title: Migrating Configuration +... + +{% comment %} +Copyright (C) The Arvados Authors. All rights reserved. + +SPDX-License-Identifier: CC-BY-SA-3.0 +{% endcomment %} + +Arvados is migrating to a centralized configuration file for all components. The centralized Arvados configuration is @/etc/arvados/config.yml@. Components that support the new centralized configuration are listed below. + +h2. API server + +The legacy API server configuration is stored in @config/application.yml@ and @config/database.yml@. After migration to @/etc/arvados/config.yml@, both of these files should be moved out of the way and/or deleted. + +Change to the API server directory and use the following commands: + +
+$ bundle exec rake config:migrate > config.yml
+$ cp config.yml /etc/arvados/config.yml
+
+ +This will print the contents of @config.yml@ after merging with legacy @application.yml@. It may then be redirected to a file and copied to @/etc/arvados/config.yml@. + +If you wish to update @config.yml@ configuration by hand, or check that everything has been migrated, use @config:diff@ to print configuration items that differ between @application.yml@ and the system @config.yml@. + +
+$ bundle exec rake config:diff
+
+ +This command will also report if no migrations are required. + +h2. arvados-controller + +Only supports centralized config file. No migration needed. + +h2. arvados-dispatch-cloud + +Only supports centralized config file. No migration needed. diff --git a/doc/admin/config.html.textile.liquid b/doc/admin/config.html.textile.liquid new file mode 100644 index 0000000000..1836aac1f5 --- /dev/null +++ b/doc/admin/config.html.textile.liquid @@ -0,0 +1,19 @@ +--- +layout: default +navsection: admin +title: Configuration reference +... + +{% comment %} +Copyright (C) The Arvados Authors. All rights reserved. + +SPDX-License-Identifier: CC-BY-SA-3.0 +{% endcomment %} + +The master Arvados configuration is stored at @/etc/arvados/config.yml@ + +See "Migrating Configuration":config-migration.html for information about migrating from legacy component-specific configuration files. + +
+{% include 'config_default_yml' %}
+
diff --git a/services/api/config/arvados_config.rb b/services/api/config/arvados_config.rb index 8817b8b10f..b6d3ae051e 100644 --- a/services/api/config/arvados_config.rb +++ b/services/api/config/arvados_config.rb @@ -42,23 +42,34 @@ EOS WARNED_OMNIAUTH_CONFIG = true end -$arvados_config = {} - -["#{::Rails.root.to_s}/config/config.default.yml", "/etc/arvados/config.yml"].each do |path| - if File.exist? path - confs = YAML.load(IO.read(path), deserialize_symbols: false) - if confs - clusters = confs["Clusters"].first - $arvados_config["ClusterID"] = clusters[0] - $arvados_config.deep_merge!(clusters[1]) - end - end +# Load the defaults +$arvados_config_defaults = ConfigLoader.load "#{::Rails.root.to_s}/config/config.default.yml" +if $arvados_config_defaults.empty? + raise "Missing #{::Rails.root.to_s}/config/config.default.yml" end -$base_arvados_config = $arvados_config.deep_dup +clusterID, clusterConfig = $arvados_config_defaults["Clusters"].first +$arvados_config_defaults = clusterConfig +$arvados_config_defaults["ClusterID"] = clusterID -arvcfg = ConfigLoader.new +# Initialize the global config with the defaults +$arvados_config_global = $arvados_config_defaults.deep_dup + +# Load the global config file +confs = ConfigLoader.load "/etc/arvados/config.yml" +if !confs.empty? + clusterID, clusterConfig = confs["Clusters"].first + $arvados_config_global["ClusterID"] = clusterID + + # Copy the cluster config over the defaults + $arvados_config_global.deep_merge!(clusterConfig) +end +# Now make a copy +$arvados_config = $arvados_config_global.deep_dup + +# Declare all our configuration items. +arvcfg = ConfigLoader.new arvcfg.declare_config "ClusterID", NonemptyString, :uuid_prefix arvcfg.declare_config "ManagementToken", String, :ManagementToken arvcfg.declare_config "Git.Repositories", String, :git_repositories_dir @@ -164,13 +175,11 @@ dbcfg.declare_config "PostgreSQL.Connection.Encoding", String, :encoding application_config = {} %w(application.default application).each do |cfgfile| path = "#{::Rails.root.to_s}/config/#{cfgfile}.yml" - if File.exist? path - confs = ConfigLoader.load(path) - # Ignore empty YAML file: - next if confs == false - application_config.deep_merge!(confs['common'] || {}) - application_config.deep_merge!(confs[::Rails.env.to_s] || {}) - end + confs = ConfigLoader.load(path) + # Ignore empty YAML file: + next if confs == false + application_config.deep_merge!(confs['common'] || {}) + application_config.deep_merge!(confs[::Rails.env.to_s] || {}) end db_config = {} @@ -190,11 +199,20 @@ if application_config[:auto_activate_users_from] end 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 +# Checks for wrongly typed configuration items, coerces properties +# into correct types (such as Duration), and optionally raise error +# for essential configuration that can't be empty. +arvcfg.coercion_and_check $arvados_config_defaults, check_nonempty: false +arvcfg.coercion_and_check $arvados_config_global, check_nonempty: false +arvcfg.coercion_and_check $arvados_config, check_nonempty: true +dbcfg.coercion_and_check $arvados_config, check_nonempty: true + +# * $arvados_config_defaults is the defaults +# * $arvados_config_global is $arvados_config_defaults merged with the contents of /etc/arvados/config.yml +# These are used by the rake config: tasks +# +# * $arvados_config is $arvados_config_global merged with the migrated contents of application.yml +# This is what actually gets copied into the Rails configuration object. if $arvados_config["Collections"]["DefaultTrashLifetime"] < 86400.seconds then raise "default_trash_lifetime is %d, must be at least 86400" % Rails.configuration.Collections.DefaultTrashLifetime @@ -232,6 +250,10 @@ ENV["DATABASE_URL"] = "postgresql://#{$arvados_config["PostgreSQL"]["Connection" "pool=#{$arvados_config["PostgreSQL"]["ConnectionPool"]}" Server::Application.configure do + # Copy into the Rails config object. This also turns Hash into + # OrderedOptions so that application code can use + # Rails.configuration.API.Blah instead of + # Rails.configuration.API["Blah"] ConfigLoader.copy_into_config $arvados_config, config ConfigLoader.copy_into_config $remaining_config, config config.secret_key_base = config.secret_token diff --git a/services/api/lib/config_loader.rb b/services/api/lib/config_loader.rb index 87bfd93fca..90b6d9ddc7 100644 --- a/services/api/lib/config_loader.rb +++ b/services/api/lib/config_loader.rb @@ -190,9 +190,16 @@ class ConfigLoader end end - def self.load path - yaml = ERB.new(IO.read path).result(binding) - YAML.load(yaml, deserialize_symbols: false) + def self.load path, erb: false + if File.exist? path + yaml = IO.read path + if erb + yaml = ERB.new(yaml).result(binding) + end + YAML.load(yaml, deserialize_symbols: false) + else + {} + end end end diff --git a/services/api/lib/tasks/config.rake b/services/api/lib/tasks/config.rake new file mode 100644 index 0000000000..e7d6ab4566 --- /dev/null +++ b/services/api/lib/tasks/config.rake @@ -0,0 +1,51 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 + +def diff_hash base, final + diffed = {} + base.each do |k,v| + bk = base[k] + fk = final[k] + if bk.is_a? Hash + d = diff_hash bk, fk + if d.length > 0 + diffed[k] = d + end + else + if bk.to_yaml != fk.to_yaml + diffed[k] = fk + end + end + end + diffed +end + +namespace :config do + desc 'Print items that differ between legacy application.yml and system config.yml' + task diff: :environment do + diffed = diff_hash $arvados_config_global, $arvados_config + cfg = { "Clusters" => {}} + cfg["Clusters"][$arvados_config["ClusterID"]] = diffed.select {|k,v| k != "ClusterID"} + if cfg["Clusters"][$arvados_config["ClusterID"]].empty? + puts "No migrations required for /etc/arvados/config.yml" + else + puts cfg.to_yaml + end + end + + desc 'Print config.yml after merging with legacy application.yml' + task migrate: :environment do + diffed = diff_hash $arvados_config_defaults, $arvados_config + cfg = { "Clusters" => {}} + cfg["Clusters"][$arvados_config["ClusterID"]] = diffed.select {|k,v| k != "ClusterID"} + puts cfg.to_yaml + end + + desc 'Print configuration as accessed through Rails.configuration' + task dump: :environment do + combined = $arvados_config.deep_dup + combined.update $remaining_config + puts combined.to_yaml + end +end