diff --git a/app/models/manageiq/providers/embedded_ansible/automation_manager/job.rb b/app/models/manageiq/providers/embedded_ansible/automation_manager/job.rb index ae175ce761b..c0f4b2ee454 100644 --- a/app/models/manageiq/providers/embedded_ansible/automation_manager/job.rb +++ b/app/models/manageiq/providers/embedded_ansible/automation_manager/job.rb @@ -55,7 +55,7 @@ def refresh_ems end def job_plays - [] + resources.where(:resource_category => 'job_play').order(:start_time) end # Intend to be called by UI to display stdout. The stdout is stored in MiqTask#task_results or #message if error @@ -111,13 +111,47 @@ def self.collect_authentications(manager, options) private_class_method :collect_authentications def update_with_provider_object(raw_job) - self.miq_task ||= raw_job.miq_task + transaction do + self.miq_task ||= raw_job.miq_task - update_attributes!( - :status => miq_task.state, - :start_time => miq_task.started_on, - :finish_time => raw_status.completed? ? miq_task.updated_on : nil - ) + self.status = miq_task.state + self.start_time = miq_task.started_on + self.finish_time = raw_status.completed? ? miq_task.updated_on : nil + + update_plays + save! + end + end + + def update_plays + plays = raw_stdout_json.select do |playbook_event| + playbook_event["event"] == "playbook_on_play_start" + end.collect do |play| + { + :name => play["event_data"]["play"], + :resource_status => play["failed"] ? 'failed' : 'successful', + :start_time => play["created"], + :ems_ref => play["uuid"], + :resource_category => "job_play" + } + end + + # Set each play's finish_time to the next play's start time, with the + # final play's finish time set to the entire job's finish time. + plays.each_cons(2) do |last_play, play| + last_play[:finish_time] = play[:start_time] + end + plays[-1][:finish_time] = finish_time if plays.any? + + old_resources = resources.index_by(&:ems_ref) + self.resources = plays.collect do |play_hash| + if (old_resource = old_resources[play_hash[:ems_ref].to_s]) + old_resource.update!(play_hash) + old_resource + else + OrchestrationStackResource.new(play_hash) + end + end end def raw_stdout_json diff --git a/spec/models/manageiq/providers/embedded_ansible/automation_manager/job_spec.rb b/spec/models/manageiq/providers/embedded_ansible/automation_manager/job_spec.rb index a7e62db53ad..7a4282d6219 100644 --- a/spec/models/manageiq/providers/embedded_ansible/automation_manager/job_spec.rb +++ b/spec/models/manageiq/providers/embedded_ansible/automation_manager/job_spec.rb @@ -83,14 +83,46 @@ } end + before { Timecop.freeze } + after { Timecop.return } + + let(:the_raw_plays) do + [ + { + "id" => 1, + "event" => "playbook_on_play_start", + "failed" => false, + "created" => Time.current, + "event_data" => {"play" => "play1"} + }, + { + "id" => 2, + "event" => "some_other_event", + "failed" => false, + "created" => Time.current + 5, + "event_data" => {"stdout" => "foo"} + }, + { + "id" => 3, + "event" => "playbook_on_play_start", + "failed" => true, + "created" => Time.current + 10, + "event_data" => {"play" => "play2"} + } + ] + end + it "syncs the job with the provider" do + fake_finish_time = the_raw_plays.last["created"] + 15 + allow(subject).to receive(:finish_time).and_return(fake_finish_time) + expect(subject).to receive(:raw_stdout_json).and_return(the_raw_plays) subject.refresh_ems expect(subject).to have_attributes( :ems_ref => subject.miq_task.id.to_s, :status => subject.miq_task.state, :start_time => subject.miq_task.started_on, - :finish_time => nil, + :finish_time => fake_finish_time, :verbosity => 0 ) subject.reload @@ -99,28 +131,29 @@ expect(subject.authentications).to match_array([machine_credential, vault_credential, cloud_credential, network_credential]) + expect(subject.job_plays.first).to have_attributes( + :start_time => a_value_within(1.second).of(the_raw_plays.first["created"]), + :finish_time => a_value_within(1.second).of(the_raw_plays.last["created"]), + :resource_status => "successful", + :resource_category => "job_play", + :name => "play1" + ) + expect(subject.job_plays.last).to have_attributes( + :start_time => a_value_within(1.second).of(the_raw_plays.last["created"]), + :finish_time => a_value_within(1.second).of(fake_finish_time), + :resource_status => "failed", + :resource_category => "job_play", + :name => "play2" + ) + # TODO/FIXME: This needs to be implemented. # # The following are implemented in AnsibleTower::Job but not here: # # - update_parameters - # - update_plays # # expect(subject.parameters.first).to have_attributes(:name => "param1", :value => "val1") - # expect(subject.job_plays.first).to have_attributes( - # :start_time => a_value_within(1.second).of(the_raw_plays.first.created), - # :finish_time => a_value_within(1.second).of(the_raw_plays.last.created), - # :resource_status => "successful", - # :resource_category => "job_play", - # :name => "play1" - # ) - # expect(subject.job_plays.last).to have_attributes( - # :start_time => a_value_within(1.second).of(the_raw_plays.last.created), - # :finish_time => a_value_within(1.second).of(the_raw_job.finished), - # :resource_status => "failed", - # :resource_category => "job_play", - # :name => "play2" - # ) + # end # TODO: This is should be irrelevant now, right?