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] To Show terraform output in Services #72

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def start

def pre_execute
checkout_git_repository
signal(:execute)
route_signal(:execute)
end

def execute
Expand All @@ -27,28 +27,65 @@ def execute

options[:terraform_stack_id] = response.stack_id
save!

queue_poll_runner
route_signal(:poll_runner)
#queue_poll_runner
end

def poll_runner
if running?
queue_poll_runner
else
signal(:post_execute)
logs_update
route_signal(:post_execute)
end
end

def post_execute
cleanup_git_repository


#cleanup_git_repository
Copy link
Member

Choose a reason for hiding this comment

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

Are we no longer cleaning up the git repository?


return queue_signal(:finish, message, status) if success?

#queue_signal(:finish, message, status)
return queue_signal(:abort, "Failed to run ansible", "error") unless success?
_log.error("Failed to run template: [#{error_message}]")

abort_job("Failed to run template", "error")
end

def logs_update
terraform_response = {
stack_id: stack_response&.response&.stack_id,
stack_name: stack_response&.response&.stack_name,
status: stack_response&.response&.status,
stack_job_end_time: stack_response&.response&.stack_job_end_time,
stack_job_start_time: stack_response&.response&.stack_job_start_time,
created_at: stack_response&.response&.created_at,
message: stack_response&.response&.message,
error_message: stack_response&.response&.error_message
}

miq_task.context_data ||= {}
miq_task.context_data[:terraform_response] = terraform_response
context[:terraform_response] = terraform_response

update!(:context => context, :started_on => context[:terraform_response][:stack_job_start_time])
miq_task.update(context_data: miq_task.context_data)
end

def queue_signal(*args, deliver_on: nil, msg_timeout: nil)
role = options[:role] || "ems_operations"
priority = options[:priority] || MiqQueue::NORMAL_PRIORITY
super(*args, :msg_timeout => msg_timeout, :priority => priority, :role => role, :deliver_on => deliver_on, :server_guid => MiqServer.my_server.guid)
end

def route_signal(*args, deliver_on: nil)
if MiqEnvironment::Command.is_podified?
signal(*args)
else
Comment on lines +82 to +84
Copy link
Member

Choose a reason for hiding this comment

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

@jaisejose1123 do we need this for terraform? The reason it is like this in embedded_ansible is because the files/directories related to the ansible-runner execution are literally on the pod's filesystem so we have to run it on the same pod, but this has a number of drawbacks and something we want to get away from.

With the opentofu-runner any pod in the namespace should be able to hit that API so any pod could run the next state.

queue_signal(*args, :deliver_on => deliver_on)
end
end

alias initializing dispatch_start
alias finish process_finished
alias abort_job process_abort
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ class ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Stack < ManageI
belongs_to :configuration_script_payload, :foreign_key => :configuration_script_base_id, :class_name => "ManageIQ::Providers::EmbeddedTerraform::AutomationManager::Template", :inverse_of => :stacks
belongs_to :miq_task, :foreign_key => :ems_ref, :inverse_of => false

virtual_has_many :job_plays

class << self
alias create_job create_stack
alias raw_create_job raw_create_stack
Expand All @@ -26,6 +28,43 @@ def create_stack(terraform_template, options = {})
)
end

def raw_stdout_via_worker(userid, format = 'txt')
unless MiqRegion.my_region.role_active?("embedded_terraform")
msg = "Cannot get standard output of this terraform because the embedded Terraform role is not enabled"
return MiqTask.create(
:name => 'terraform_stdout',
:userid => userid || 'system',
:state => MiqTask::STATE_FINISHED,
:status => MiqTask::STATUS_ERROR,
:message => msg
).id
end

options = {:userid => userid || 'system', :action => 'terraform_stdout'}
queue_options = {
:class_name => self.class,
:method_name => 'raw_stdout',
:instance_id => id,
:args => [format],
:priority => MiqQueue::HIGH_PRIORITY,
:role => nil
}

MiqTask.generic_action_with_callback(options, queue_options)
end

def job_plays
resources.where(:resource_category => 'job_play').order(:start_time)
end

def raw_stdout(format = 'txt')
case format
when "json" then raw_stdout_json
when "html" then raw_stdout_html
else raw_stdout_txt
end
end

def raw_create_stack(terraform_template, options = {})
terraform_template.run(options)
rescue => err
Expand All @@ -49,9 +88,36 @@ def refresh
self.finish_time = raw_status.completed? ? miq_task.updated_on : nil
save!
end
update_plays
end

def update_plays
tasks = miq_task.try(&:context_data).try(:[], :terraform_response)
options = {
:name => tasks[:stack_name],
:ems_ref => tasks[:stack_id],
:resource_status => tasks[:status],
:start_time => tasks[:stack_job_start_time],
:finish_time => tasks[:stack_job_end_time],
:stack_id => self.id,
:resource_category => "job_play"
}
resource = OrchestrationStackResource.new(options)
resource.save
end

def raw_status
Status.new(miq_task)
end

def raw_stdout_json
miq_task.try(&:context_data).try(:[], :terraform_response).try(:[], :message) || []
end


def raw_stdout_html
text = raw_stdout_json
text = _("No output available") if text.blank?
TerminalToHtml.render(text)
end
end
45 changes: 45 additions & 0 deletions app/models/service_terraform_template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ def refresh(action)
stack(action).refresh
end

def on_error(action)
_log.info("on_error called for service action: #{action}")
update(:retirement_state => 'error') if action == "Retirement"
if job(action)
stack(action).try(:refresh)
postprocess(action)
else
_log.info("postprocess not called because job was nil")
end
end

def postprocess(action)
log_stdout(action)
end


def job(action)
service_resources.find_by(:name => action, :resource_type => 'OrchestrationStack').try(:resource)
end

def check_refreshed(_action)
[true, nil]
end
Expand Down Expand Up @@ -117,4 +137,29 @@ def translate_credentials!(options)
credential_id = options.delete(:credential_id)
options[:credentials] << Authentication.find(credential_id).native_ref if credential_id.present?
end

def log_stdout(action)
log_option = options.fetch_path(:config_info, action.downcase.to_sym, :log_output) || 'on_error'
job = job(action)
if job.nil?
$log.info("No stdout available due to missing job")
else
terraform_log_stdout(log_option, job)
end
end

def terraform_log_stdout(log_option, job)
raise ArgumentError, "invalid job object" if job.nil?
return unless %(on_error always).include?(log_option)
return if log_option == 'on_error' && job.raw_status.succeeded?

$log.info("Stdout from ansible job #{job.name}: #{job.raw_stdout('txt_download')}")
rescue StandardError => err
if job.nil?
$log.error("Job was nil, must pass a valid job")
else
$log.error("Failed to get stdout from ansible job #{job.name}")
end
$log.log_backtrace(err)
end
end
Loading