Project

General

Profile

« Previous | Next » 

Revision 2de7832d

Added by Ohad Levy over 10 years ago

fixes #3099 - Adding parameters to locations and organizations

View differences:

app/assets/javascripts/host_edit.js
var v = param.find('[id^=value_]').val();
$('#parameters').find('.btn-success').click();
var new_param = param.closest('.tab-pane').find('[id*=host_host_parameters]:visible').last().parent();
var new_param = param.closest('.tab-pane').find('[id*=host_host_parameters]:visible').last().parent().parent();
new_param.find('[id$=_name]').val(n);
new_param.find('[id$=_value]').val(v);
mark_params_override();
app/controllers/api/v2/parameters_controller.rb
api :GET, "/hostgroups/:hostgroup_id/parameters", "List all parameters for hostgroup"
api :GET, "/domains/:domain_id/parameters", "List all parameters for domain"
api :GET, "/operatingsystems/:operatingsystem_id/parameters", "List all parameters for operating system"
api :GET, "/locations/:location_id/parameters", "List all parameters for location"
api :GET, "/organizations/:organization_id/parameters", "List all parameters for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
param :page, String, :desc => "paginate results"
param :per_page, String, :desc => "number of entries per request"
......
api :GET, "/hostgroups/:hostgroup_id/parameters/:id", "Show a nested parameter for hostgroup"
api :GET, "/domains/:domain_id/parameters/:id", "Show a nested parameter for domain"
api :GET, "/operatingsystems/:operatingsystem_id/parameters/:id", "Show a nested parameter for operating system"
api :GET, "/locations/:location_id/parameters/:id", "Show a nested parameter for location"
api :GET, "/organizations/:organization_id/parameters/:id", "Show a nested parameter for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
param :id, String, :required => true, :desc => "id of parameter"
def show
......
api :POST, "/hostgroups/:hostgroup_id/parameters/", "Create a nested parameter for hostgroup"
api :POST, "/domains/:domain_id/parameters/", "Create a nested parameter for domain"
api :POST, "/operatingsystems/:operatingsystem_id/parameters/", "Create a nested parameter for operating system"
api :POST, "/locations/:location_id/parameters/", "Create a nested parameter for location"
api :POST, "/organizations/:organization_id/parameters/", "Create a nested parameter for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
param :parameter, Hash, :required => true do
param :name, String
param :value, String
......
api :PUT, "/hostgroups/:hostgroup_id/parameters/:id", "Update a nested parameter for hostgroup"
api :PUT, "/domains/:domain_id/parameters/:id", "Update a nested parameter for domain"
api :PUT, "/operatingsystems/:operatingsystem_id/parameters/:id", "Update a nested parameter for operating system"
api :PUT, "/locations/:location_id/parameters/:id", "Update a nested parameter for location"
api :PUT, "/organizations/:organization_id/parameters/:id", "Update a nested parameter for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
param :id, String, :required => true, :desc => "id of parameter"
param :parameter, Hash, :required => true do
param :name, String
......
api :DELETE, "/hostgroups/:hostgroup_id/parameters/:id", "Delete a nested parameter for hostgroup"
api :DELETE, "/domains/:domain_id/parameters/:id", "Delete a nested parameter for domain"
api :DELETE, "/operatingsystems/:operatingsystem_id/parameters/:id", "Delete a nested parameter for operating system"
api :DELETE, "/locations/:location_id/parameters/:id", "Delete a nested parameter for location"
api :DELETE, "/organizations/:organization_id/parameters/:id", "Delete a nested parameter for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
param :id, String, :required => true, :desc => "id of parameter"
def destroy
......
api :DELETE, "/hostgroups/:hostgroup_id/parameters", "Delete all nested parameters for hostgroup"
api :DELETE, "/domains/:domain_id/parameters", "Delete all nested parameters for domain"
api :DELETE, "/operatingsystems/:operatingsystem_id/parameters", "Delete all nested parameters for operating system"
api :DELETE, "/locations/:location_id/parameters", "Delete all nested parameter for location"
api :DELETE, "/organizations/:organization_id/parameters", "Delete all nested parameter for organization"
param :host_id, String, :desc => "id of host"
param :hostgroup_id, String, :desc => "id of hostgroup"
param :domain_id, String, :desc => "id of domain"
param :operatingsystem_id, String, :desc => "id of operating system"
param :location_id, String, :desc => "id of location"
param :organization_id, String, :desc => "id of organization"
def reset
@parameter = nested_obj.send(parameters_method)
......
end
def allowed_nested_id
%w(host_id hostgroup_id domain_id operatingsystem_id)
%w(host_id hostgroup_id domain_id operatingsystem_id location_id organization_id)
end
def find_parameter
app/helpers/common_parameters_helper.rb
content_tag :div, :class => "form-group condensed" do
text_area_tag("value_#{value[:value]}", value[:value], :rows => (value[:value].to_s.lines.count || 1 rescue 1),
:class => "col-md-5", :disabled => true) +
content_tag(:span, :class => "help-block") { popover(_("Additional info"), _("<b>Source:</b> %s") % (value[:source]))}
content_tag(:span, :class => "help-block") { popover(_("Additional info"), _("<b>Source:</b> %s") % _(value[:source].to_s))}
end
end
app/models/host/managed.rb
def host_inherited_params include_source = false
hp = {}
# read common parameters
CommonParameter.all.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :common} : p.value] }
CommonParameter.all.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => N_('common').to_sym} : p.value] }
if SETTINGS[:organizations_enabled] && organization
# read organization parameters
organization.parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => N_('organization').to_sym} : p.value] }
end
if SETTINGS[:locations_enabled] && location
# read location parameters
location.parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => N_('location').to_sym} : p.value] }
end
# read domain parameters
domain.domain_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :domain} : p.value] } unless domain.nil?
domain.domain_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => N_('domain').to_sym} : p.value] } unless domain.nil?
# read OS parameters
operatingsystem.os_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => :os} : p.value] } unless operatingsystem.nil?
operatingsystem.os_parameters.each {|p| hp.update Hash[p.name => include_source ? {:value => p.value, :source => N_('os').to_sym} : p.value] } unless operatingsystem.nil?
# read group parameters only if a host belongs to a group
hp.update hostgroup.parameters(include_source) unless hostgroup.nil?
hp
app/models/hostgroup.rb
# otherwise we might be overwriting the hash in the wrong order.
groups = ids.size == 1 ? [self] : Hostgroup.includes(:group_parameters).sort_by_ancestry(Hostgroup.find(ids))
groups.each do |hg|
hg.group_parameters.each {|p| hash[p.name] = include_source ? {:value => p.value, :source => :hostgroup} : p.value }
hg.group_parameters.each {|p| hash[p.name] = include_source ? {:value => p.value, :source => N_('hostgroup').to_sym} : p.value }
end
hash
end
app/models/parameters/location_parameter.rb
class LocationParameter < Parameter
belongs_to :location, :foreign_key => :reference_id
audited :except => [:priority], :associated_with => :location, :allow_mass_assignment => true
validates :name, :uniqueness => {:scope => :reference_id}
private
def enforce_permissions operation
# We get called again with the operation being set to create
return true if operation == "edit" and new_record?
return true if User.current.allowed_to?("#{operation}_locations".to_sym)
errors.add(:base, _("You do not have permission to %s this location parameter") % operation)
false
end
end
app/models/parameters/organization_parameter.rb
class OrganizationParameter < Parameter
belongs_to :organization, :foreign_key => :reference_id
audited :except => [:priority], :associated_with => :organization, :allow_mass_assignment => true
validates :name, :uniqueness => {:scope => :reference_id}
private
def enforce_permissions operation
# We get called again with the operation being set to create
return true if operation == "edit" and new_record?
return true if User.current.allowed_to?("#{operation}_organizations".to_sym)
errors.add(:base, _("You do not have permission to %s this organization parameter") % operation)
false
end
end
app/models/taxonomies/location.rb
has_and_belongs_to_many :organizations
has_many_hosts :dependent => :nullify
has_many :parameters, :dependent => :destroy, :foreign_key => :reference_id, :class_name => "LocationParameter"
accepts_nested_attributes_for :parameters, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
scope :completer_scope, lambda { |opts| my_locations }
scope :my_locations, lambda {
app/models/taxonomies/organization.rb
has_and_belongs_to_many :locations
has_many_hosts :dependent => :nullify
has_many :parameters, :dependent => :destroy, :foreign_key => :reference_id, :class_name => "OrganizationParameter"
accepts_nested_attributes_for :parameters, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
scope :completer_scope, lambda { |opts| my_organizations }
app/views/common_parameters/_parameter.html.erb
<div class="fields">
<table class="row">
<tr class="form-group <%= 'error' if f.object.errors.any? %>">
<td class="col-md-3">
<%= content_tag(:input, '', :class => "form-control", :disabled => true, :value => _('Global'), :type=> :text ) if controller_name =~ /(host|hostgroup)/ %>
<% if controller_name =~ /(host|hostgroup)/ %>
<td class="col-md-2">
<%= content_tag(:input, '', :class => "form-control", :disabled => true, :value => _('Global'), :type=> :text ) %>
</td>
<% end %>
<td class="col-md-2">
<%= f.text_field(:name, :class => "form-control", :disabled => (not authorized_via_my_scope("host_editing", "edit_params")), :placeholder => _("Name")) %>
</td>
app/views/taxonomies/_form.html.erb
<% javascript 'taxonomy' %>
<%= form_for taxonomy do |f| %>
<%= base_errors_for taxonomy %>
<%= text_f f, :name %>
<ul class="nav nav-tabs" data-tabs="tabs">
<%= base_errors_for taxonomy %>
<%= text_f f, :name %>
<div class="form-group row">
<ul class="nav nav-pills nav-stacked col-md-3" data-tabs="pills">
<li class="active"><a href="#users" data-toggle="tab"><%= _("Users") %></a></li>
<li><a href="#smart_proxies" data-toggle="tab"><%= _("Smart Proxies") %></a></li>
<% if SETTINGS[:unattended] %>
......
<% elsif taxonomy.is_a?(Location) && SETTINGS[:organizations_enabled] %>
<li><a href="#organizations" data-toggle="tab"><%= _("Organizations") %></a></li>
<% end %>
<li><a href="#params" data-toggle="tab"><%= _("Parameters") %></a></li>
</ul>
<div class="tab-content">
<div class="tab-content col-md-9">
<div class="tab-pane active" id="users">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Users"), :multiple => true, :onchange => 'ignore_checked(this)'}, "User") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All users"), :multiple => true, :onchange => 'ignore_checked(this)'}, "User") %>
<%= multiple_selects f, :users, User.except_admin, taxonomy.selected_ids[:user_ids],
{:disabled => taxonomy.used_and_selected_ids[:user_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:user_ids], :label => _('Select users')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:user_ids].to_json} %>
</div>
<div class="tab-pane" id="smart_proxies">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Smart Proxies"), :multiple => true, :onchange => 'ignore_checked(this)'}, "SmartProxy") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All smart proxies"), :multiple => true, :onchange => 'ignore_checked(this)'}, "SmartProxy") %>
<%= multiple_selects f, :smart_proxies, SmartProxy, taxonomy.selected_ids[:smart_proxy_ids],
{:disabled => taxonomy.used_and_selected_ids[:smart_proxy_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:smart_proxy_ids], :label => _('Select smart proxies')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:smart_proxy_ids].to_json} %>
</div>
<% if SETTINGS[:unattended] %>
<div class="tab-pane" id="subnets">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Subnets"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Subnet") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All subnets"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Subnet") %>
<%= multiple_selects f, :subnets, Subnet, taxonomy.selected_ids[:subnet_ids],
{:disabled => taxonomy.used_and_selected_ids[:subnet_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:subnet_ids], :label => _('Select subnets')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:subnet_ids].to_json} %>
</div>
<div class="tab-pane" id="compute_resources">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Compute Resources"), :multiple => true, :onchange => 'ignore_checked(this)'}, "ComputeResource") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All compute resources"), :multiple => true, :onchange => 'ignore_checked(this)'}, "ComputeResource") %>
<%= multiple_selects f, :compute_resources, ComputeResource, taxonomy.selected_ids[:compute_resource_ids],
{:disabled => taxonomy.used_and_selected_ids[:compute_resource_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:compute_resource_ids], :label => _('Select compute resources')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:compute_resource_ids].to_json} %>
</div>
<div class="tab-pane" id="media">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Media"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Medium") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All media"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Medium") %>
<%= multiple_selects f, :media, Medium, taxonomy.selected_ids[:medium_ids],
{:disabled => taxonomy.used_and_selected_ids[:medium_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:medium_ids], :label => _('Select media')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:medium_ids].to_json} %>
</div>
<div class="tab-pane" id="template">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Templates"), :multiple => true, :onchange => 'ignore_checked(this)'}, "ConfigTemplate") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All templates"), :multiple => true, :onchange => 'ignore_checked(this)'}, "ConfigTemplate") %>
<%= multiple_selects f, :config_templates, ConfigTemplate, taxonomy.selected_ids[:config_template_ids],
{:disabled => taxonomy.used_and_selected_ids[:config_template_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:config_template_ids], :label => _('Select templates')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:config_template_ids].to_json} %>
</div>
<div class="tab-pane" id="domains">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Domains"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Domain") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All domains"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Domain") %>
<%= multiple_selects f, :domains, Domain, taxonomy.selected_ids[:domain_ids],
{:disabled => taxonomy.used_and_selected_ids[:domain_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:domain_ids], :label => _('Select domains')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:domain_ids].to_json} %>
</div>
<% end %>
<div class="tab-pane" id="environments">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Environments"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Environment") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All environments"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Environment") %>
<%= multiple_selects f, :environments, Environment, taxonomy.selected_ids[:environment_ids],
{:disabled => taxonomy.used_and_selected_ids[:environment_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:environment_ids], :label => _('Select environments')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:environment_ids].to_json} %>
</div>
<div class="tab-pane" id="hostgroups">
<%= checkbox_f(f, :ignore_types, {:label => "", :help_text => _("All Host Groups"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Hostgroup") %>
<%= checkbox_f(f, :ignore_types, {:label => _("All host groups"), :multiple => true, :onchange => 'ignore_checked(this)'}, "Hostgroup") %>
<%= multiple_selects f, :hostgroups, Hostgroup, taxonomy.selected_ids[:hostgroup_ids],
{:disabled => taxonomy.used_and_selected_ids[:hostgroup_ids], :label => ''},
{:disabled => taxonomy.used_and_selected_ids[:hostgroup_ids], :label => _('Select host groups')},
{'data-mismatches' => taxonomy.need_to_be_selected_ids[:hostgroup_ids].to_json} %>
</div>
<% if taxonomy.is_a?(Location) && SETTINGS[:locations_enabled] %>
<div class="tab-pane" id="organizations">
<%= organization_selects f, taxonomy.selected_ids[:organization_ids],
{ :disabled => taxonomy.used_and_selected_ids[:organization_ids], :label => '' },
{ :disabled => taxonomy.used_and_selected_ids[:organization_ids], :label => _('Select organizations')},
{ 'data-mismatches' => taxonomy.need_to_be_selected_ids[:organization_ids].to_json } %>
</div>
<% elsif taxonomy.is_a?(Organization) && SETTINGS[:organizations_enabled] %>
<div class="tab-pane" id="locations">
<%= location_selects f, taxonomy.selected_ids[:location_ids],
{ :disabled => taxonomy.used_and_selected_ids[:location_ids], :label => '' },
{ :disabled => taxonomy.used_and_selected_ids[:location_ids], :label => _('Select locations')},
{ 'data-mismatches' => taxonomy.need_to_be_selected_ids[:location_ids].to_json } %>
</div>
<% end %>
<div class="tab-pane" id="params">
<%= render "common_parameters/parameters", { :f => f, :type => :parameters } %>
</div>
<%= submit_or_cancel f %>
</div>
</div>
<% end %>
config/routes/api/v2.rb
resources :media, :only => [:index, :show]
resources :smart_proxies, :only => [:index, :show]
# scoped by location AND organization
resources :parameters, :except => [:new, :edit] do
collection do
delete '/', :to => :reset
end
end
# scoped by location AND organization
resources :organizations, :except => [:new, :edit] do
resources :domains, :only => [:index, :show]
resources :subnets, :only => [:index, :show]
......
resources :media, :only => [:index, :show]
resources :smart_proxies, :only => [:index, :show]
resources :parameters, :except => [:new, :edit] do
collection do
delete '/', :to => :reset
end
end
# scoped by location AND organization
resources :locations, :except => [:new, :edit] do
resources :domains, :only => [:index, :show]
test/fixtures/parameters.yml
type: OsParameter
operatingsystem: redhat
location:
name: location
value: value
type: LocationParameter
location: location1
org:
name: org
value: value
type: OrganizationParameter
organization: organization1
test/unit/location_parameter_test.rb
require 'test_helper'
class LocationParameterTest < ActiveSupport::TestCase
setup do
User.current = User.admin
end
test 'should have a reference_id' do
location_parameter = LocationParameter.new
location_parameter.name = 'valid'
location_parameter.value = 'valid'
assert_not location_parameter.save
location = Location.first
location_parameter.reference_id = location.id
assert location_parameter.save
end
test 'duplicate names cannot exist for a location' do
location = taxonomies(:location1)
parameter1 = LocationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => location.id
parameter2 = LocationParameter.create :name => 'some_parameter', :value => 'value', :reference_id => location.id
assert_not parameter2.valid?
assert_equal ['has already been taken'], parameter2.errors[:name]
end
test 'duplicate names can exist for different taxonomies' do
location1 = taxonomies(:location1)
location2 = taxonomies(:location2)
assert LocationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => location1.id
assert LocationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => location2.id
end
end
test/unit/organization_parameter_test.rb
require 'test_helper'
class OrganizationParameterTest < ActiveSupport::TestCase
setup do
User.current = User.admin
end
test 'should have a reference_id' do
organization_parameter = OrganizationParameter.new
organization_parameter.name = 'valid'
organization_parameter.value = 'valid'
assert_not organization_parameter.save
organization = Organization.first
organization_parameter.reference_id = organization.id
assert organization_parameter.save
end
test 'duplicate names cannot exist for a organization' do
organization = taxonomies(:organization1)
parameter1 = OrganizationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => organization.id
parameter2 = OrganizationParameter.create :name => 'some_parameter', :value => 'value', :reference_id => organization.id
assert_not parameter2.valid?
assert_equal ['has already been taken'], parameter2.errors[:name]
end
test 'duplicate names can exist for different taxonomies' do
organization1 = taxonomies(:organization1)
organization2 = taxonomies(:organization2)
assert OrganizationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => organization1.id
assert OrganizationParameter.create! :name => 'some_parameter', :value => 'value', :reference_id => organization2.id
end
end

Also available in: Unified diff