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

Ansible Playbook Control UI #399

Merged
merged 9 commits into from Feb 17, 2017
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/controllers/miq_policy_controller.rb
Expand Up @@ -715,6 +715,9 @@ def send_button_changes
render :update do |page|
page << javascript_prologue
if @edit
if @refresh_inventory
page.replace("action_options_div", :partial => "action_options")
end
if @action_type_changed || @snmp_trap_refresh
page.replace("action_options_div", :partial => "action_options")
elsif @alert_refresh
Expand Down
42 changes: 42 additions & 0 deletions app/controllers/miq_policy_controller/miq_actions.rb
Expand Up @@ -120,12 +120,20 @@ def action_field_changed
end
@snmp_trap_refresh = build_snmp_options(:options, @edit[:new][:action_type] == "snmp_trap")
@edit[:new][:options][:scan_item_set_name] = params[:analysis_profile] if params[:analysis_profile]
@refresh_inventory = false
if params[:inventory_manual] || params[:inventory_localhost] || params[:inventory_event_target]
@refresh_inventory = true
update_playbook_variables(params)
end
@edit[:new][:options][:service_template_id] = params[:service_template_id].to_i if params[:service_template_id]
@edit[:new][:options][:hosts] = params[:hosts] if params[:hosts]

if params[:miq_action_type] && params[:miq_action_type] != @edit[:new][:action_type] # action type was changed
@edit[:new][:action_type] = params[:miq_action_type]
@edit[:new][:options] = {} # Clear out the options
action_build_alert_choices if params[:miq_action_type] == "evaluate_alerts" # Build alert choices hash
action_build_snmp_variables if params[:miq_action_type] == "snmp_trap" # Build snmp_trap variables hash
action_initialize_playbook_variables
if params[:miq_action_type] == "tag"
get_tags_tree
end
Expand All @@ -135,6 +143,20 @@ def action_field_changed
send_button_changes
end

def action_initialize_playbook_variables
@edit[:new][:options][:use_event_target] = @edit[:new][:inventory_type] == 'event_target'
@edit[:new][:options][:use_localhost] = @edit[:new][:inventory_type] == 'localhost'
end

def update_playbook_variables(params)
@edit[:new][:inventory_type] = params[:inventory_manual] if params[:inventory_manual]
@edit[:new][:inventory_type] = params[:inventory_localhost] if params[:inventory_localhost]
@edit[:new][:inventory_type] = params[:inventory_event_target] if params[:inventory_event_target]
@edit[:new][:options][:hosts] = '' if params[:inventory_localhost] || params[:inventory_event_target]
@edit[:new][:options][:use_event_target] = @edit[:new][:inventory_type] == 'event_target'
@edit[:new][:options][:use_localhost] = @edit[:new][:inventory_type] == 'localhost'
end

def action_tag_pressed
@edit = session[:edit]
@action = @edit[:action_id] ? MiqAction.find_by_id(@edit[:action_id]) : MiqAction.new
Expand Down Expand Up @@ -276,6 +298,10 @@ def action_build_edit_screen
].sort_by { |x| x.first.downcase }
@edit[:cats] = MiqAction.inheritable_cats.sort_by { |c| c.description.downcase }.collect { |c| [c.name, c.description] }

@edit[:ansible_playbooks] = ServiceTemplateAnsiblePlaybook.order(:name).pluck(:name, :id) || {}
@edit[:new][:inventory_type] = 'localhost'
action_build_playbook_variables if @action.action_type == "run_ansible_playbook"

@edit[:current] = copy_hash(@edit[:new])
get_tags_tree
@in_a_form = true
Expand Down Expand Up @@ -327,6 +353,12 @@ def action_set_record_vars(action)
end
end

def action_build_playbook_variables
@edit[:new][:inventory_type] = 'manual' if @edit[:new][:options][:hosts]
@edit[:new][:inventory_type] = 'event_target' if @edit[:new][:options][:use_event_target]
@edit[:new][:inventory_type] = 'localhost' if @edit[:new][:options][:use_localhost]
end

# Check action record variables
def action_valid_record?(rec)
edit = @edit[:new]
Expand Down Expand Up @@ -365,12 +397,22 @@ def action_valid_record?(rec)
rec[:options][:variables] = options[:variables].reject { |var| var[:oid].blank? }
end
end

validate_playbook_options(options) if edit[:action_type] == "run_ansible_playbook"

if edit[:action_type] == "tag" && options[:tags].blank?
add_flash(_("At least one Tag must be selected"), :error)
end
@flash_array.nil?
end

def validate_playbook_options(options)
add_flash(_("An Ansible Playbook must be selected"), :error) if options[:service_template_id].blank?
if @edit[:new][:inventory_type] == 'manual' && options[:hosts].blank?
add_flash(_("At least one host must be specified for manual mode"), :error)
end
end

# Get information for an action
def action_get_info(action)
@record = @action = action
Expand Down
2 changes: 2 additions & 0 deletions app/decorators/miq_action_decorator.rb
Expand Up @@ -33,6 +33,8 @@ def fonticon
'fa fa-tag'
when 'vm_collect_running_processes'
'fa fa-cogs'
when 'run_ansible_playbook'
'fa fa-file-text-o'
when 'default'
'product product-action'
end
Expand Down
52 changes: 51 additions & 1 deletion app/views/miq_policy/_action_options.html.haml
@@ -1,7 +1,6 @@
- url = url_for(:action => 'action_field_changed', :id => "#{@action.id || 'new'}")
- observe_with_interval = {:interval => '.5', :url => url}.to_json
- observe = {:url => url}.to_json

#action_options_div
- case @edit[:new][:action_type]
- when "email"
Expand Down Expand Up @@ -321,3 +320,54 @@
%td{:align => "left", :valign => "top", :nowrap => 1}
= check_box_tag("cat_#{cat.first}", "1", checked, "data-miq_observe_checkbox" => observe)
= h(cat.last)
- when "run_ansible_playbook"
%h3
= _("Run an Ansible Playbook")
.form-horizontal
.form-group
%label.control-label.col-md-2
= _("Ansible Playbook:")
.col-md-8
= select_tag('service_template_id',
options_for_select([["<#{_('Choose')}>", nil]] + @edit[:ansible_playbooks],
@edit[:new][:options][:service_template_id]),
:style => "width:150px",
:class => "selectpicker")
:javascript
miqInitSelectPicker();
miqSelectPickerEvent('service_template_id', '#{url}')
.form-group
%label.control-label.col-md-2
= _("Inventory:")
.col-md-8
= radio_button_tag('inventory', "localhost", true,
"title" => _('Run on localhost'),
"checked" => @edit[:new][:inventory_type] == "localhost",
"data-miq_observe" => observe)
= label_tag('inventory_localhost', _("Localhost"), "title" => _('Run on localhost'))
%br
= radio_button_tag('inventory', "event_target", false,
"title" => _('Run on the target machine of the alert'),
"checked" => @edit[:new][:inventory_type] == "event_target",
"data-miq_observe" => observe)
= label_tag('inventory_event_target', _("Target Machine"), "title" => _('Run on the target machine of the alert'))
%br
= radio_button_tag('inventory', "manual", false,
"title" => _('Enter a comma separated list of IP or DNS names'),
"checked" => @edit[:new][:inventory_type] == "manual",
"data-miq_observe" => observe)
= label_tag('inventory_manual', _("Specific Hosts"), "title" => _('Enter a comma separated list of IP or DNS names'))
#manual_inventory_div{:style => @edit[:new][:inventory_type] == "manual" ? "" : "display:none"}
.form-group
.col-md-8
= text_field_tag("hosts",
@edit[:new][:options][:hosts],
:maxlength => MAX_DESC_LEN,
:class => "form-control",
"data-miq_observe" => observe_with_interval)
= _('Enter a comma separated list of IP or DNS names')





48 changes: 48 additions & 0 deletions spec/controllers/miq_policy_controller/miq_actions_spec.rb
Expand Up @@ -60,7 +60,55 @@
expect(assigns(:flash_array).first[:message]).to include("saved")
expect(controller.send(:flash_errors?)).not_to be_truthy
end

it "can edit an Ansible playbook action" do
controller.instance_variable_set(:@_params, :id => @action.id)
controller.action_edit
edit = controller.instance_variable_get(:@edit)
edit[:new][:action_type] = "run_ansible_playbook"
edit[:new][:inventory_type] = 'manual'
edit[:new][:options][:hosts] = 'host1, host2'
edit[:new][:options][:service_template_id] = '01'
session[:edit] = assigns(:edit)
controller.instance_variable_set(:@_params, :id => @action.id, :button => "save")
controller.action_edit
expect(assigns(:flash_array).first[:message]).not_to include("At least one Playbook")
expect(assigns(:flash_array).first[:message]).to include("saved")
expect(controller.send(:flash_errors?)).not_to be_truthy
end

it "displays an error if no Ansible playbook is selected" do
allow(controller).to receive(:javascript_flash)
controller.instance_variable_set(:@_params, :id => @action.id)
controller.action_edit
edit = controller.instance_variable_get(:@edit)
edit[:new][:action_type] = "run_ansible_playbook"
edit[:new][:inventory_type] = 'event_target'
edit[:new][:options][:use_event_target] = true
edit[:new][:options][:use_event_localhost] = false
session[:edit] = assigns(:edit)
controller.instance_variable_set(:@_params, :id => @action.id, :button => "save")
controller.action_edit
expect(assigns(:flash_array).first[:message]).to include("An Ansible Playbook must be selected")
expect(controller.send(:flash_errors?)).to be_truthy
end

it "displays an error if no hosts are slected for an Ansible playbook with 'manual' inventory" do
allow(controller).to receive(:javascript_flash)
controller.instance_variable_set(:@_params, :id => @action.id)
controller.action_edit
edit = controller.instance_variable_get(:@edit)
edit[:new][:action_type] = "run_ansible_playbook"
edit[:new][:inventory_type] = 'manual'
edit[:new][:options][:service_template_id] = '01'
session[:edit] = assigns(:edit)
controller.instance_variable_set(:@_params, :id => @action.id, :button => "save")
controller.action_edit
expect(assigns(:flash_array).first[:message]).to include("At least one host must be specified for manual mode")
expect(controller.send(:flash_errors?)).to be_truthy
end
end

describe "#action_get_info" do
let(:cat1) { FactoryGirl.create(:classification, :description => res.first) }
let(:cat2) { FactoryGirl.create(:classification, :description => res.second) }
Expand Down