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

Modularize MiqServer #15014

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 6 additions & 89 deletions app/models/miq_server.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
require 'resolv'
require 'miq_server/base_constants'
require 'miq_server/base_methods'
require 'miq_server/queue_management'

class MiqServer < ApplicationRecord
include_concern 'WorkerManagement'
Expand All @@ -8,7 +11,6 @@ class MiqServer < ApplicationRecord
include_concern 'EnvironmentManagement'
include_concern 'LogManagement'
include_concern 'NtpManagement'
include_concern 'QueueManagement'
include_concern 'RoleManagement'
include_concern 'StatusManagement'
include_concern 'UpdateManagement'
Expand All @@ -24,29 +26,15 @@ class MiqServer < ApplicationRecord
has_many :messages, :as => :handler, :class_name => 'MiqQueue'
has_many :miq_events, :as => :target, :dependent => :destroy

cattr_accessor :my_guid_cache

before_destroy :validate_is_deleteable

default_value_for :rhn_mirror, false

virtual_column :zone_description, :type => :string

RUN_AT_STARTUP = %w( MiqRegion MiqWorker MiqQueue MiqReportResult )

STATUS_STARTING = 'starting'.freeze
STATUS_STARTED = 'started'.freeze
STATUS_RESTARTING = 'restarting'.freeze
STATUS_STOPPED = 'stopped'.freeze
STATUS_QUIESCE = 'quiesce'.freeze
STATUS_NOT_RESPONDING = 'not responding'.freeze
STATUS_KILLED = 'killed'.freeze

STATUSES_STOPPED = [STATUS_STOPPED, STATUS_KILLED]
STATUSES_ACTIVE = [STATUS_STARTING, STATUS_STARTED]
STATUSES_ALIVE = STATUSES_ACTIVE + [STATUS_RESTARTING, STATUS_QUIESCE]

RESTART_EXIT_STATUS = 123
include MiqServerBaseConstants
include MiqServerBaseMethods
include MiqServerQueueManagement
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be MiqServer::BaseConstants, etc. based on your file structure and that there are other modules already using that pattern. Also, the requires at the top probably won't be needed then as autoload should pick them up at the correct location.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not possible, but I guess I didn't explain (thought I did somewhere, but I will make sure I add to the description at some point).

Basically, it boils down to this: MiqServer is a class that inherits from ApplicationRecord, not a module, and because of load ordering, that always gets loaded first before any of the sub modules in the app/models/miq_server folder. For what I am doing with #14916, I don't want to have portions of this require ApplicationRecord to be loaded, so this needs to be it's own module, but because of that, it can't live within the same namespace. Here is why:

module MiqServer
  module BaseConstants
    # code here
  end
end

class MiqServer < ApplicationRecord
end

#=> Error:  MiqServer is already defined as a module

If we were to do it in the inverse, then we would have to define MiqServer as a class inheriting from ApplicationRecord, which doesn't work with #14916 where I am trying to define it as vanilla active record.

I will push what I have to #14916 where I implement this and the other relevant PRs so you can see how I plan to use this. That commit (and the rest of the PR really...) is very POC and temporary at the moment, but it should provide an idea for why I did it this way.


def self.active_miq_servers
where(:status => STATUSES_ACTIVE)
Expand Down Expand Up @@ -104,15 +92,6 @@ def self.setup_data_directory
Dir.mkdir data_dir unless File.exist?(data_dir)
end

def self.pidfile
@pidfile ||= "#{Rails.root}/tmp/pids/evm.pid"
end

def self.running?
p = PidFile.new(pidfile)
p.running? ? p.pid : false
end

def start
MiqEvent.raise_evm_event(self, "evm_server_start")

Expand Down Expand Up @@ -374,43 +353,6 @@ def monitor_loop
end
end

def stop(sync = false)
return if self.stopped?

shutdown_and_exit_queue
wait_for_stopped if sync
end

def wait_for_stopped
loop do
reload
break if self.stopped?
sleep stop_poll
end
end

def self.stop(sync = false)
svr = my_server(true) rescue nil
svr.stop(sync) unless svr.nil?
PidFile.new(pidfile).remove
end

def kill
# Kill all the workers of this server
kill_all_workers

# Then kill this server
_log.info("initiated for #{format_full_log_msg}")
update_attributes(:stopped_on => Time.now.utc, :status => "killed", :is_master => false)
(pid == Process.pid) ? shutdown_and_exit : Process.kill(9, pid)
end

def self.kill
svr = my_server(true)
svr.kill unless svr.nil?
PidFile.new(pidfile).remove
end

def shutdown
_log.info("initiated for #{format_full_log_msg}")
MiqEvent.raise_evm_event(self, "evm_server_stop")
Expand Down Expand Up @@ -464,14 +406,6 @@ def set_database_application_name
ArApplicationName.name = database_application_name
end

def is_local?
guid == MiqServer.my_guid
end

def is_remote?
!is_local?
end

def is_recently_active?
last_heartbeat && (last_heartbeat >= 10.minutes.ago.utc)
end
Expand Down Expand Up @@ -499,10 +433,6 @@ def started?
status == "started"
end

def stopped?
STATUSES_STOPPED.include?(status)
end

def active?
STATUSES_ACTIVE.include?(status)
end
Expand All @@ -526,19 +456,6 @@ def logon_status_details
result.merge(:message => message)
end

#
# Zone and Role methods
#
def self.my_guid
@@my_guid_cache ||= begin
guid_file = Rails.root.join("GUID")
File.write(guid_file, SecureRandom.uuid) unless File.exist?(guid_file)
File.read(guid_file).strip
end
end

cache_with_timeout(:my_server) { find_by(:guid => my_guid) }

def self.my_zone(force_reload = false)
my_server(force_reload).my_zone
end
Expand Down
17 changes: 17 additions & 0 deletions app/models/miq_server/base_constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module MiqServerBaseConstants
RUN_AT_STARTUP = %w(MiqRegion MiqWorker MiqQueue MiqReportResult).freeze

STATUS_STARTING = 'starting'.freeze
STATUS_STARTED = 'started'.freeze
STATUS_RESTARTING = 'restarting'.freeze
STATUS_STOPPED = 'stopped'.freeze
STATUS_QUIESCE = 'quiesce'.freeze
STATUS_NOT_RESPONDING = 'not responding'.freeze
STATUS_KILLED = 'killed'.freeze

STATUSES_STOPPED = [STATUS_STOPPED, STATUS_KILLED].freeze
STATUSES_ACTIVE = [STATUS_STARTING, STATUS_STARTED].freeze
STATUSES_ALIVE = STATUSES_ACTIVE + [STATUS_RESTARTING, STATUS_QUIESCE].freeze

RESTART_EXIT_STATUS = 123
end
96 changes: 96 additions & 0 deletions app/models/miq_server/base_methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require 'util/extensions/miq-module'

module MiqServerBaseMethods
extend ActiveSupport::Concern

included do
cattr_accessor :my_guid_cache

cache_with_timeout(:my_server) { find_by(:guid => my_guid) }
end

module ClassMethods
#
# Zone and Role methods
#
def my_guid
my_guid_cache ||= begin
guid_file = Rails.root.join("GUID")
File.write(guid_file, SecureRandom.uuid) unless File.exist?(guid_file)
File.read(guid_file).strip
end
end

def pidfile
@pidfile ||= Rails.root.join("tmp", "pids", "evm.pid")
end

def running?
p = PidFile.new(pidfile)
p.running? ? p.pid : false
end

def kill
svr = my_server(true)
svr.kill unless svr.nil?
PidFile.new(pidfile).remove
end

def stop(sync = false)
svr = my_server(true) rescue nil
svr.stop(sync) unless svr.nil?
PidFile.new(pidfile).remove
end
end

def kill
# Kill all the workers of this server
kill_all_workers

# Then kill this server
_log.info("initiated for #{format_full_log_msg}")
update_attributes(:stopped_on => Time.now.utc, :status => "killed", :is_master => false)
(pid == Process.pid) ? shutdown_and_exit : Process.kill(9, pid)
end

def kill_all_workers
return unless is_local?

killed_workers = []
miq_workers.each do |w|
next unless MiqWorker::STATUSES_CURRENT_OR_STARTING.include?(w.status)

w.kill
worker_delete(w.pid)
killed_workers << w
end
miq_workers.delete(*killed_workers) unless killed_workers.empty?
end

def stop(sync = false)
return if stopped?

shutdown_and_exit_queue
wait_for_stopped if sync
end

def wait_for_stopped
loop do
reload
break if stopped?
sleep stop_poll
end
end

def is_local?
guid == MiqServer.my_guid
end

def is_remote?
!is_local?
end

def stopped?
self.class::STATUSES_STOPPED.include?(status)
end
end
2 changes: 1 addition & 1 deletion app/models/miq_server/queue_management.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module MiqServer::QueueManagement
module MiqServerQueueManagement
extend ActiveSupport::Concern

def clear_miq_queue_for_this_server
Expand Down
42 changes: 3 additions & 39 deletions app/models/miq_server/worker_management.rb
Original file line number Diff line number Diff line change
@@ -1,47 +1,11 @@
require 'miq_server/worker_management_base'

module MiqServer::WorkerManagement
extend ActiveSupport::Concern

include_concern 'Dequeue'
include_concern 'Heartbeat'
include_concern 'Monitor'

included do
has_many :miq_workers
end

module ClassMethods
def kill_all_workers
svr = my_server(true)
svr.kill_all_workers unless svr.nil?
end
end

def setup_drb_variables
@workers_lock = Sync.new
@workers = {}

@queue_messages_lock = Sync.new
@queue_messages = {}
end

def start_drb_server
require 'drb'
require 'drb/acl'

setup_drb_variables

acl = ACL.new(%w( deny all allow 127.0.0.1/32 ))
DRb.install_acl(acl)

drb = DRb.start_service("druby://127.0.0.1:0", self)
update_attributes(:drb_uri => drb.uri)
end

def worker_add(worker_pid)
@workers_lock.synchronize(:EX) { @workers[worker_pid] ||= {} } unless @workers_lock.nil?
end

def worker_delete(worker_pid)
@workers_lock.synchronize(:EX) { @workers.delete(worker_pid) } unless @workers_lock.nil?
end
include MiqServerWorkerManagementBase
end
1 change: 0 additions & 1 deletion app/models/miq_server/worker_management/monitor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ module MiqServer::WorkerManagement::Monitor
extend ActiveSupport::Concern

include_concern 'ClassNames'
include_concern 'Kill'
include_concern 'Quiesce'
include_concern 'Reason'
include_concern 'Settings'
Expand Down
30 changes: 0 additions & 30 deletions app/models/miq_server/worker_management/monitor/kill.rb

This file was deleted.

13 changes: 13 additions & 0 deletions app/models/miq_server/worker_management/monitor/quiesce.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ def workers_quiesced?
false
end

def kill_timed_out_worker_quiesce
killed_workers = []
miq_workers.each do |w|
next unless quiesce_timed_out?(w.quiesce_time_allowance)

_log.warn("Timed out quiesce of #{w.format_full_log_msg} after #{w.quiesce_time_allowance} seconds")
w.kill
worker_delete(w.pid)
killed_workers << w
end
miq_workers.delete(*killed_workers) unless killed_workers.empty?
end

def quiesce_workers_loop
_log.info("Stopping all active workers")

Expand Down
Loading