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

Bump version to 7.0.47 #842

Merged
merged 3 commits into from
Sep 25, 2023
Merged
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
2 changes: 1 addition & 1 deletion lib/foreman_rh_cloud/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module ForemanRhCloud
VERSION = '7.0.46'.freeze
VERSION = '7.0.47'.freeze
end
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,17 @@ def rescue_strategy_for_self
end

def done?(current_status = invocation_status)
job_invocation.finished? || current_status.map { |_host_id, task_status| task_status['report_done'] }.all?
ActiveModel::Type::Boolean.new.cast(current_status[:task_state][:task_done_reported])
end

def job_finished?
job_invocation.finished?
end

def all_hosts_finished?(current_status)
current_status[:hosts_state].values.all? do |status|
ActiveModel::Type::Boolean.new.cast(status['report_done'] == true)
end
end

# noop, we don't want to do anything when the polling task starts
Expand Down Expand Up @@ -95,7 +105,11 @@ def correlation_id
end

def host_status(host)
external_task&.dig('invocation_status', host)
external_task&.dig('invocation_status', :hosts_state, host)
end

def task_done_state
ActiveModel::Type::Boolean.new.cast(external_task&.dig('invocation_status', :task_state, :task_done_reported))
end

def sequence(host)
Expand All @@ -111,13 +125,15 @@ def report_url
end

def invocation_status
Hash[job_invocation.targeting.hosts.map do |host|
hosts_state = Hash[job_invocation.targeting.hosts.map do |host|
next unless host.insights&.uuid
[
host.insights.uuid,
task_status(job_invocation.sub_task_for_host(host), host.insights.uuid),
]
end.compact]

{task_state: {task_done_reported: task_done_state}, hosts_state: hosts_state}
end

def task_status(host_task, host_name)
Expand All @@ -128,7 +144,7 @@ def task_status(host_task, host_name)
{
'state' => host_task.state,
'output' => host_task.main_action.live_output.map { |line| line['output'] }.join("\n"),
'exit_status' => host_task.main_action.exit_status,
'exit_status' => ActiveModel::Type::Integer.new.cast(host_task.main_action.exit_status),
'sequence' => sequence(host_name),
'report_done' => host_done?(host_name),
}
Expand All @@ -138,9 +154,9 @@ def report_job_progress(invocation_status)
generator = InsightsCloud::Generators::PlaybookProgressGenerator.new(correlation_id)
all_hosts_success = true

invocation_status.each do |host_name, status|
invocation_status[:hosts_state].each do |host_name, status|
# skip host if the host already reported that it's finished
next if status['report_done']
next if ActiveModel::Type::Boolean.new.cast(status['report_done'])

unless status['state'] == 'unknown'
sequence = status['sequence']
Expand All @@ -154,7 +170,11 @@ def report_job_progress(invocation_status)
all_hosts_success &&= status['exit_status'] == 0
end
end
generator.job_finished_message(all_hosts_success) if done?(invocation_status)

if (job_finished? || all_hosts_finished?(invocation_status))
generator.job_finished_message(all_hosts_success)
invocation_status[:task_state][:task_done_reported] = true
end

send_report(generator.generate)
end
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "foreman_rh_cloud",
"version": "7.0.46",
"version": "7.0.47",
"description": "Inventory Upload =============",
"main": "index.js",
"scripts": {
Expand Down
157 changes: 120 additions & 37 deletions test/jobs/connector_playbook_execution_reporter_task_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ def send_report(report)
end

test 'It reports finish playbook messages' do
TestConnectorPlaybookExecutionReporterTask.any_instance.stubs(:done?).returns(true)
host1_task = @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)
host1_task.state = 'stopped'
host1_task.save!

TestConnectorPlaybookExecutionReporterTask.any_instance.stubs(:job_finished?).returns(true)

actual = ForemanTasks.sync_task(TestConnectorPlaybookExecutionReporterTask, @job_invocation)

Expand All @@ -39,6 +43,13 @@ def send_report(report)
assert_not_nil actual_report
actual_jsonl = read_jsonl(actual_report)

assert_equal true, actual.output['task']['invocation_status']['task_state']['task_done_reported']
assert_equal 0, actual.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']
assert_equal 0, actual.output['task']['invocation_status']['hosts_state']['TEST_UUID2']['exit_status']

assert_equal true, @job_invocation.finished?
assert_equal 'stopped', @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)['state']

assert_not_nil actual_report_finished = actual_jsonl.find { |l| l['type'] == 'playbook_run_completed' }
assert_equal 'TEST_CORRELATION', actual_report_finished['correlation_id']
assert_equal 'success', actual_report_finished['status']
Expand All @@ -49,57 +60,127 @@ def send_report(report)
end

test 'It reports single progress message for done host' do
TestConnectorPlaybookExecutionReporterTask.any_instance.stubs(:done?).returns(false, true)
class ArrangeTestHost < InsightsCloud::Async::ConnectorPlaybookExecutionReporterTask
def send_report(report)
host1_task = @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)
host1_task.state = 'stopped'
host1_task.save!

output[:saved_reports] = (output[:saved_reports] || []) << report
end
end

actual = ForemanTasks.sync_task(TestConnectorPlaybookExecutionReporterTask, @job_invocation)
ArrangeTestHost.instance_variable_set(:@connector_feature_id, nil)
host1_task = @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)
host1_task.state = 'running'
host1_task.save!

actual_report = actual.output[:saved_reports].first.to_s
ArrangeTestHost.any_instance.stubs(:job_finished?).returns(false, true)

assert_equal 1, actual.output[:saved_reports].size
assert_not_nil actual_report
actual_jsonl = read_jsonl(actual_report)
actual = ForemanTasks.sync_task(ArrangeTestHost, @job_invocation)

actual_report1 = actual.output[:saved_reports].first.to_s
actual_report2 = actual.output[:saved_reports].second.to_s

assert_equal 2, actual.output[:saved_reports].size
assert_not_nil actual_report1
assert_not_nil actual_report2

actual_json1 = read_jsonl(actual_report1)
actual_json2 = read_jsonl(actual_report2)

assert_equal true, actual.output['task']['invocation_status']['task_state']['task_done_reported']
assert_equal 0, actual.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']

actual_host_updates = actual_jsonl
.select { |l| l['type'] == 'playbook_run_update' && l['host'] == @host1.insights.uuid }
assert_equal 1, actual_host_updates.size
assert_equal 0, actual_host_updates.first['sequence']
assert_equal 'stopped', @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)['state']

assert_not_nil actual_report_updated = actual_json1.find { |l| l['type'] == 'playbook_run_update' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_report_updated['correlation_id']
assert_equal 'TEST_UUID1', actual_report_updated['host']
assert_equal 0, actual_report_updated['sequence']
assert_equal 6, actual_report_updated.size

assert_not_nil actual_report_updated = actual_json2.find { |l| l['type'] == 'playbook_run_update' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_report_updated['correlation_id']
assert_equal 'TEST_UUID1', actual_report_updated['host']
assert_equal 1, actual_report_updated['sequence']
assert_equal 6, actual_report_updated.size

assert_not_nil actual_host_finished = actual_json2.find { |l| l['type'] == 'playbook_run_finished' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_host_finished['correlation_id']
assert_equal 'TEST_UUID1', actual_host_finished['host']
assert_equal 'success', actual_host_finished['status']
assert_equal 7, actual_host_finished.size

assert_not_nil actual_report_finished = actual_json2.find { |l| l['type'] == 'playbook_run_completed' }
assert_equal 'TEST_CORRELATION', actual_report_finished['correlation_id']
assert_equal 'success', actual_report_finished['status']
assert_equal 4, actual_report_finished.size
end

test 'It reports two progress messages for in progress host' do
TestConnectorPlaybookExecutionReporterTask.any_instance.stubs(:done?).returns(false, false, true)
class ArrangeTestHostTwo < InsightsCloud::Async::ConnectorPlaybookExecutionReporterTask
def send_report(report)
iteration_number = output[:iteration_number].to_i

if iteration_number == 1
host1_task = job_invocation.sub_task_for_host(Host.where(name: 'host1').first)
host1_task.state = 'stopped'
host1_task.save!
end

output[:iteration_number] = iteration_number + 1
output[:saved_reports] = (output[:saved_reports] || []) << report
end
end

host1_task = @job_invocation.template_invocations.joins(:host).where(hosts: {name: @host1.name}).first.run_host_job_task
ArrangeTestHostTwo.instance_variable_set(:@connector_feature_id, nil)
host1_task = @job_invocation.sub_task_for_host(Host.where(name: 'host1').first)
host1_task.state = 'running'
host1_task.save!

actual = ForemanTasks.sync_task(TestConnectorPlaybookExecutionReporterTask, @job_invocation)
ArrangeTestHostTwo.any_instance.stubs(:job_finished?).returns(false, false, true)

assert_equal 2, actual.output[:saved_reports].size
actual = ForemanTasks.sync_task(ArrangeTestHostTwo, @job_invocation)

actual_report1 = actual.output[:saved_reports].first.to_s
actual_report2 = actual.output[:saved_reports].second.to_s
actual_report3 = actual.output[:saved_reports].third.to_s

assert_equal 3, actual.output[:saved_reports].size
assert_not_nil actual_report1
assert_not_nil actual_report2
assert_not_nil actual_report3

first_report = actual.output[:saved_reports].first.to_s
actual_jsonl = read_jsonl(first_report)
actual_json1 = read_jsonl(actual_report1)
actual_json2 = read_jsonl(actual_report2)
actual_json3 = read_jsonl(actual_report3)

actual_host_updates = actual_jsonl
.select { |l| l['type'] == 'playbook_run_update' && l['host'] == @host1.insights.uuid }
assert_equal 1, actual_host_updates.size
assert_equal 0, actual_host_updates.first['sequence']
assert_equal true, actual.output['task']['invocation_status']['task_state']['task_done_reported']
assert_equal 0, actual.output['task']['invocation_status']['hosts_state']['TEST_UUID1']['exit_status']

actual_host_updates = actual_jsonl
.select { |l| l['type'] == 'playbook_run_update' && l['host'] == @host2.insights.uuid }
assert_equal 1, actual_host_updates.size
assert_equal 0, actual_host_updates.first['sequence']
assert_not_nil actual_report_updated = actual_json1.find { |l| l['type'] == 'playbook_run_update' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_report_updated['correlation_id']
assert_equal 'TEST_UUID1', actual_report_updated['host']
assert_equal 0, actual_report_updated['sequence']
assert_equal 6, actual_report_updated.size

second_report = actual.output[:saved_reports].last.to_s
actual_jsonl = read_jsonl(second_report)
assert_not_nil actual_report_updated = actual_json2.find { |l| l['type'] == 'playbook_run_update' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_report_updated['correlation_id']
assert_equal 'TEST_UUID1', actual_report_updated['host']
assert_equal 1, actual_report_updated['sequence']
assert_equal 6, actual_report_updated.size

actual_host_updates = actual_jsonl
.select { |l| l['type'] == 'playbook_run_update' && l['host'] == @host1.insights.uuid }
assert_equal 1, actual_host_updates.size
assert_equal 1, actual_host_updates.first['sequence']
assert_not_nil actual_host_finished = actual_json3.find { |l| l['type'] == 'playbook_run_finished' && l['host'] == 'TEST_UUID1' }
assert_equal 'TEST_CORRELATION', actual_host_finished['correlation_id']
assert_equal 'TEST_UUID1', actual_host_finished['host']
assert_equal 'success', actual_host_finished['status']
assert_equal 7, actual_host_finished.size

actual_host_updates = actual_jsonl
.select { |l| l['type'] == 'playbook_run_update' && l['host'] == @host2.insights.uuid }
assert_equal 0, actual_host_updates.size
assert_not_nil actual_report_finished = actual_json3.find { |l| l['type'] == 'playbook_run_completed' }
assert_equal 'TEST_CORRELATION', actual_report_finished['correlation_id']
assert_equal 'success', actual_report_finished['status']
assert_equal 4, actual_report_finished.size
end

private
Expand Down Expand Up @@ -164,10 +245,12 @@ def generate_job_invocation
:value => '1'
)

@host1 = FactoryBot.create(:host, :with_insights_hits, name: 'host1')
@host1 = FactoryBot.create(:host, :with_insights_hits)
@host1.name = 'host1' # overriding name since there is an issue with Factorybot and setting the name correctly, same for 2nd host
@host1.insights.uuid = 'TEST_UUID1'
@host1.insights.save!
@host2 = FactoryBot.create(:host, :with_insights_hits, name: 'host2')
@host2 = FactoryBot.create(:host, :with_insights_hits)
@host2.name = 'host2'
@host2.insights.uuid = 'TEST_UUID2'
@host2.insights.save!

Expand All @@ -190,7 +273,7 @@ def generate_job_invocation
{ 'timestamp' => (Time.now - (5 - i)).to_f, 'output' => "#{i}\n" }
end
Support::DummyDynflowAction.any_instance.stubs(:live_output).returns(fake_output)
Support::DummyDynflowAction.any_instance.stubs(:exit_status).returns(0)
Support::DummyDynflowAction.any_instance.stubs(:exit_status).returns("0")

job_invocation
end
Expand Down
Loading