Project

General

Profile

« Previous | Next » 

Revision 4d4b84f6

Added by Ohad Levy almost 13 years ago

  • ID 4d4b84f6b722874504f508fa92802f6ddee37c11

fixes #35 - Allow hostgroup nesting for puppet classes and parameters

View differences:

.gitmodules
[submodule "vendor/plugins/scoped_search"]
path = vendor/plugins/scoped_search
url = git://github.com/wvanbergen/scoped_search.git
[submodule "vendor/plugins/ancestry"]
path = vendor/plugins/ancestry
url = git://github.com/stefankroes/ancestry.git
app/controllers/hostgroups_controller.rb
def index
begin
values = Hostgroup.search_for(params[:search],:order => params[:order])
flash.clear
rescue => e
error e.to_s
values = Hostgroup.search_for ""
......
@hostgroup = Hostgroup.new
end
def nest
@hostgroup = Hostgroup.new(:parent_id => params[:id])
render :action => :new
end
# Clone the hostgroup
def clone
new = @hostgroup.clone
app/helpers/hostgroups_helper.rb
module HostgroupsHelper
include CommonParametersHelper
include HostsAndHostgroupsHelper
def warning_message group
msg = ["Are you sure?"]
if group.has_children?
msg << "This group has nested groups!\n"
msg << "Deleting this group will unlink its nested groups and any associated puppet classes and / or parameters"
end
msg.join("\n")
end
end
app/helpers/hosts_and_hostgroups_helper.rb
end
end
def hostgroup_name group
return if group.blank?
content_tag(:span, group.to_s.gsub(group.name, ""), :class => "grey") +
link_to_if_authorized(h(group.name), hash_for_edit_hostgroup_path(:id => group))
end
def accessible_hostgroups
hg = (User.current.hostgroups.any? and !User.current.admin?) ? User.current.hostgroups : Hostgroup.all
hg.sort
end
def image_file_entry item
# If the host has an explicit image_path then use that
# Else use the default based upon the host's medium and operatingsystem
app/helpers/hosts_helper.rb
(User.current.domains.any? and !User.current.admin?) ? User.current.domains : Domain.all
end
def accessible_hostgroups
(User.current.hostgroups.any? and !User.current.admin?) ? User.current.hostgroups : Hostgroup.all
end
def update_details_from_hostgroup
return nil unless @host.new_record?
remote_function(:url => { :action => "process_hostgroup" },
app/models/host.rb
end
def all_puppetclasses
return hostgroup.nil? ? puppetclasses : (hostgroup.puppetclasses + puppetclasses).uniq
return hostgroup.nil? ? puppetclasses : (hostgroup.classes + puppetclasses).uniq
end
# provide information about each node, mainly used for puppet external nodes
......
# read OS parameters
operatingsystem.os_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless operatingsystem.nil?
# read group parameters only if a host belongs to a group
hostgroup.group_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless hostgroup.nil?
parameters.update hostgroup.parameters unless hostgroup.nil?
# and now read host parameters, override if required
host_parameters.each {|p| parameters.update Hash[p.name => p.value] }
return parameters
app/models/hostgroup.rb
class Hostgroup < ActiveRecord::Base
has_ancestry :orphan_strategy => :rootify
include Authorization
include HostCommon
has_and_belongs_to_many :puppetclasses
has_and_belongs_to_many :users, :join_table => "user_hostgroups"
validates_uniqueness_of :name
validates_uniqueness_of :name, :scope => :ancestry
validates_format_of :name, :with => /\A(\S+\s?)+\Z/, :message => "can't be blank or contain trailing white spaces."
has_many :group_parameters, :dependent => :destroy, :foreign_key => :reference_id
accepts_nested_attributes_for :group_parameters, :reject_if => lambda { |a| a[:value].blank? }, :allow_destroy => true
......
#TODO: add a method that returns the valid os for a hostgroup
def all_puppetclasses
puppetclasses
classes
end
alias_method :to_label, :to_s
def to_label
"/" + ancestors.map{|a| a.name + "/"}.join + name
end
def as_json(options={})
super({:only => [:name, :id, :value], :include => [:puppetclasses, :group_parameters, :environment]}.merge(options))
super({:only => [:name, :id], :methods => [:classes, :parameters], :include => [:puppetclasses, :group_parameters, :environment]}.merge(options))
end
def hostgroup
......
ptable.layout
end
def classes
klasses = []
ids = ancestor_ids
ids << id unless new_record? or self.frozen?
Hostgroup.sort_by_ancestry(Hostgroup.find(ids, :include => :puppetclasses)).each do |hg|
klasses << hg.puppetclasses
end
klasses.flatten
end
# returns self and parent parameters as a hash
def parameters
hash = {}
ids = ancestor_ids
ids << id unless new_record? or self.frozen?
Hostgroup.sort_by_ancestry(Hostgroup.find(ids, :include => :group_parameters)).each do |hg|
hg.group_parameters.each {|p| hash[p.name] = p.value }
end
hash
end
def params
parameters = {}
# read common parameters
......
# read OS parameters
operatingsystem.os_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless operatingsystem.nil?
# read group parameters only if a host belongs to a group
hostgroup.group_parameters.each {|p| parameters.update Hash[p.name => p.value] } unless hostgroup.nil?
parameters.update self.parameters unless hostgroup.nil?
parameters
end
app/views/hostgroups/_form.html.erb
<% form_for @hostgroup do |f| %>
<%= f.error_messages %>
<p>
<%= f.label :parent_id, "Parent", :class => "span-3" %>
<%= f.collection_select(:parent_id, accessible_hostgroups, :id, :to_label, { :include_blank => true },
{ :class => "span-3" }) %>
<%= f.label :name, nil, :class => "span-3" %>
<%= f.text_field :name, :class => "last" %>
<%= f.text_field :name, :class => "span-3" %>
</p>
<br>
<% field_set_tag 'Host Defaults' do -%>
<% field_set_tag 'Primary Settings' do %>
app/views/hostgroups/index.html.erb
<th>Name</th>
<th></th>
</tr>
<% for hostgroup in @hostgroups %>
<% Hostgroup.sort_by_ancestry(@hostgroups).each do |hostgroup| %>
<tr class="<%= cycle("even", "odd") -%>">
<td><%=link_to_if_authorized h(hostgroup.name), hash_for_edit_hostgroup_path(:id => hostgroup) %></td>
<td> <%= hostgroup_name hostgroup %> </td>
<td class="ra">
<%= display_link_if_authorized 'Nest', hash_for_nest_hostgroup_path(:id => hostgroup) %>
<%= display_link_if_authorized 'Clone', hash_for_clone_hostgroup_path(:id => hostgroup) %>
<%= display_link_if_authorized "Destroy", hash_for_hostgroup_path(:id => hostgroup, :auth_action => :destroy), :confirm => 'Are you sure?', :method => :delete %>
<%= display_link_if_authorized "Destroy", hash_for_hostgroup_path(:id => hostgroup, :auth_action => :destroy), :confirm => warning_message(hostgroup), :method => :delete %>
</td>
</tr>
<% end %>
app/views/hosts/_form.html.erb
<%= f.label :name %>
<%= f.text_field :name, :value => @host.shortname, :title => @host.to_s, :size => 12 %>
</div>
<div class="span-6">
<div class="span-3">
<%= f.label :hostgroup_id, "Host group" %>
<%= image_tag "spinner.gif", :id => "indicator1", :style => "display:none;" %>
<%= f.collection_select(:hostgroup_id, accessible_hostgroups, :id, :name, { :include_blank => true },
{ :onchange => update_details_from_hostgroup }) %>
</div>
<%= f.collection_select(:hostgroup_id, accessible_hostgroups, :id, :to_label, { :include_blank => true },
{ :onchange => update_details_from_hostgroup, :class => "span-3" }) %>
<div class="span-6">
<%= f.label :environment_id %>
<%= f.collection_select :environment_id, Environment.all, :id, :to_label, { :include_blank => true } %>
app/views/hosts/_list.html.erb
<td><%= icon(host.os, :size => "18x18", :title => host.os.to_s) + " " + host.os.to_s if host.os %></td>
<td><%= h host.try(:environment) %></td>
<td><%= h host.try(:model) %></td>
<td><%= h host.try(:hostgroup) %></td>
<td><%= hostgroup_name host.hostgroup %></td>
<td><%= last_report_column(host) %></td>
<td>
<%= display_link_if_authorized 'Edit', hash_for_edit_host_path(:id => host) %>
app/views/puppetclasses/_class_selection.html.erb
:collection => obj.puppetclasses ,:as => :klass,
:locals => { :type => obj.class.to_s.downcase } %>
</div>
<% if (klasses = obj.hostgroup.try(:puppetclasses)).is_a?(Array) and obj.is_a?(Host) -%>
<% if (klasses = obj.hostgroup.try(:classes)).is_a?(Array) and obj.is_a?(Host) -%>
<% for klass in klasses -%>
<li title="included already from host group"><%= h klass.name %></li>
<% end -%>
config/routes.rb
map.resources :puppetclasses, :member => { :assign => :post }, :collection => {:import_environments => :get, :auto_complete_search => :get} do |pc|
pc.resources :hosts, :requirements => {:id => /[^\/]+/}
end
map.resources :hostgroups, :member => { :clone => :get }, :collection => { :auto_complete_search => :get }
map.resources :hostgroups, :member => { :nest => :get, :clone => :get }, :collection => { :auto_complete_search => :get }
map.resources :common_parameters
map.resources :environments, :collection => {:import_environments => :get, :obsolete_and_new => :post}
map.resources :fact_values, :only => [:create, :index], :collection => { :auto_complete_search => :get }
db/migrate/20110619130336_add_ancestry_to_hostgroup.rb
class AddAncestryToHostgroup < ActiveRecord::Migration
def self.up
add_column :hostgroups, :ancestry, :string
add_index :hostgroups, :ancestry
end
def self.down
remove_index :hostgroups, :ancestry
remove_column :hostgroups, :ancestry
end
end
public/stylesheets/style.css
height: 25px;
}
.menu-dropdown {text-transform: capitalize;}
.grey {
color:#aaa;
}
test/functional/hostgroups_controller_test.rb
assert_template 'new'
end
def test_nest
get :nest, {:id => Hostgroup.first.id}, set_session_user
assert_template 'new'
end
def test_create_invalid
Hostgroup.any_instance.stubs(:valid?).returns(false)
post :create, {}, set_session_user
......
end
def test_destroy
hostgroup = Hostgroup.first
delete :destroy, {:id => hostgroup}, set_session_user
hostgroup = hostgroups(:unusual)
delete :destroy, {:id => hostgroup.id}, set_session_user
assert_redirected_to hostgroups_url
assert !Hostgroup.exists?(hostgroup.id)
end
def test_destroy_json
hostgroup = Hostgroup.first
delete :destroy, {:format => "json", :id => hostgroup}, set_session_user
hostgroup = hostgroups(:common)
delete :destroy, {:format => "json", :id => hostgroup.id}, set_session_user
template = ActiveSupport::JSON.decode(@response.body)
assert_response :ok
assert !Hostgroup.exists?(hostgroup.id)
test/unit/hostgroup_test.rb
assert record.valid?
end
test "should be able to nest a group parameters" do
# creates a 3 level hirecy, each one with his own parameters
# and overrides.
pid = Time.now.to_i
assert (top = Hostgroup.create(:name => "topA", :group_parameters_attributes => {
pid += 1=>{"name"=>"topA", "value"=>"1", :nested => ""},
pid += 1=>{"name"=>"topB", "value"=>"1", :nested => ""},
pid += 1=>{"name"=>"topC", "value"=>"1", :nested => ""},
}))
assert (second = Hostgroup.create(:name => "SecondA", :parent_id => top.id, :group_parameters_attributes => {
pid += 1 =>{"name"=>"topA", "value"=>"2", :nested => ""},
pid += 1 =>{"name"=>"secondA", "value"=>"2", :nested => ""}}))
assert second.parameters.include? "topA"
assert_equal "2", second.parameters["topA"]
assert second.parameters.include? "topB"
assert_equal "1", second.parameters["topB"]
assert second.parameters.include? "topC"
assert_equal "1", second.parameters["topC"]
assert second.parameters.include? "secondA"
assert_equal "2", second.parameters["secondA"]
assert (third = Hostgroup.create(:name => "ThirdA", :parent_id => second.id, :group_parameters_attributes => {
pid += 1 =>{"name"=>"topB", "value"=>"3", :nested => ""},
pid += 1 =>{"name"=>"topA", "value"=>"3", :nested => ""}}))
assert third.parameters.include? "topA"
assert_equal "3", third.parameters["topA"]
assert third.parameters.include? "topB"
assert_equal "3", third.parameters["topB"]
assert third.parameters.include? "topC"
assert_equal "1", third.parameters["topC"]
assert third.parameters.include? "secondA"
assert_equal "2", third.parameters["secondA"]
end
test "should inheirt parent classes" do
assert (top = Hostgroup.create(:name => "topA", "puppetclass_ids"=>[Puppetclass.first.id]))
assert (second = Hostgroup.create(:name => "secondB", :parent_id => top.id, "puppetclass_ids"=>[Puppetclass.last.id]))
assert_equal [Puppetclass.first, Puppetclass.last].sort, second.classes.sort
end
test "should remove relationships if deleting a parent hostgroup" do
assert (top = Hostgroup.create(:name => "topA"))
assert (second = Hostgroup.create(:name => "secondB", :parent_id => top.id))
assert top.has_children?
assert !second.is_root?
assert top.destroy
assert Hostgroup.find(second.id).is_root?
end
end
vendor/plugins/ancestry
Subproject commit 770f2e36eb8b9865ee0ea1f81f5ca21068bebe3e

Also available in: Unified diff