app/controllers/miq_ae_tools_controller.rb
class MiqAeToolsController < ApplicationController
include Mixins::BreadcrumbsMixin
before_action :check_privileges
before_action :get_session_data
after_action :cleanup_action
after_action :set_session_data
def index
resolve
end
def show
@lastaction = "resolve"
end
# handle buttons pressed on the button bar
def button
@edit = session[:edit] # Restore @edit for adv search box
@refresh_div = "main_div" # Default div for button.rjs to refresh
if params[:pressed] == "refresh_log"
refresh_log
return
end
unless @refresh_partial # if no button handler ran, show not implemented msg
add_flash(_("Button not yet implemented"), :error)
@refresh_partial = "layouts/flash_msg"
@refresh_div = "flash_msg_div"
end
end
def log
assert_privileges("fetch_log")
@breadcrumbs = []
@log = Vmdb::Loggers.contents($miq_ae_logger)
add_flash(_("Logs for this %{product} Server are not available for viewing") % {:product => Vmdb::Appliance.PRODUCT_NAME}, :warning) if @log.blank?
@lastaction = "log"
@layout = "miq_ae_logs"
@msg_title = "AE"
@download_action = "fetch_log"
drop_breadcrumb(:name => _("Log"), :url => "/miq_ae_tools/log")
render :action => "show"
end
def refresh_log
assert_privileges("refresh_log")
@log = Vmdb::Loggers.contents($miq_ae_logger)
add_flash(_("Logs for this %{product} Server are not available for viewing") % {:product => Vmdb::Appliance.PRODUCT_NAME}, :warning) if @log.blank?
replace_main_div(:partial => "layouts/log_viewer",
:locals => {:legend_text => _("Last 1000 lines from the Automation log")})
end
# Send the log in text format
def fetch_log
assert_privileges("fetch_log")
disable_client_cache
log = Vmdb::Loggers.contents($miq_ae_logger, nil)
send_data(log, :filename => "automation.log") if log
AuditEvent.success(:userid => session[:userid],
:event => "download_automation_log",
:message => _("Automation log downloaded"))
end
# AJAX driven routine to check for changes in ANY field on the form
def form_field_changed
assert_privileges('miq_ae_class_simulation')
get_form_vars
render :update do |page|
page << javascript_prologue
if params.key?(:instance_name) || params.key?(:starting_object) ||
params.key?(:target_class) || params.key?(:target_id) ||
params.key?(:other_name) || params.key?(:target_attr_name)
unless params.key?(:other_name) || params.key?(:target_attr_name)
page.replace("resolve_form_div", :partial => "resolve_form")
end
if @resolve[:throw_ready]
page << javascript_hide("throw_off")
page << javascript_show("throw_on")
else
page << javascript_hide("throw_on")
page << javascript_show("throw_off")
end
end
end
end
def import_export
assert_privileges('miq_ae_class_import_export')
@in_a_form = true
@breadcrumbs = []
drop_breadcrumb(:name => _("Import / Export"), :url => "/miq_ae_tools/import_export")
@lastaction = "import_export"
@layout = "miq_ae_export"
@importable_domain_options = []
MiqAeDomain.all_unlocked.collect do |domain|
@importable_domain_options << [domain.name, domain.name]
end
editable_domains = current_tenant.editable_domains.collect(&:name)
@importable_domain_options = @importable_domain_options.select do |importable_domain|
editable_domains.include?(importable_domain[0])
end
@importable_domain_options.unshift([_("<Same as import from>"), nil])
render :action => "show"
end
def automate_json
assert_privileges('miq_ae_class_import_export')
begin
automate_json = automate_import_json_serializer.serialize(ImportFileUpload.find(params[:import_file_upload_id]))
rescue StandardError => e
add_flash(_("Error: import processing failed: %{message}") % {:message => e.message}, :error)
end
respond_to do |format|
if @flash_array&.count
format.json { render :json => @flash_array.first.to_json, :status => 500 }
else
format.json { render :json => automate_json }
end
end
end
def cancel_import
assert_privileges('miq_ae_class_import_export')
automate_import_service.cancel_import(params[:import_file_upload_id])
add_flash(_("Datastore import was cancelled or is finished"), :info)
respond_to do |format|
format.json { render :json => @flash_array.to_json, :status => 200 }
end
end
def import_via_git
assert_privileges('miq_ae_class_import_export')
begin
git_based_domain_import_service.import(params[:git_repo_id], params[:git_branch_or_tag], current_tenant.id)
add_flash(_("Imported from git"), :info)
rescue StandardError => error
add_flash(_("Error: import failed: %{message}") % {:message => error.message}, :error)
end
respond_to do |format|
format.json { render :json => @flash_array.to_json, :status => 200 }
end
end
def import_automate_datastore
assert_privileges('miq_ae_class_import_export')
if params[:selected_namespaces].present?
selected_namespaces = determine_all_included_namespaces(params[:selected_namespaces])
import_file_upload = ImportFileUpload.where(:id => params[:import_file_upload_id]).first
if import_file_upload
begin
import_stats = automate_import_service.import_datastore(
import_file_upload,
params[:selected_domain_to_import_from],
params[:selected_domain_to_import_to],
selected_namespaces.sort
)
if import_stats.nil?
add_flash(_("Error: Datastore import was not successful"), :error)
else
stat_options = generate_stat_options(import_stats)
add_flash(_("Datastore import was successful.
Namespaces updated/added: %{namespace_stats}
Classes updated/added: %{class_stats}
Instances updated/added: %{instance_stats}
Methods updated/added: %{method_stats}") % stat_options, :success)
end
rescue MiqAeException::Error => bang
add_flash(_("Error: %{message}") % {:message => bang.message}, :error)
end
else
add_flash(_("Error: Datastore import file upload expired"), :error)
end
else
add_flash(_("You must select at least one namespace to import"), :info)
end
respond_to do |format|
format.json { render :json => @flash_array.to_json, :status => 200 }
end
end
def upload_import_file
assert_privileges('miq_ae_class_import_export')
redirect_options = {:action => :review_import}
upload_file = params.fetch_path(:upload, :file)
if upload_file.blank?
add_flash(_("Use the Choose file button to locate an import file"), :warning)
else
import_file_upload_id = automate_import_service.store_for_import(upload_file.read)
add_flash(_("Import file was uploaded successfully"), :success)
redirect_options[:import_file_upload_id] = import_file_upload_id
end
flash_to_session
redirect_to(redirect_options)
end
def review_import
assert_privileges('miq_ae_class_import_export')
@import_file_upload_id = params[:import_file_upload_id]
@message = @flash_array.first.to_json
end
def retrieve_git_datastore
assert_privileges('miq_ae_class_import_export')
git_url = params[:git_url]
if git_url.blank?
add_flash(_("Please provide a valid git URL"), :error)
response_json = {:message => @flash_array.first}
elsif !GitBasedDomainImportService.available?
add_flash(_("Please enable the git owner role in order to import git repositories"), :error)
response_json = {:message => @flash_array.first}
else
begin
setup_results = git_repository_service.setup(
git_url,
params[:git_username],
params[:git_password],
params[:git_verify_ssl]
)
git_repo_id = setup_results[:git_repo_id]
new_git_repo = setup_results[:new_git_repo?]
task_id = git_based_domain_import_service.queue_refresh(git_repo_id)
response_json = {:task_id => task_id, :git_repo_id => git_repo_id, :new_git_repo => new_git_repo}
rescue StandardError => err
add_flash(_("Error during repository setup: %{error_message}") % {:error_message => err.message}, :error)
response_json = {:message => @flash_array.first}
end
end
respond_to do |format|
format.json { render :json => response_json.to_json, :status => 200 }
end
end
def check_git_task
assert_privileges('miq_ae_class_import_export')
task = MiqTask.find(params[:task_id])
json = if task.state != MiqTask::STATE_FINISHED
{:state => task.state}
else
git_repo = GitRepository.find(params[:git_repo_id])
if task.status == "Ok"
branch_names = git_repo.git_branches.collect(&:name)
tag_names = git_repo.git_tags.collect(&:name)
flash_message = "Successfully found git repository, please choose a branch or tag"
add_flash(_(flash_message), :success)
{
:git_branches => branch_names,
:git_tags => tag_names,
:git_repo_id => git_repo.id,
:success => true,
:message => @flash_array.first
}
else
git_repo.destroy if git_repo && params[:new_git_repo] != "false"
add_flash(_("Error during repository fetch: %{message}") % {:message => task.message}, :error)
{
:success => false,
:message => @flash_array.first
}
end
end
respond_to do |format|
format.json { render :json => json.to_json, :status => 200 }
end
end
# Import classes
def upload
assert_privileges('miq_ae_class_import_export')
if params[:upload] && params[:upload][:datastore].present?
begin
MiqAeDatastore.upload(params[:upload][:datastore])
flash_to_session(_("Datastore import was successful. Added/Updated %{namespace_stats} Namespaces, %{class_stats} Classes, %{instance_stats} Instances, %{method_stats} Methods.") % stat_options)
redirect_to(:action => 'import_export')
rescue StandardError => bang
flash_to_session(_("Error during 'upload': %{message}") % {:message => bang.message}, :error)
redirect_to(:action => 'import_export')
end
else
@in_a_form = true
add_flash(_("Use the Choose file button to locate an Import file"), :error)
# render :action=>"import_export"
import_export
end
end
# Send all classes and instances
def export_datastore
assert_privileges('miq_ae_class_import_export')
filename = "datastore_" + format_timezone(Time.now, Time.zone, "fname") + ".zip"
disable_client_cache
send_data(MiqAeDatastore.export(current_tenant), :filename => filename)
end
# Reset all custom classes and instances to default
def reset_datastore
assert_privileges('miq_ae_class_import_export')
unless params[:task_id] # First time thru, kick off the report generate task
initiate_wait_for_task(:task_id => MiqAutomate.async_datastore_reset)
return
end
miq_task = MiqTask.find(params[:task_id]) # Not first time, read the task record
session[:ae_id] = params[:id]
session[:ae_task_id] = params[:task_id]
if miq_task.status != "Ok" # Check to see if any results came back or status not Ok
add_flash(_("Error during reset: Status [%{status}] Message [%{message}]") %
{:status => miq_task.status, :message => miq_task.message}, :error)
else
self.x_node = "root" if x_active_tree == :ae_tree && x_tree
add_flash(_("All custom classes and instances have been reset to default"))
end
javascript_flash(:spinner_off => true)
end
private ###########################
def automate_import_json_serializer
@automate_import_json_serializer ||= AutomateImportJsonSerializerService.new
end
def automate_import_service
@automate_import_service ||= AutomateImportService.new
end
def git_based_domain_import_service
@git_based_domain_import_service ||= GitBasedDomainImportService.new
end
def git_repository_service
@git_repository_service ||= GitRepositoryService.new
end
def add_stats(stats_hash)
stats_hash.inject(0) do |result, key_value|
result + key_value[1]
end
end
def determine_all_included_namespaces(namespaces)
namespaces.each do |namespace|
potentially_missed_namespaces = determine_missed_namespaces(namespace)
namespaces += potentially_missed_namespaces
end
namespaces.uniq
end
def generate_stat_options(import_stats)
namespace_stats = add_stats(import_stats[:namespace])
class_stats = add_stats(import_stats[:class])
instance_stats = add_stats(import_stats[:instance])
method_stats = add_stats(import_stats[:method])
{
:namespace_stats => namespace_stats,
:class_stats => class_stats,
:instance_stats => instance_stats,
:method_stats => method_stats
}
end
def determine_missed_namespaces(namespace)
if namespace.match?("/")
[namespace, determine_missed_namespaces(namespace.split("/")[0..-2].join("/"))].flatten
else
[namespace]
end
end
def ws_text_from_xml(xml, depth = 0)
txt = ""
if depth.zero?
txt += "<#{xml.root.name}>\n"
xml.root.each_element do |e|
txt += " "
txt += e.inspect + "\n"
txt += ws_text_from_xml(e, depth + 2)
txt += " "
txt += "<\\#{e.name}>\n"
end
txt += "<\\#{xml.root.name}>"
else
xml.each_element do |e|
depth.times { txt += " " }
txt += e.inspect + "\n"
txt += ws_text_from_xml(e, depth + 1)
depth.times { txt += " " }
txt += "<\\#{e.name}>\n"
end
end
txt
end
def valid_resolve_object?
add_flash(_("Starting Class must be selected"), :error) if @resolve[:new][:starting_object].blank?
if @resolve[:new][:instance_name].blank? && @resolve[:new][:other_name].blank?
add_flash(_("Starting Process is required"), :error)
end
add_flash(_("Request is required"), :error) if @resolve[:new][:object_request].blank?
ApplicationController::AE_MAX_RESOLUTION_FIELDS.times do |i|
f = ("attribute_" + (i + 1).to_s)
v = ("value_" + (i + 1).to_s)
add_flash(_("%{val} missing for %{field}") % {:val => f.titleize, :field => v.titleize}, :error) if @resolve[:new][:attrs][i][0].blank? && @resolve[:new][:attrs][i][1].present?
add_flash(_("%{val} missing for %{field}") % {:val => v.titleize, :field => f.titleize}, :error) if @resolve[:new][:attrs][i][0].present? && @resolve[:new][:attrs][i][1].blank?
end
!flash_errors?
end
def get_form_vars
if params.key?(:starting_object)
@resolve[:new][:starting_object] = params[:starting_object]
@resolve[:new][:instance_name] = nil
end
if params[:readonly]
@resolve[:new][:readonly] = (params[:readonly] != "1")
end
copy_params_if_present(@resolve[:new], params, %i[instance_name other_name object_message object_request target_class target_id])
ApplicationController::AE_MAX_RESOLUTION_FIELDS.times do |i|
f = ("attribute_" + (i + 1).to_s)
v = ("value_" + (i + 1).to_s)
@resolve[:new][:attrs][i][0] = params[f] if params[f.to_sym]
@resolve[:new][:attrs][i][1] = params[v] if params[v.to_sym]
end
if params.key?(:target_class)
targets = Rbac.filtered(params[:target_class]).select(:id, *columns_for_klass(params[:target_class])) if params[:target_class].present?
unless targets.nil?
@resolve[:targets] = targets.sort_by { |t| t.name.downcase }.collect { |t| [t.name, t.id.to_s] }
@resolve[:new][:target_id] = nil
end
end
@resolve[:new][:target_id] = nil if params[:target_class] == ""
copy_params_if_present(@resolve, params, %i[button_text button_number])
@resolve[:throw_ready] = ready_to_throw
end
def get_session_data
@layout = "miq_ae_tools"
@resolve = session[:resolve_tools] if session[:resolve_tools]
end
def set_session_data
session[:resolve_tools] = @resolve if @resolve
end
def breadcrumbs_options
{
:breadcrumbs => [
{:title => _("Automation")},
{:title => _("Automate")},
action_name == "resolve" ? {:title => _("Simulation")} : nil,
].compact,
:hide_title => action_name == "resolve",
}
end
menu_section :automate
end