Feature #170 » 170.patch
app/controllers/hosts_controller.rb | ||
---|---|---|
# Clone any parameters as well
|
||
@original.host_parameters.each{|param| @host.host_parameters << param.clone}
|
||
flash[:error_customisation] = {:header_message => nil, :class => "flash notice", :id => nil,
|
||
:message => "The following fields will need modification:" }
|
||
:message => "The following fields will need reviewing:" }
|
||
@host.valid?
|
||
render :action => :new
|
||
end
|
app/controllers/usergroups_controller.rb | ||
---|---|---|
def index
|
||
@usergroups = Usergroup.all
|
||
end
|
||
|
||
def new
|
||
@usergroup = Usergroup.new
|
||
end
|
||
|
||
def create
|
||
@usergroup = Usergroup.new(params[:usergroup])
|
||
if @usergroup.save
|
||
... | ... | |
render :action => 'new'
|
||
end
|
||
end
|
||
|
||
def edit
|
||
@usergroup = Usergroup.find(params[:id])
|
||
|
||
render :action => :edit
|
||
end
|
||
|
||
def update
|
||
@usergroup = Usergroup.find(params[:id])
|
||
@usergroup.user_ids = params[:usergroup][:user_ids] || []
|
||
@usergroup.usergroup_ids = params[:usergroup][:usergroup_ids] || []
|
||
if @usergroup.valid?
|
||
if @usergroup.update_attributes(params[:usergroup])
|
||
flash[:foreman_notice] = "Successfully updated usergroup."
|
||
redirect_to usergroups_path
|
||
else
|
||
render :action => 'edit'
|
||
end
|
||
end
|
||
|
||
def destroy
|
||
@usergroup = Usergroup.find(params[:id])
|
||
if u = @usergroup.destroy
|
||
if @usergroup.destroy
|
||
flash[:foreman_notice] = "Successfully destroyed usergroup."
|
||
else
|
||
logger.error u.errors.full_messages
|
||
flash[:foreman_error] = u.errors.full_messages.join "<br>"
|
||
logger.error @usergrup.errors.full_messages
|
||
flash[:foreman_error] = @usergroup.errors.full_messages.join "<br>"
|
||
end
|
||
redirect_to usergroups_path
|
||
end
|
app/helpers/hosts_helper.rb | ||
---|---|---|
link_to_if(Report.maximum('id', :conditions => {:host_id => record.id}), time, report_host_path(record))
|
||
end
|
||
def root_pass_form_column(record, field_name)
|
||
password_field_tag field_name, record.root_pass
|
||
end
|
||
def is_owned_by_form_column(record, options)
|
||
owner = record.owner || @user || User.first
|
||
grouped_options = {"Users" => User.all.map(&:select_title).sort,
|
||
"User Groups" => Usergroup.all.map(&:select_title).sort
|
||
}
|
||
select "record", "is_owned_by", grouped_options_for_select(grouped_options, owner.select_title)
|
||
def grouped_options
|
||
{ "Users" => User.all.map(&:select_title).sort,
|
||
"User Groups" => Usergroup.all.map(&:select_title).sort }
|
||
end
|
||
# method that reformats the hostname column by adding the status icons
|
app/models/auth_source_ldap.rb | ||
---|---|---|
attrs = []
|
||
# get user's DN
|
||
if not account.nil? and self.account.include? "$login" then
|
||
logger.debug "LDAP-Auth with User login"
|
||
ldap_con = initialize_ldap_con(self.account.sub("$login", login), password)
|
||
logger.debug "LDAP-Auth with User login"
|
||
ldap_con = initialize_ldap_con(self.account.sub("$login", login), password)
|
||
else
|
||
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
||
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
||
end
|
||
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
|
||
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
|
||
dn = String.new
|
||
ldap_con.search( :base => self.base_dn,
|
||
:filter => object_filter & login_filter,
|
||
# only ask for the DN if on-the-fly registration is disabled
|
||
:attributes=> (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) do |entry|
|
||
:filter => object_filter & login_filter,
|
||
# only ask for the DN if on-the-fly registration is disabled
|
||
:attributes=> (onthefly_register? ? ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] : ['dn'])) do |entry|
|
||
dn = entry.dn
|
||
attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
|
||
:lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
|
||
:mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
|
||
:auth_source_id => self.id ] if onthefly_register?
|
||
end
|
||
:lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
|
||
:mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
|
||
:auth_source_id => self.id ] if onthefly_register?
|
||
end
|
||
return nil if dn.empty?
|
||
logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
|
||
# authenticate user
|
||
... | ... | |
def initialize_ldap_con(ldap_user, ldap_password)
|
||
options = { :host => self.host,
|
||
:port => self.port,
|
||
:encryption => (self.tls ? :simple_tls : nil)
|
||
}
|
||
:port => self.port,
|
||
:encryption => (self.tls ? :simple_tls : nil)
|
||
}
|
||
options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank?
|
||
Net::LDAP.new options
|
||
end
|
app/models/domain_parameter.rb | ||
---|---|---|
class DomainParameter < Parameter
|
||
belongs_to :domain
|
||
validates_presence_of :domain_id, :message => "parameters require an associated domain", :unless => :nested
|
||
validates_uniqueness_of :name
|
||
validates_uniqueness_of :name, :scope => :domain_id
|
||
end
|
app/models/group_parameter.rb | ||
---|---|---|
class GroupParameter < Parameter
|
||
belongs_to :hostgroup
|
||
validates_presence_of :hostgroup_id
|
||
validates_presence_of :hostgroup_id, :unless => :nested
|
||
validates_uniqueness_of :name, :scope => :hostgroup_id
|
||
end
|
app/models/host.rb | ||
---|---|---|
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("skipped")} & #{Report::MAX}) != 0)"
|
||
}
|
||
named_scope :with_changes, { :conditions => "(puppet_status > 0) and
|
||
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("applied")} & #{Report::MAX}) != 0) or
|
||
((puppet_status >> #{Report::BIT_NUM*Report::METRIC.index("restarted")} & #{Report::MAX}) !=0)"
|
||
... | ... | |
validates_length_of :root_pass, :minimum => 8,:too_short => 'should be 8 characters or more'
|
||
validates_format_of :mac, :with => /([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/
|
||
validates_format_of :ip, :with => /(\d{1,3}\.){3}\d{1,3}/
|
||
validates_presence_of :ptable, :message => "Cant be blank unless a custom partition has been defined",
|
||
validates_presence_of :ptable, :message => "cant be blank unless a custom partition has been defined",
|
||
:if => Proc.new { |host| host.disk.empty? and not defined?(Rake) }
|
||
validates_format_of :sp_mac, :with => /([a-f0-9]{1,2}:){5}[a-f0-9]{1,2}/, :allow_nil => true, :allow_blank => true
|
||
validates_format_of :sp_ip, :with => /(\d{1,3}\.){3}\d{1,3}/, :allow_nil => true, :allow_blank => true
|
||
... | ... | |
def <=>(other)
|
||
self.name <=> other.name
|
||
end
|
||
|
||
# Returns the name of this host as a string
|
||
# String: the host's name
|
||
def to_label
|
||
... | ... | |
end
|
||
def is_owned_by
|
||
|
||
end
|
||
def is_owned_by=(the_owner)
|
||
... | ... | |
if match = the_owner.match(/^[^\(]+\(([^\)]+)\)/)
|
||
owner = User.find_by_login(match[1])
|
||
else
|
||
owner = Usergroup.find_by_name(the_owner)
|
||
owner = Usergroup.find_by_name(the_owner)
|
||
end
|
||
if owner
|
||
update_attribute :owner, owner
|
||
update_attribute :owner, owner
|
||
else
|
||
errors.add_to_base "Unable to set the owner of this host to #{the_owner}"
|
||
end
|
app/models/host_mailer.rb | ||
---|---|---|
def error_state(report)
|
||
host = report.host
|
||
if SETTINGS[:ldap]
|
||
email = host.owner.recipients
|
||
else
|
||
email = SETTINGS[:administrator]
|
||
end
|
||
email = SETTINGS[:ldap] ? host.owner.recipients : SETTINGS[:administrator]
|
||
raise "unable to find recipients" if email.empty?
|
||
recipients email
|
||
from "Foreman-noreply"
|
app/models/host_parameter.rb | ||
---|---|---|
class HostParameter < Parameter
|
||
belongs_to :host
|
||
validates_presence_of :host_id, :message => "parameters require an associated host", :unless => :nested
|
||
validates_uniqueness_of :name, :scope => :host_id
|
||
def to_s
|
||
"#{host_id ? host.name : "unassociated"}: #{name} = #{value}"
|
app/models/user.rb | ||
---|---|---|
belongs_to :auth_source
|
||
has_many :changes, :class_name => 'Audit', :as => :user
|
||
has_many :usergroups, :through => :usergroup_member
|
||
|
||
has_many :direct_hosts, :as => :owner, :class_name => "Host"
|
||
validates_uniqueness_of :login, :message => "already exists"
|
||
... | ... | |
end
|
||
alias_method :to_s, :to_label
|
||
alias_method :name, :to_label
|
||
|
||
def <=>(other)
|
||
self.name <=> other.name
|
||
end
|
||
|
||
# The text item to see in a select dropdown menu
|
||
def select_title
|
||
name + " (#{login})"
|
||
end
|
||
|
||
def self.try_to_login(login, password)
|
||
# Make sure no one can sign in with an empty password
|
||
return nil if password.to_s.empty?
|
||
... | ... | |
end
|
||
all_groups.uniq.map{|g| g.hosts}.flatten.uniq
|
||
end
|
||
|
||
def hosts
|
||
direct_hosts + indirect_hosts
|
||
end
|
||
|
||
def recipients
|
||
[mail]
|
||
end
|
||
|
||
protected
|
||
|
||
def validate
|
||
if Usergroup.all.map(&:name).include?(self.login)
|
||
errors.add_to_base "A usergroup already exists with this name"
|
app/models/usergroup.rb | ||
---|---|---|
class Usergroup < ActiveRecord::Base
|
||
has_many_polymorphs :members, :from => [:usergroups, :users ], :as => :member, :through => :usergroup_member, :foreign_key => :usergroup_id, :dependent => :destroy
|
||
has_many :hosts, :as => :owner
|
||
|
||
validates_uniqueness_of :name
|
||
|
||
before_destroy Ensure_not_used_by.new(:hosts, :usergroups)
|
||
|
||
def to_s
|
||
name
|
||
end
|
||
|
||
# The text item to see in a select dropdown menu
|
||
alias_method :select_title, :to_s
|
||
... | ... | |
def recipients
|
||
all_users.map(&:mail)
|
||
end
|
||
|
||
# This methods retrieves all users in a usergroup
|
||
# Returns: Array of users
|
||
def all_users(group_list=[self], user_list=[])
|
||
retrieve_users_and_groups group_list, user_list
|
||
user_list.sort.uniq
|
||
end
|
||
|
||
# This methods retrieves all usergroups in a usergroup
|
||
# Returns: Array of usergroups
|
||
def all_usergroups(group_list=[self], user_list=[])
|
||
... | ... | |
# Recurses down the tree of usergroups and finds the users
|
||
# [+group_list+]: Array of Usergroups that have already been processed
|
||
# [+users+] : Array of users accumulated at this point
|
||
# Returns : Array of non unique users
|
||
# Returns : Array of non unique users
|
||
def retrieve_users_and_groups(group_list, user_list)
|
||
for group in usergroups
|
||
next if group_list.include? group
|
||
group_list << group
|
||
|
||
group.retrieve_users_and_groups(group_list, user_list)
|
||
group.retrieve_users_and_groups(group_list, user_list)
|
||
end
|
||
user_list.concat users
|
||
end
|
||
... | ... | |
errors.add :name, "is already used by a user account"
|
||
end
|
||
end
|
||
|
||
end
|
app/views/hosts/_architecture.html.erb | ||
---|---|---|
<%= label :host, :operatingsystem, "Operating system" %>
|
||
Operating system
|
||
<%= collection_select :host, :operatingsystem_id, @architecture.operatingsystems, :id, :to_label, :include_blank => true %>
|
||
<span id=os_sub_select>
|
||
<% if @operatingsystem -%>
|
app/views/hosts/_form.html.erb | ||
---|---|---|
<% field_set_tag 'Primary settings' do -%>
|
||
<table>
|
||
<tr>
|
||
<td><%= f.label :name %></td>
|
||
<td>Name</td>
|
||
<td><%= f.text_field :name, :size => 16, :value => @host.shortname %></td>
|
||
<td><%= f.label :hostgroup, "Host group" %></td>
|
||
<td>Host group</td>
|
||
<td><%= f.collection_select :hostgroup_id, Hostgroup.all, :id, :name, :include_blank => true %></td>
|
||
<td><%= f.label :environment %></td>
|
||
<td>Environment</td>
|
||
<td><%= f.collection_select :environment_id, Environment.all, :id, :to_label, :include_blank => true %></td>
|
||
<td><%= f.label :puppetmaster %></td>
|
||
<td>Puppetmaster</td>
|
||
<td><%= f.text_field :puppetmaster, :size => 10, :value => @host.puppetmaster %></td>
|
||
<td><%= link_to_function "Additional Classes", toggle_div(:classlist) %></td>
|
||
</tr>
|
||
... | ... | |
<%= render 'unattended', :f => f %>
|
||
<% end -%>
|
||
<% if SETTINGS[:ldap] -%>
|
||
<%= f.select :owner, grouped_options_for_select(grouped_options) %>
|
||
<% end -%>
|
||
<% field_set_tag 'Additional Information' do -%>
|
||
<%= f.text_area :comment, :size => "120x5" %>
|
||
<% end -%>
|
app/views/hosts/_operatingsystem.html.erb | ||
---|---|---|
<%= label :host, :media %>
|
||
Media
|
||
<%= collection_select :host, :media_id, @operatingsystem.medias, :id, :to_label %>
|
||
<%= label :host, :ptable, "Partition Table" %>
|
||
Partition Table
|
||
<%= collection_select :host, :ptable_id, @operatingsystem.ptables, :id, :to_label %>
|
app/views/hosts/_unattended.html.erb | ||
---|---|---|
<% field_set_tag 'Network settings', :id => "network" do -%>
|
||
<table>
|
||
<tr>
|
||
<td><%= f.label :domain %></td>
|
||
<td>Domain</td>
|
||
<td><%= f.collection_select :domain_id, Domain.all, :id, :to_label %></td>
|
||
<td><%= f.label :ip %></td>
|
||
<td>IP</td>
|
||
<td><%= f.text_field :ip, :size => 16 %></td>
|
||
<td><%= f.label :mac, "MAC" %></td>
|
||
<td>MAC</td>
|
||
<td><%= f.text_field :mac, :size => 17 %></td>
|
||
</tr>
|
||
</table>
|
||
... | ... | |
<tr>
|
||
<td colspan="6">
|
||
<span id="architecture">
|
||
<%= f.label :architecture %>
|
||
Architecture
|
||
<%= f.collection_select :architecture_id, Architecture.all, :id, :to_label, :include_blank => true %>
|
||
<span id="host_os">
|
||
<% if @architecture -%>
|
||
... | ... | |
</td>
|
||
</tr>
|
||
<tr>
|
||
<td><%= f.label :root_pass, "Root password" %></td>
|
||
<td>Root password</td>
|
||
<td><%= f.password_field :root_pass %></td>
|
||
<td><%= f.label :model %></td>
|
||
<td>Model</td>
|
||
<td><%= f.collection_select :model_id, Model.all, :id, :to_label, :include_blank => true %></td>
|
||
<td><%= f.label :serial %></td>
|
||
<td>Serial</td>
|
||
<td><%= f.select :serial, ["","0,9600n8","0,19200n8","1,9600n8","1,19200n8"] %></td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="6">
|
||
<%= link_to_function "Switch to custom disk layout", toggle_div("custom_disk") %>
|
||
<div id="custom_disk", style=display:none;>
|
||
<%= f.label :disk, "Custom Disk layout" %>
|
||
Custom Disk layout
|
||
<%= f.text_area :disk, :size => "50x10", :disabled => true %>
|
||
</div>
|
||
</td>
|
app/views/usergroups/_form.html.erb | ||
---|---|---|
<tr>
|
||
<td>
|
||
Name
|
||
</td>
|
||
<td>
|
||
</td>
|
||
<td>
|
||
<%= f.text_field :name %>
|
||
</td>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
User groups
|
||
</td><td>
|
||
User groups
|
||
</td><td>
|
||
<%= edit_habtm @usergroup, Usergroup, @usergroup %>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
Users
|
||
</td><td>
|
||
<%= edit_habtm @usergroup, User %>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td>
|
||
Users
|
||
</td><td>
|
||
<%= edit_habtm @usergroup, User %>
|
||
</td>
|
||
</tr>
|
||
<tr><td><%= f.submit "Submit" %></td></tr>
|
||
</table>
|
||
<% end %>
|
config/initializers/foreman.rb | ||
---|---|---|
end
|
||
end
|
||
end
|
||
module ActionView::Helpers::ActiveRecordHelper
|
||
def error_messages_for_with_customisation(*params)
|
||
if flash[:error_customisation]
|
||
if params[-1].is_a? Hash
|
||
params[-1].update flash[:error_customisation]
|
||
else
|
||
params << flash[:error_customisation]
|
||
end
|
||
end
|
||
error_messages_for_without_customisation(*params)
|
||
end
|
||
alias_method_chain :error_messages_for, :customisation
|
||
end
|
config/settings.yaml | ||
---|---|---|
#:modulepath: /etc/puppet/modules/
|
||
:tftppath: tftp/
|
||
#:rrd_report_url: report/
|
||
#:ldap: true
|
||
:ldap: true
|
||
#your default puppet server - can be overridden in the host level
|
||
#if none specified, plain "puppet" will be used.
|
||
#:puppet_server: puppet
|
||
#:unattended: false
|
||
#use the following setting to override the default 30 minutes puppet run interval - value must be in minutes
|
||
#:puppet_interval: 60
|
||
#:puppet_interval: 60
|
lib/family.rb | ||
---|---|---|
def mediapath host
|
||
uri = media_uri(host)
|
||
server = uri.select(:host, :port).compact.join(':')
|
||
dir = uri.select(:path, :query).compact.join('?')
|
||
dir = uri.select(:path, :query).compact.join('?') unless uri.scheme == 'ftp'
|
||
case uri.scheme
|
||
when 'http', 'https', 'ftp'
|
||
... | ... | |
epel_url.gsub!("$os","4-9")
|
||
when "5"
|
||
epel_url.gsub!("$os","5-3")
|
||
when "6"
|
||
epel_url.gsub!("$os","6-1").
|
||
gsub!("/pub/epel/","/pub/epel/beta/") # workaround for hardcoded beta in url, should be remove once RH6 is released
|
||
else
|
||
return ""
|
||
end
|
||
return "su -c 'rpm -Uvh #{media_uri(host, epel_url)}"
|
||
return "su -c 'rpm -Uvh #{media_uri(host, epel_url)}'"
|
||
end
|
||
def yumrepo host
|
test/fixtures/parameters.yml | ||
---|---|---|
name: test
|
||
value: myvalue
|
||
type: CommonParameter
|
||
#
|
||
# two:
|
||
# column: value
|
||
two:
|
||
name: parameter
|
||
value: value1
|
||
test/unit/domain_parameter_test.rb | ||
---|---|---|
parameter.domain_id = domain.id
|
||
assert parameter.save
|
||
end
|
||
test "should have a unique parameter name" do
|
||
p1 = DomainParameter.new(:name => "parameter", :value => "value1", :domain_id => Domain.first)
|
||
assert p1.save
|
||
p2 = DomainParameter.new(:name => "parameter", :value => "value2", :domain_id => Domain.first)
|
||
assert !p2.save
|
||
end
|
||
end
|
||
test/unit/parameter_test.rb | ||
---|---|---|
parameter.value.strip!.squeeze!(" ").empty?
|
||
assert parameter.save
|
||
end
|
||
test "name must not be unique accross different parameter groups" do
|
||
p1 = HostParameter.new :name => "param", :value => "value1", :host_id => Host.first
|
||
assert p1.save
|
||
p2 = DomainParameter.new :name => "param", :value => "value2", :domain_id => Domain.first
|
||
assert p2.save
|
||
p3 = CommonParameter.new :name => "param", :value => "value3"
|
||
assert p3.save
|
||
p4 = GroupParameter.new :name => "param", :value => "value4", :hostgroup_id => Hostgroup.first
|
||
assert p4.save
|
||
end
|
||
end
|