Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Rails7 #22873

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
16 changes: 8 additions & 8 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ def manageiq_plugin(plugin_name)
end
end

manageiq_plugin "manageiq-schema"
gem "manageiq-schema", :github => "jrafanie/manageiq-schema", :branch => "allow_rails_7"

# Unmodified gems
gem "activerecord-session_store", "~>2.0"
gem "activerecord-virtual_attributes", "~>6.1.2"
gem "activerecord-virtual_attributes", :github => "jrafanie/activerecord-virtual_attributes", :branch => "allow_rails_7"
gem "acts_as_tree", "~>2.7" # acts_as_tree needs to be required so that it loads before ancestry
gem "ancestry", "~>4.1.0", :require => false
gem "awesome_spawn", "~>1.6", :require => false
Expand All @@ -35,7 +35,7 @@ gem "color", "~>1.8"
gem "config", "~>2.2", ">=2.2.3", :require => false
gem "connection_pool", :require => false # For Dalli
gem "dalli", "~>3.2.3", :require => false
gem "default_value_for", "~>3.3"
gem "default_value_for", :github => "FooBarWidget/default_value_for"
gem "docker-api", "~>1.33.6", :require => false
gem "elif", "=0.1.0", :require => false
gem "fast_gettext", "~>2.0.1"
Expand All @@ -47,11 +47,11 @@ gem "inventory_refresh", "~>2.1", :require => false
gem "kubeclient", "~>4.0", :require => false # For scaling pods at runtime
gem "linux_admin", "~>3.0", :require => false
gem "listen", "~>3.2", :require => false
gem "manageiq-api-client", "~>0.3.6", :require => false
gem "manageiq-api-client", "~>0.5.0", :require => false
gem "manageiq-loggers", "~>1.0", ">=1.1.1", :require => false
gem "manageiq-messaging", "~>1.0", ">=1.4.3", :require => false
gem "manageiq-password", "~>1.0", :require => false
gem "manageiq-postgres_ha_admin", "~>3.2", :require => false
gem "manageiq-postgres_ha_admin", "~>3.3", :require => false
gem "manageiq-ssh-util", "~>0.2.0", :require => false
gem "memoist", "~>0.16.0", :require => false
gem "money", "~>6.13.5", :require => false
Expand All @@ -68,8 +68,8 @@ gem "psych", ">=3.1", :require => false #
gem "query_relation", "~>0.1.0", :require => false
gem "rack", ">=2.2.6.4", :require => false
gem "rack-attack", "~>6.5.0", :require => false
gem "rails", "~>6.1.7", ">=6.1.7.7"
gem "rails-i18n", "~>6.x"
gem "rails", "~>7.0.0"
gem "rails-i18n", "~>7.x"
gem "rake", ">=12.3.3", :require => false
gem "rest-client", "~>2.1.0", :require => false
gem "ruby_parser", :require => false # Required for i18n string extraction, and DescentdantLoader (via prism)
Expand Down Expand Up @@ -305,7 +305,7 @@ group :test do
gem "brakeman", "~>5.4", :require => false
gem "bundler-audit", :require => false
gem "capybara", "~>2.5.0", :require => false
gem "db-query-matchers", "~>0.10.0"
gem "db-query-matchers", "~>0.11.0"
gem "factory_bot", "~>5.1", :require => false
gem "simplecov", ">=0.21.2", :require => false
gem "timecop", "~>0.9", "!= 0.9.7", :require => false
Expand Down
3 changes: 0 additions & 3 deletions app/models/miq_request_workflow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ class MiqRequestWorkflow
include Vmdb::Logging
include DialogFieldValidation

# We rely on MiqRequestWorkflow's descendants to be comprehensive
singleton_class.send(:prepend, DescendantLoader::ArDescendantsWithLoader)

attr_accessor :requester, :values, :last_vm_id
attr_writer :dialogs

Expand Down
2 changes: 1 addition & 1 deletion app/models/miq_worker/runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ def self.ruby_object_usage
ObjectSpace.each_object(Object) do |obj|
next unless defined?(obj.class)

types[obj.class.name] += 1
types[obj.class.to_s] += 1
end
types
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/vm_reconfigure_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def self.build_message(options, key, message, modifier = nil)

def self.build_disk_message(options)
if options[:disk_add].present?
disk_sizes = options[:disk_add].collect { |d| d["disk_size_in_mb"].to_i.megabytes.to_s(:human_size) + ", Type: " + d["type"].to_s }
disk_sizes = options[:disk_add].collect { |d| d["disk_size_in_mb"].to_i.megabytes.to_fs(:human_size) + ", Type: " + d["type"].to_s }
"Add Disks: #{options[:disk_add].length} : #{disk_sizes.join(", ")} "
end
end
Expand Down
3 changes: 1 addition & 2 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ class Application < Rails::Application

config.autoload_paths += config.eager_load_paths

config.autoloader = :zeitwerk

# config.load_defaults 6.1
# Disable defaults as ActiveRecord::Base.belongs_to_required_by_default = true causes MiqRegion.seed to fail validation on belongs_to maintenance zone

Expand Down Expand Up @@ -160,6 +158,7 @@ class Application < Rails::Application
# on the top to bottom order of initializer calls in the file.
# Because this is easy to mess up, keep your initializers in order.
initializer :load_inflections, :before => :init_vmdb_plugins do
require 'vmdb/inflections'
Vmdb::Inflections.load_inflections
end

Expand Down
1 change: 1 addition & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
require "factory_bot"
require "timecop"
require "vcr"
require "rspec"
require "webmock/rspec"
require "capybara"

Expand Down
1 change: 1 addition & 0 deletions config/initializers/active_metrics.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# Note: The legacy Postgresql adapter ignores everything except the adapter name here, just stealing the current ActiveRecord connection.
require 'active_metrics'
ActiveMetrics::Base.establish_connection(:adapter => "miq_postgres", :database => "manageiq_metrics")
1 change: 1 addition & 0 deletions config/initializers/fast_gettext.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
load_paths.sort_by! { |p| File.basename(p) } # consistently sort en_foo.yml *after* en.yml
I18n.load_path += load_paths

require 'vmdb/fast_gettext_helper'
Vmdb::FastGettextHelper.register_locales
Vmdb::FastGettextHelper.register_human_localenames
gettext_options = %w[--sort-by-msgid --location --no-wrap]
Expand Down
1 change: 1 addition & 0 deletions config/initializers/session_store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
when "cache" then :mem_cache_store
end

require 'manageiq/session'
ManageIQ::Session.store = session_store
14 changes: 14 additions & 0 deletions config/initializers/zeitwerk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,17 @@
Rails.autoloaders.main.collapse(Rails.root.join("lib/manageiq/reporting/charting"))
Rails.autoloaders.main.collapse(Rails.root.join("lib/ansible/runner/credential"))
Rails.autoloaders.main.collapse(Rails.root.join("lib/pdf_generator"))

DescendantLoader.instance.discovered_parent_child_classes.each do |parent, children|
puts "Registering on_load for class: #{parent}"
Rails.autoloaders.main.on_load(parent.to_s) do |klass, _abspath|
puts "Running on_load for class: #{klass} with children: #{children}"
children.each do |child|
begin
child.safe_constantize
rescue NameError
puts "!!! FAILED to load #{child} for parent: #{klass}"
end
end
end
end
2 changes: 1 addition & 1 deletion lib/acts_as_ar_model.rb
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def attribute_for_inspect(attr_name)
if value.kind_of?(String) && value.length > 50
"#{value[0..50]}...".inspect
elsif value.kind_of?(Date) || value.kind_of?(Time)
%("#{value.to_s(:db)}")
%("#{value.to_fs(:db)}")
else
value.inspect
end
Expand Down
1 change: 1 addition & 0 deletions lib/extensions/as_include_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def include_concern(mod)
end
include to_include.constantize
end
require 'vmdb/deprecation'
Vmdb::Deprecation.deprecate_methods(self, :include_concern)
end
end
Expand Down
33 changes: 4 additions & 29 deletions lib/extensions/descendant_loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ def clear_class_inheritance_relationships
include Cache
include Mapper

def discovered_parent_child_classes
@discovered_parent_child_classes ||= class_inheritance_relationships.select { |_k, names| names.length > 0 }
end

def load_subclasses(parent)
names_to_load = class_inheritance_relationships[parent.to_s].dup
while (name = names_to_load.shift)
Expand All @@ -260,29 +264,6 @@ def scoped_name(name, scopes)
end
end

module ArDescendantsWithLoader
def descendants
if Vmdb::Application.instance.initialized? && !defined? @loaded_descendants
@loaded_descendants = true
DescendantLoader.instance.load_subclasses(self)
end

super
end

# Rails 6.1 added an alias for subclasss to call direct_descendants in:
# https://github.com/rails/rails/commit/8f8aa857e084b76b1120edaa9bb9ce03ba1e6a19
# We need to get in front of it, like we do for descendants.
def subclasses
if Vmdb::Application.instance.initialized? && !defined? @loaded_descendants
@loaded_descendants = true
DescendantLoader.instance.load_subclasses(self)
end

super
end
end

module AsDependenciesClearWithLoader
def clear
DescendantLoader.instance.clear_class_inheritance_relationships
Expand All @@ -291,12 +272,6 @@ def clear
end
end

# Patch Class to support non-AR models in the models directory
Class.prepend(DescendantLoader::ArDescendantsWithLoader)
# Patch ActiveRecord specifically to get ahead of ActiveSupport::DescendantsTracker
# The patching of Class does not put it in the right place in the ancestors chain
ActiveRecord::Base.singleton_class.prepend(DescendantLoader::ArDescendantsWithLoader)

at_exit do
DescendantLoader.instance.save_cache!
end
2 changes: 2 additions & 0 deletions lib/extensions/yaml_load_aliases.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'yaml_permitted_classes'

module YamlLoadAliases
# Psych 4 aliases load as safe_load. Some loads happen early, like reading the database.yml so we don't want to load our
# constants at that time, such as MiqExpression, Ruport, so we have two sets of permitted classes.
Expand Down
2 changes: 2 additions & 0 deletions lib/manageiq/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,5 @@ def self.fetch_store_from_rails
private_class_method :fetch_store_from_rails
end
end

Dir.glob(File.join(__dir__, "session/*")).sort.each {|f| require f}
1 change: 1 addition & 0 deletions lib/manageiq/session/mem_cache_store_adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ def type
end

def session_options
require 'miq_memcached'
super.merge(MiqMemcached.default_client_options).merge(
:expire_after => 24.hours,
:key => "_vmdb_session",
Expand Down
11 changes: 9 additions & 2 deletions lib/miq_preloader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,15 @@ module MiqPreloader
# Currently an array does not work
# @return [Array<ActiveRecord::Base>] records
def self.preload(records, associations, preload_scope = nil)
preloader = ActiveRecord::Associations::Preloader.new
preloader.preload(records, associations, preload_scope)
# similar change to https://github.com/ManageIQ/activerecord-virtual_attributes/pull/133/files
if ActiveRecord::Associations::Preloader.instance_methods.include?(:preload)
preloader = ActiveRecord::Associations::Preloader.new
preloader.preload(records, associations, preload_scope)
else
# Rails 7+ interface, see rails commit: e3b9779cb701c63012bc1af007c71dc5a888d35a
# Note, added Array(records) as it could be a single element
ActiveRecord::Associations::Preloader.new(records: Array(records), associations: associations, scope: preload_scope).call
end
end

# for a record, cache results. Also cache the children's links back
Expand Down
1 change: 1 addition & 0 deletions lib/patches/database_configuration_patch.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require "manageiq"
require "vmdb/settings"

module DatabaseConfigurationPatch
def database_configuration
Expand Down
2 changes: 1 addition & 1 deletion lib/vmdb/settings/database_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def my_server
end

def resource_queryable?
ActiveRecord::Base.connectable? && ::SettingsChange.table_exists?
ActiveRecord::Base.connectable? && defined?(::SettingsChange) && ::SettingsChange.table_exists?
end
end
end
Expand Down
14 changes: 11 additions & 3 deletions spec/lib/extensions/ar_to_model_hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

let(:fixed_options) { test_vm_class.send(:to_model_hash_options_fixup, @test_to_model_hash_options) }
let(:mocked_preloader) { double }
let(:rails7) { !ActiveRecord::Associations::Preloader.instance_methods.include?(:preload) }

require 'active_support/testing/stream'
include ActiveSupport::Testing::Stream
Expand Down Expand Up @@ -66,12 +67,19 @@

# we're testing the preload of associations, skip the recursive .to_model_hash
allow_any_instance_of(test_vm_class).to receive(:to_model_hash_recursive)
allow(ActiveRecord::Associations::Preloader).to receive(:new).and_return(mocked_preloader)
end

def assert_preloaded(associations)
expect(mocked_preloader).to receive(:preload) do |_recs, assocs|
expect(assocs).to match_array(associations)
if rails7
allow(ActiveRecord::Associations::Preloader).to receive(:new)
.with(associations: array_including(associations), records: array_including(instance_of(test_vm_class)), scope: nil)
.and_return(mocked_preloader)
expect(mocked_preloader).to receive(:call)
else
allow(ActiveRecord::Associations::Preloader).to receive(:new).and_return(mocked_preloader)
expect(mocked_preloader).to receive(:preload) do |_recs, assocs|
expect(assocs).to match_array(associations)
end
end

test_vm_class.new.to_model_hash(fixed_options)
Expand Down
4 changes: 2 additions & 2 deletions spec/lib/miq_preloader_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
it "preloads with an array (records is a relation)" do
ems
emses = ExtManagementSystem.all.load
vms = Vm.where(:ems_id => emses.select(:id)).to_a
vms = Vm.where(:ems_id => emses.select(:id))
expect { preload(emses, :vms, vms) }.not_to make_database_queries

expect { preload(emses, :vms, vms) }.not_to make_database_queries
Expand All @@ -88,7 +88,7 @@
it "preloads with an array (records is an array)" do
ems
emses = ExtManagementSystem.all.load.to_a
vms = Vm.where(:ems_id => emses.map(&:id)).to_a
vms = Vm.where(:ems_id => emses.map(&:id))
expect { preload(emses, :vms, vms) }.not_to make_database_queries

expect { preload(emses, :vms, vms) }.not_to make_database_queries
Expand Down
2 changes: 1 addition & 1 deletion spec/models/mixins/supports_feature_mixin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ def define_subclass(module_name, parent, supports_values = {})
# this cleans out those values so future runs do not have bogus classes
# this causes sporadic test failures.
def cleanup_subclass(parent, children)
tracker = ActiveSupport::DescendantsTracker.class_variable_get(:@@direct_descendants)[parent]
tracker = ActiveSupport::DescendantsTracker.subclasses(parent)
tracker&.reject! { |child| children.include?(child) }
end

Expand Down
6 changes: 3 additions & 3 deletions spec/models/vm_reconfigure_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
context "Single Disk add " do
let(:request_options) { {:disk_add => [{"disk_size_in_mb" => "33", "persistent" => "true", "type" => "thin"}.with_indifferent_access]} }
let(:description_partial) do
"Add Disks: 1 : #{request.options[:disk_add][0]["disk_size_in_mb"].to_i.megabytes.to_s(:human_size)}, Type: " \
"Add Disks: 1 : #{request.options[:disk_add][0]["disk_size_in_mb"].to_i.megabytes.to_fs(:human_size)}, Type: " \
"#{request.options[:disk_add][0]["type"]} "
end

Expand All @@ -55,8 +55,8 @@
{"disk_size_in_mb" => "44", "persistent" => "true", "type" => "thick"}.with_indifferent_access]}
end
let(:description_partial) do
"Add Disks: 2 : #{request.options[:disk_add][0]["disk_size_in_mb"].to_i.megabytes.to_s(:human_size)}, Type: " \
"#{request.options[:disk_add][0]["type"]}, #{request.options[:disk_add][1]["disk_size_in_mb"].to_i.megabytes.to_s(:human_size)}, Type: " \
"Add Disks: 2 : #{request.options[:disk_add][0]["disk_size_in_mb"].to_i.megabytes.to_fs(:human_size)}, Type: " \
"#{request.options[:disk_add][0]["type"]}, #{request.options[:disk_add][1]["disk_size_in_mb"].to_i.megabytes.to_fs(:human_size)}, Type: " \
"#{request.options[:disk_add][1]["type"]} "
end

Expand Down
2 changes: 1 addition & 1 deletion spec/support/chargeback_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def add_metric_rollups_for(resources, range, step, metric_rollup_params, trait =
base_values
end

record_values << "(#{values}, '#{time.to_s(:db)}')"
record_values << "(#{values}, '#{time.to_fs(:db)}')"
end
end

Expand Down