Project

General

Profile

« Previous | Next » 

Revision c6e02bd3

Added by Joseph Magen over 10 years ago

fixes #3178 - add feature for compute profiles for hostgroups and hosts

View differences:

app/assets/javascripts/compute_resource.js
});
}
function ovirt_hwpSelected(item){
var hwp = $(item).val();
function ovirt_templateSelected(item){
var template = $(item).val();
var url = $(item).attr('data-url');
$(item).indicator_show();
$.ajax({
type:'post',
url: url,
data:'hwp_id=' + hwp,
data:'template_id=' + template,
success: function(result){
$('[id$=_memory]').val(result.memory);
$('[id$=_cores]').val(result.cores);
......
}
sg_select.multiSelect("refresh");
}
function capacity_edit(element) {
var buttons = $(element).closest('.fields').find('button[name=allocation_radio_btn].btn.active');
if (buttons.size() > 0 && $(buttons[0]).text() == 'Full') {
var allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
allocation.value = element.value;
}
return false;
}
function allocation_switcher(element, action) {
var allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
if (action == 'None') {
$(allocation).attr('readonly', 'readonly');
allocation.value = '0G';
} else if (action == 'Size') {
$(allocation).removeAttr('readonly');
allocation.value = '';
$(allocation).focus();
} else if (action == 'Full') {
$(allocation).attr('readonly', 'readonly');
var capacity = $(element).closest('.fields').find('[id$=capacity]')[0];
allocation.value = capacity.value;
}
return false;
}
app/assets/javascripts/host_edit.js
$('#compute_resource').empty();
$('#vm_details').empty();
$("#compute_resource_tab").hide();
$("#compute_profile").hide();
update_capabilities('build');
}
else
......
$('#mac_address').hide();
$("#model_name").hide();
$("#compute_resource_tab").show();
$("#compute_profile").show();
$('#vm_details').empty();
var data = $('form').serialize().replace('method=put', 'method=post');
$('#compute_resource').html(spinner_placeholder(_('Loading virtual machine information ...')));
......
$(this).attr("disabled", "disabled");
});
$("a.disable-unsupported").remove();
}
function capacity_edit(element) {
var buttons = $(element).closest('.fields').find('button[name=allocation_radio_btn].btn.active');
if (buttons.size() > 0 && $(buttons[0]).text() == 'Full') {
var allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
allocation.value = element.value;
}
return false;
}
function allocation_switcher(element, action) {
var allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
if (action == 'None') {
$(allocation).attr('readonly', 'readonly');
allocation.value = '0G';
} else if (action == 'Size') {
$(allocation).removeAttr('readonly');
allocation.value = '';
$(allocation).focus();
} else if (action == 'Full') {
$(allocation).attr('readonly', 'readonly');
var capacity = $(element).closest('.fields').find('[id$=capacity]')[0];
allocation.value = capacity.value;
}
return false;
}
}
app/assets/javascripts/two-pane.js
$(document).on('click', ".table-two-pane td", function(e) {
var item = $(this).find("a[href$='edit']");
if(item.length){
$(document).on('click', ".table-two-pane td a[href$='edit']", function(e) {
if ($('.table-two-pane').length) {
e.preventDefault();
two_pane_open(item);
two_pane_open(this);
}
});
......
}
});
$(document).on('click', "a[href$='new'].new_two_pane", function(e) {
if ($('.table-two-pane').length) {
e.preventDefault();
two_pane_open(this);
}
});
$(document).on('submit','.two-pane-right', function() {
two_pane_submit();
return false;
app/controllers/compute_attributes_controller.rb
class ComputeAttributesController < ApplicationController
def new
@set = ComputeAttribute.new(:compute_profile_id => params[:compute_profile_id].to_i,
:compute_resource_id => params[:compute_resource_id].to_i)
end
def create
@set = ComputeAttribute.new(params[:compute_attribute])
if @set.save
process_success :success_redirect => request.referer || compute_profile_path(@set.compute_profile)
else
process_error
end
end
def edit
@set = ComputeAttribute.find_by_id(params[:id])
end
def update
@set = ComputeAttribute.find(params[:id])
if @set.update_attributes!(params[:compute_attribute])
process_success :success_redirect => request.referer || compute_profile_path(@set.compute_profile)
else
process_error
end
end
end
app/controllers/compute_profiles_controller.rb
class ComputeProfilesController < ApplicationController
include Foreman::Controller::AutoCompleteSearch
before_filter :find_compute_profile, :only => %w{edit show update destroy}
def index
@compute_profiles = ComputeProfile.search_for(params[:search], :order => params[:order]).paginate(:page => params[:page])
end
def show
end
def new
@compute_profile = ComputeProfile.new
end
def edit
end
def create
@compute_profile = ComputeProfile.new(params[:compute_profile])
if @compute_profile.save
process_success :success_redirect => compute_profile_path(@compute_profile)
else
process_error
end
end
def update
if @compute_profile.update_attributes(params[:compute_profile])
process_success :success_redirect => compute_profiles_path
else
process_error
end
end
def destroy
if @compute_profile.destroy
process_success
else
process_error
end
end
private
def find_compute_profile
@compute_profile = ComputeProfile.find(params[:id])
end
end
app/controllers/compute_resources_controller.rb
class ComputeResourcesController < ApplicationController
include Foreman::Controller::AutoCompleteSearch
AJAX_REQUESTS = %w{hardware_profile_selected cluster_selected}
AJAX_REQUESTS = %w{template_selected cluster_selected}
before_filter :ajax_request, :only => AJAX_REQUESTS
before_filter :find_by_id, :only => [:show, :edit, :update, :destroy, :ping, :associate] + AJAX_REQUESTS
......
render :partial => "compute_resources/form", :locals => { :compute_resource => @compute_resource }
end
def hardware_profile_selected
compute = @compute_resource.hardware_profile(params[:hwp_id])
def template_selected
compute = @compute_resource.template(params[:template_id])
compute.interfaces
compute.volumes
respond_to do |format|
app/controllers/hosts_controller.rb
def compute_resource_selected
return not_found unless (params[:host] && (id=params[:host][:compute_resource_id]))
Taxonomy.as_taxonomy @organization, @location do
render :partial => "compute", :locals => {:compute_resource => ComputeResource.find_by_id(id)}
compute_profile_id = params[:host][:compute_profile_id] || Hostgroup.find_by_id(params[:host][:hostgroup_id]).try(:compute_profile_id)
compute_resource = ComputeResource.find(id)
render :partial => "compute", :locals => { :compute_resource => compute_resource,
:vm_attrs => compute_resource.compute_profile_attributes_for(compute_profile_id) }
end
end
......
@environment = @hostgroup.environment
@domain = @hostgroup.domain
@subnet = @hostgroup.subnet
@compute_profile = @hostgroup.compute_profile
@host = if params[:host][:id]
host = Host::Base.find(params[:host][:id])
app/helpers/audits_helper.rb
module AuditsHelper
MainObjects = %w(Host Hostgroup User Operatingsystem Environment Puppetclass Parameter Architecture ComputeResource ConfigTemplate)
MainObjects = %w(Host Hostgroup User Operatingsystem Environment Puppetclass Parameter Architecture ComputeResource ConfigTemplate ComputeProfile ComputeAttribute)
# lookup the Model representing the numerical id and return its label
def id_to_label name, change
......
def audit_title audit
type_name = audited_type audit
if type_name == "Puppet Class"
"#{id_to_label audit.audited_changes.keys[0], audit.audited_changes.values[0]}"
else
name = audit.auditable_name.blank? ? audit.revision.to_label : audit.auditable_name
name += " / #{audit.associated_name}" if audit.associated_id and !audit.associated_name.blank?
name
case type_name
when 'Puppet Class'
"#{id_to_label audit.audited_changes.keys[0], audit.audited_changes.values[0]}"
else
name = audit.auditable_name.blank? ? audit.revision.to_label : audit.auditable_name
name += " / #{audit.associated_name}" if audit.associated_id and !audit.associated_name.blank?
name
end
rescue
""
......
end
def audited_type audit
type_name = audit.auditable_type
type_name = "Puppet Class" if type_name == "HostClass"
type_name = "#{audit.associated_type || 'Global'}-#{type_name}" if type_name == "Parameter"
type_name = case audit.auditable_type
when 'HostClass'
'Puppet Class'
when 'Parameter'
"#{audit.associated_type || 'Global'}-#{type_name}"
else
audit.auditable_type
end
type_name.underscore.titleize
end
app/helpers/compute_resources_vms_helper.rb
def security_groups_for_vpc(security_groups, vpc_id)
security_groups.map{ |sg| [sg.name, sg.group_id] if sg.vpc_id == vpc_id}.compact
end
def show_vm_name?
controller_name != 'hosts' && controller_name != 'compute_attributes'
end
end
app/helpers/layout_helper.rb
module LayoutHelper
def title(page_title, page_header = nil)
content_for(:title, page_title.to_s)
@page_header = page_header || @content_for_title || page_title.to_s
@page_header ||= page_header || @content_for_title || page_title.to_s
end
def title_actions *elements
app/models/compute_attribute.rb
class ComputeAttribute < ActiveRecord::Base
attr_accessible :compute_profile_id, :compute_resource_id, :vm_attrs
audited :associated_with => :compute_profile
belongs_to :compute_resource
belongs_to :compute_profile
validates :compute_profile_id, :presence => true, :uniqueness => {:scope => :compute_resource_id}
validates :compute_resource_id, :presence => true, :uniqueness => {:scope => :compute_profile_id}
serialize :vm_attrs, Hash
before_save :update_name
def method_missing(method, *args, &block)
return vm_attrs["#{method}"] if vm_attrs.keys.include?(method.to_s)
raise Foreman::Exception.new(N_('%s is an unknown attribute'), method)
end
def new_vm
compute_resource.new_vm(vm_attrs) if vm_attrs
end
def pretty_vm_attrs
# vm_description is defined in FogExtensions for each compute resource
@pretty_vm_attrs ||= new_vm.try(:vm_description)
end
private
def update_name
self.name = pretty_vm_attrs if pretty_vm_attrs.present?
end
end
app/models/compute_profile.rb
class ComputeProfile < ActiveRecord::Base
include Authorization
attr_accessible :name
audited
has_associated_audits
before_destroy EnsureNotUsedBy.new(:hostgroups)
has_many :compute_attributes
has_many :compute_resources, :through => :compute_attributes
has_many_hosts
has_many :hostgroups
validates :name, :presence => true, :uniqueness => true
scoped_search :on => :name, :complete_value => true
default_scope lambda { order('compute_profiles.name') }
scope :visibles, lambda { includes(:compute_attributes).where('compute_attributes.id > 0') }
def to_param
"#{id}-#{name.parameterize}"
end
end
app/models/compute_resource.rb
has_many_hosts
has_many :images, :dependent => :destroy
before_validation :set_attributes_hash
has_many :compute_attributes
has_many :compute_profiles, :through => :compute_attributes
# attribute used by *_names and *_name methods. default is :name
attr_name :to_label
# with proc support, default_scope can no longer be chained
# include all default scoping here
......
ActiveSupport::HashWithIndifferentAccess.new(:name => "foreman_#{Time.now.to_i}")
end
def hardware_profiles(opts={})
def templates(opts={})
end
def hardware_profile(id,opts={})
def template(id,opts={})
end
def update_required?(old_attrs, new_attrs)
......
self.attrs[:setpw] = setpw.to_i
end
def compute_profile_attributes_for(id)
compute_attributes.find_by_compute_profile_id(id).try(:vm_attrs) || {}
end
protected
def client
app/models/compute_resources/foreman/model/openstack.rb
Host.my_hosts.where(:ip => [vm.floating_ip_address, vm.private_ip_address]).first
end
def flavor_name(flavor_ref)
client.flavors.get(flavor_ref).try(:name)
end
private
def client
app/models/compute_resources/foreman/model/ovirt.rb
self.attrs[:ovirt_quota_id]
end
def hardware_profiles(opts={})
def templates(opts={})
client.templates
end
def hardware_profile(id)
def template(id)
client.templates.get(id) || raise(ActiveRecord::RecordNotFound)
end
app/models/concerns/fog_extensions.rb
require 'fog/vsphere/models/compute/folder'
Fog::Compute::Vsphere::Folder.send(:include, FogExtensions::Vsphere::Folder)
require 'fog/rackspace'
require 'fog/rackspace/models/compute_v2/server'
Fog::Compute::RackspaceV2::Server.send(:include, FogExtensions::RackspaceV2::Server)
rescue LoadError
Rails.logger.info "Fog is not installed - unable to manage compute resources"
rescue => exception
app/models/concerns/fog_extensions/aws/server.rb
def reset
poweroff && start
end
def vm_description
flavor.to_label
end
end
end
end
app/models/concerns/fog_extensions/google/server.rb
def flavors
service.flavors
end
def image_id
image_name
end
def vm_description
pretty_machine_type
end
end
end
end
app/models/concerns/fog_extensions/libvirt/server.rb
module Server
extend ActiveSupport::Concern
include ActionView::Helpers::NumberHelper
def to_s
name
end
......
start
end
def vm_description
_("%{cpus} CPUs and %{memory} memory") % {:cpus => cpus, :memory => number_to_human_size(memory.to_i)}
end
end
end
end
app/models/concerns/fog_extensions/openstack/server.rb
reboot('HARD')
end
def vm_description
service.flavors.get(flavor_ref).try(:name)
end
end
end
end
app/models/concerns/fog_extensions/ovirt/server.rb
module Server
extend ActiveSupport::Concern
include ActionView::Helpers::NumberHelper
def state
status
end
......
start
end
def vm_description
_("%{cores} Cores and %{memory} memory") % {:cores => cores, :memory => number_to_human_size(memory.to_i)}
end
end
end
end
app/models/concerns/fog_extensions/rackspace_v2/server.rb
module FogExtensions
module RackspaceV2
module Server
extend ActiveSupport::Concern
def vm_description
flavor.name
end
end
end
end
app/models/concerns/fog_extensions/vsphere/server.rb
reboot(:force => true)
end
def vm_description
_("%{cpus} CPUs and %{memory} MB memory") % {:cpus => cpus, :memory => memory_mb.to_i}
end
end
end
end
app/models/concerns/host_common.rb
belongs_to :puppet_ca_proxy, :class_name => "SmartProxy"
belongs_to :domain
belongs_to :subnet
belongs_to :compute_profile
before_save :check_puppet_ca_proxy_is_required?
has_many :lookup_values, :finder_sql => Proc.new { LookupValue.where('lookup_values.match' => lookup_value_match).to_sql }, :dependent => :destroy
app/models/host/managed.rb
:if => Proc.new { |host| host.managed and host.disk.empty? and not defined?(Rake) and capabilities.include?(:build) }
validates :serial, :format => {:with => /[01],\d{3,}n\d/, :message => N_("should follow this format: 0,9600n8")},
:allow_blank => true, :allow_nil => true
after_validation :set_compute_attributes
end
before_validation :set_hostgroup_defaults, :set_ip_address, :normalize_addresses, :normalize_hostname, :force_lookup_value_matcher
after_validation :ensure_associations, :set_default_user
before_validation :set_certname, :if => Proc.new {|h| h.managed? and Setting[:use_uuid_for_certificates] } if SETTINGS[:unattended]
......
def set_hostgroup_defaults
return unless hostgroup
assign_hostgroup_attributes(%w{environment domain puppet_proxy puppet_ca_proxy})
assign_hostgroup_attributes(%w{environment domain puppet_proxy puppet_ca_proxy compute_profile})
if SETTINGS[:unattended] and (new_record? or managed?)
assign_hostgroup_attributes(%w{operatingsystem architecture})
assign_hostgroup_attributes(%w{medium ptable subnet}) if capabilities.include?(:build)
end
end
def set_compute_attributes
return unless compute_attributes.empty?
return unless compute_profile_id && compute_resource_id
self.compute_attributes = compute_resource.compute_profile_attributes_for(compute_profile_id)
end
def set_ip_address
self.ip ||= subnet.unused_ip if subnet and SETTINGS[:unattended] and (new_record? or managed?)
end
......
bmc_proxy.boot({:function => 'bootdevice', :device => booting_device})
end
# take from hostgroup if compute_profile_id is nil
def compute_profile_id
read_attribute(:compute_profile_id) || hostgroup.try(:compute_profile_id)
end
private
def lookup_value_match
app/models/hostgroup.rb
ancestors.map{|a| a.name + "/"}.join + name
end
def inherited_compute_profile_id
read_attribute(:compute_profile_id) || nested_compute_profile_id
end
def compute_profile
ComputeProfile.find_by_id(inherited_compute_profile_id)
end
private
def lookup_value_match
......
nil
end
def nested_compute_profile_id
Hostgroup.sort_by_ancestry(ancestors.where('compute_profile_id > 0')).last.try(:compute_profile_id) if ancestry.present?
end
def remove_duplicated_nested_class
self.puppetclasses -= ancestors.map(&:puppetclasses).flatten
end
app/services/foreman/access_permissions.rb
:"api/v2/compute_resources" => [:create]
}
map.permission :edit_compute_resources, {:compute_resources => [:edit, :update].push(*ajax_actions),
:compute_profiles => [:new, :create, :edit, :update, :destroy, :index, :show, :auto_complete_search],
:compute_attributes => [:new, :create, :edit, :update, :destroy, :index, :show],
:"api/v1/compute_resources" => [:update],
:"api/v2/compute_resources" => [:update]
}
......
ajax_actions = [:architecture_selected, :compute_resource_selected, :domain_selected, :environment_selected,
:hostgroup_or_environment_selected, :medium_selected, :os_selected, :use_image_selected, :process_hostgroup,
:process_taxonomy, :current_parameters, :puppetclass_parameters, :template_used]
cr_ajax_actions = [:cluster_selected, :hardware_profile_selected, :provider_selected]
cr_ajax_actions = [:cluster_selected, :template_selected, :provider_selected]
pc_ajax_actions = [:parameters]
subnets_ajax_actions = [:freeip]
tasks_ajax_actions = [:show]
app/services/menu/loader.rb
menu.item :smart_proxies, :caption => N_('Smart proxies')
if SETTINGS[:unattended]
menu.item :compute_resources, :caption => N_('Compute resources')
menu.item :compute_profiles, :caption => N_('Compute profiles')
menu.item :subnets, :caption => N_('Subnets')
menu.item :domains, :caption => N_('Domains')
end
app/views/api/v2/hostgroups/main.json.rabl
extends "api/v2/hostgroups/base"
attributes :subnet_id, :subnet_name, :operatingsystem_id, :operatingsystem_name, :domain_id, :domain_name, :environment_id, :environment_name, :ancestry, :parameters, :puppetclass_ids
attributes :subnet_id, :subnet_name, :operatingsystem_id, :operatingsystem_name, :domain_id, :domain_name, :environment_id, :environment_name,
:compute_profile_id, :compute_profile_name, :ancestry, :parameters, :puppetclass_ids
app/views/api/v2/hosts/main.json.rabl
:subnet_id, :subnet_name, :sp_subnet_id, :ptable_id, :ptable_name, :medium_id, :medium_name, :build,
:comment, :disk, :installed_at, :model_id, :model_name, :hostgroup_id, :hostgroup_name, :owner_id, :owner_type,
:enabled, :puppet_ca_proxy_id, :managed, :use_image, :image_file, :uuid, :compute_resource_id, :compute_resource_name,
:compute_profile_id, :compute_profile_name,
:puppet_proxy_id, :certname, :image_id, :image_name, :created_at, :updated_at,
:last_compile, :last_freshcheck, :serial, :source_file_id, :puppet_status
app/views/compute_attributes/_form.html.erb
<%= javascript 'compute_resource', 'lookup_keys'%>
<%= form_for([@set.compute_profile, @set]) do |f| %>
<%= base_errors_for @set %>
<%= select_f f, :compute_profile_id, ComputeProfile.all, :id, :name, {}, :disabled => true, :label => _('Compute profile') %>
<%= select_f f, :compute_resource_id, ComputeResource.all, :id, :to_label, {}, :disabled => true, :label => _('Compute resource') %>
<%= fields_for 'compute_attribute[vm_attrs]', @set.compute_resource.new_vm(@set.vm_attrs) do |f2| %>
<%= render :partial => "compute_resources_vms/form/#{@set.compute_resource.provider.downcase}",
:locals => { :f => f2, :compute_resource => @set.compute_resource } %>
<% end %>
<% if f.object.new_record? %>
<%= f.hidden_field :compute_profile_id %>
<%= f.hidden_field :compute_resource_id %>
<% end %>
<%= submit_or_cancel f, false, :cancel_path => compute_profile_path(@set.compute_profile) %>
<% end %>
app/views/compute_attributes/edit.html.erb
<% title _("Edit compute profile on %s") % @set.compute_resource.to_label %>
<%= render 'form' %>
app/views/compute_attributes/new.html.erb
<% title _("New compute profile on %s") % @set.compute_resource.to_label %>
<%= render 'form' %>
app/views/compute_profiles/_form.html.erb
<%= form_for(@compute_profile) do |f| %>
<%= base_errors_for @compute_profile %>
<%= text_f f, :name %>
<%= submit_or_cancel f %>
<% end %>
app/views/compute_profiles/edit.html.erb
<% title _("Edit Compute profile") %>
<%= render 'form' %>
app/views/compute_profiles/index.html.erb
<% title _('Compute profiles') %>
<% title_actions display_link_if_authorized(_('New Compute Profile'), hash_for_new_compute_profile_path), help_path %>
<table class="table table-bordered table-striped table-two-pane">
<tr>
<th><%= sort :name %></th>
<th></th>
</tr>
<% @compute_profiles.each do |compute_profile| %>
<tr>
<td><%= link_to_if_authorized h(compute_profile.name), hash_for_compute_profile_path(compute_profile)%></td>
<td><%= action_buttons(
display_link_if_authorized(_('Edit'), hash_for_compute_profile_path(compute_profile)),
display_link_if_authorized(_('Rename'), hash_for_edit_compute_profile_path(compute_profile)),
display_delete_if_authorized(hash_for_compute_profile_path(compute_profile), :confirm => _('Delete %s?') % compute_profile.name))%>
</td>
</tr>
<% end %>
</table>
<%= page_entries_info @compute_profiles %>
<%= will_paginate @compute_profiles %>
app/views/compute_profiles/new.html.erb
<% title _("New Compute profile") %>
<%= render 'form' %>
app/views/compute_profiles/show.html.erb
<%= javascript 'compute_resource', 'lookup_keys'%>
<% title(_("Edit Compute profile: %s") % @compute_profile.name) %>
<% title_actions display_link_if_authorized(_("Back"), hash_for_compute_profiles_path) %>
<p>
<%= _("Click on the link of a compute resource to edit its default VM attributes.") %>
</p>
<br />
<table class="table table-bordered table-striped table-two-pane">
<tr>
<th><%= _("Compute Resource") %></th>
<th><%= _("VM Attributes (%s)") % @compute_profile.name %></th>
</tr>
<% ComputeResource.my_compute_resources.each do |compute_resource| %>
<% compute_attribute = ComputeAttribute.where(:compute_profile_id => @compute_profile.id, :compute_resource_id => compute_resource.id).first %>
<% which_path = if compute_attribute.try(:id)
edit_compute_profile_compute_attribute_path(@compute_profile.to_param, compute_attribute.id)
else
new_compute_profile_compute_resource_compute_attribute_path(@compute_profile.to_param, compute_resource.to_param)
end %>
<tr>
<td><%= link_to(compute_resource.to_label, which_path, :class => compute_attribute.try(:id) ? '' : 'new_two_pane') %></td>
<td>
<% set = compute_resource.compute_attributes.where(:compute_profile_id => @compute_profile.id).first %>
<%= set ? set.name : content_tag(:span, _("unspecified"), :class => 'gray') %>
</td>
</tr>
<% end %>
</table>
app/views/compute_resources/show.html.erb
<%= javascript "compute_resource" %>
<%= javascript 'compute_resource', 'lookup_keys'%>
<% title @compute_resource.name %>
<% title_actions display_link_if_authorized(_("Associate VMs"), hash_for_associate_compute_resource_path(:compute_resource_id => @compute_resource), :title=> _("Associate VMs to Foreman hosts"), :method => :put, :class=>"btn btn-default"),
......
<% if @compute_resource.capabilities.include?(:image) %>
<li><a href="#images" data-toggle="tab"><%= _("Images") %></a></li>
<% end %>
<li><a href="#compute_profiles" data-toggle="tab"><%= _("Compute profiles") %></a></li>
</ul>
<div class="tab-content">
......
</div>
</div>
<% end %>
<div id="compute_profiles" class="tab-pane">
<table class="table table-bordered table-striped table-two-pane">
<tr>
<th><%= _("Compute profile") %></th>
<th><%= _("VM Attributes") %></th>
</tr>
<% ComputeProfile.scoped.each do |compute_profile| %>
<% compute_attribute = ComputeAttribute.where(:compute_profile_id => compute_profile.id, :compute_resource_id => @compute_resource.id).first %>
<% which_path = if compute_attribute.try(:id)
edit_compute_profile_compute_attribute_path(compute_profile.to_param, compute_attribute.id)
else
new_compute_profile_compute_resource_compute_attribute_path(compute_profile.to_param, @compute_resource.to_param)
end %>
<tr>
<td><%= link_to(compute_profile.name, which_path, :class => compute_attribute.try(:id) ? '' : 'new_two_pane') %></td>
<td>
<% set = @compute_resource.compute_attributes.where(:compute_profile_id => compute_profile.id).first %>
<%= set ? set.name : content_tag(:span, _("unspecified"), :class => 'gray') %>
</td>
</tr>
<% end %>
</table>
</div>
</div>
app/views/compute_resources_vms/form/_libvirt.html.erb
<% new = f.object && f.object.new? %>
<%= text_f f, :name, :disabled => !new if controller_name != "hosts" %>
<%= text_f f, :name, :disabled => !new if show_vm_name? %>
<%= selectable_f f, :cpus, 1..compute_resource.max_cpu_count, { }, :disabled => !new, :label => _('CPUs') %>
<%= selectable_f f, :memory, memory_options(compute_resource.max_memory), { }, :class => "col-md-2", :disabled => !new, :label => _('Memory') %>
......
</div>
<!--TODO # Move to a helper-->
<% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1' %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start')} if new %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start')} if new && controller_name != "compute_attributes" %>
app/views/compute_resources_vms/form/_openstack.html.erb
<% new = f.object && f.object.id.blank? %>
<%= text_f f, :name, :disabled => !new if controller_name != "hosts" %>
<%= text_f f, :name, :disabled => !new if show_vm_name? %>
<%= select_f f, :flavor_ref, compute_resource.flavors, :id, :name, {}, :label => _('Flavor') %>
<%
arch ||= nil ; os ||= nil
app/views/compute_resources_vms/form/_ovirt.html.erb
<% javascript 'compute_resource', 'lookup_keys' %>
<%= text_f f, :name if controller_name != "hosts" %>
<%= text_f f, :name if show_vm_name? %>
<% new = @host.nil? || @host.try(:new_record?) %>
<% clusters = compute_resource.clusters %>
<%= select_f f, :cluster, clusters, :id, :name, { },
......
:help_inline => :indicator,
:label => _('Cluster') } %>
<%= f.hidden_field :cluster if !new %>
<%= select_f f, :template, compute_resource.hardware_profiles, :id, :name, {:include_blank => _("Select template")},
{ :disabled => !new, :'data-url' => hardware_profile_selected_compute_resource_path(compute_resource),
:onchange => 'ovirt_hwpSelected(this);',
<%= select_f f, :template, compute_resource.templates, :id, :name, {:include_blank => _("Select template")},
{ :disabled => !new, :'data-url' => template_selected_compute_resource_path(compute_resource),
:onchange => 'ovirt_templateSelected(this);',
:help_inline => :indicator,
:help_block => _("Template / Hardware Profile to use"),
:help_block => _("Template / Compute Profile to use"),
:label => _('Template') } %>
<%= f.hidden_field :template if !new %>
<div class='hardware_profile'>
<div class='compute_profile'>
<%= selectable_f f, :cores, 1..compute_resource.max_cpu_count, { }, :class => "col-md-2", :label => _('Cores') %>
<%= selectable_f f, :memory, memory_options(compute_resource.max_memory), { }, :class => "col-md-2", :label => _('Memory') %>
<div class="children_fields">
......
</div>
</div>
<% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1' %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start') } if new %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start') } if new && controller_name != "compute_attributes" %>
app/views/compute_resources_vms/form/_vmware.html.erb
<% new = @host ? @host.created_at.nil? : true %>
<%= text_f f, :name, :disabled => !new if controller_name != "hosts" %>
<%= text_f f, :name, :disabled => !new if show_vm_name? %>
<%= selectable_f f, :cpus, 1..compute_resource.max_cpu_count, { }, :class => "col-md-2", :disabled => !new, :label => _('CPUs') %>
<%= text_f f, :memory_mb, :class => "col-md-2", :disabled => !new, :label => _("Memory (MB)") %>
<%= selectable_f f, :cluster, compute_resource.clusters, { }, :class => "col-md-2", :disabled => !new, :label => _('Cluster') %>
......
<!--TODO # Move to a helper-->
<% checked = params[:host] && params[:host][:compute_attributes] && params[:host][:compute_attributes][:start] || '1' %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start') } if new and controller_name == 'hosts' %>
<%= checkbox_f f, :start, { :checked => (checked == '1'), :help_inline => _("Power ON this machine"), :label => _('Start') } if new and show_vm_name? %>
app/views/compute_resources_vms/form/libvirt/_network.html.erb
<div class="fields">
<div class="form-group">
<% nat = compute_resource.networks %>
<% bridge = compute_resource.interfaces %>
......
</div>
<%= selectable_f f, :model, %w(virtio rtl8139 ne2k_pci pcnet e1000), {},
{ :label => _('NIC type'), :class => 'col-md-2' } %>
</div>
</div>
app/views/compute_resources_vms/form/libvirt/_volume.html.erb
<div class="fields">
<div class="form-group">
<%= selectable_f f, :pool_name, compute_resource.storage_pools.map(&:name), { }, :class => "col-md-2", :label => _("Storage pool") %>
<%= text_f f, :capacity, :class => "col-md-2", :label => _("Size (GB)"), :onchange => 'capacity_edit(this)' %>
<%= allocation_text_f f %>
<%= select_f f, :format_type, %w[RAW QCOW2],:downcase, :to_s, { }, :class => "col-md-2", :label => _("Type"),
:help_inline => remove_child_link("X", f, { :method => :'_delete', :title => _('remove volume'), :class => 'label label-danger disable-unsupported' }) %>
</div>
</div>
app/views/compute_resources_vms/form/ovirt/_network.html.erb
<div class="fields">
<div class="form-group">
<% if f.object._delete != '1' %>
<% disabled = (f.object.persisted? == "true" || f.object.persisted? == true) %>
<%= text_f f, :name, :disabled => disabled, :class => "col-md-2", :label => _('Name') %>
......
:label => _('Network') %>
<%= f.hidden_field :network if disabled %>
<% end %>
</div>
</div>
app/views/compute_resources_vms/form/vmware/_network.html.erb
<div class="fields">
<div class="form-group">
<% if (networks = compute_resource.networks).any? %>
<%= select_f f, :type, compute_resource.nictypes, :first, :last, { },
:class => "col-md-2 disable-unsupported",
......
:help_inline => remove_child_link("X", f, { :method => :'_delete', :title => _('remove network interface'), :class => 'label label-danger disable-unsupported' })
%>
<% end %>
</div>
</div>
app/views/hostgroups/_form.html.erb
<%= text_f f, :name %>
<%= select_f f, :environment_id, Environment.all, :id, :to_label, {:include_blank => true},
{:label => _("Environment"), :onchange => 'update_puppetclasses(this);', :"data-url" => environment_selected_hostgroups_path} %>
<%= select_f(f, :compute_profile_id, ComputeProfile.visibles, :id, :name, {:include_blank => (f.object.parent_id.present? ? _("Inherit from parent") : '')},
{:label => _("Compute profile")}) if ComputeProfile.visibles.any? %>
<%= puppet_master_fields f %>
</div>
app/views/hosts/_compute.html.erb
<%= fields_for "#{type}[compute_attributes]", @host ? @host.compute_object : compute_resource.new_vm do |compute| %>
<%= fields_for "#{type}[compute_attributes]", @host ? @host.compute_object : compute_resource.new_vm(vm_attrs) do |compute| %>
<% if compute.object %>
<div id='update_not_supported' class='alert hide'><%= _("VM editing is not implemented for this provider") %></div>
<%= render :partial => "compute_resources_vms/form/#{compute_resource.provider.downcase}",
app/views/hosts/_form.html.erb
<%= select_f f, :compute_resource_id, ComputeResource.my_compute_resources, :id, :to_label,
{ :include_blank => _('Bare Metal') },
{:label => _('Deploy on'), :disabled => !@host.new_record?, :'data-url' => compute_resource_selected_hosts_path,
:onchange => 'computeResourceSelected(this);',
:help_inline => :indicator } if SETTINGS[:unattended] && @host.new_record? || @host.compute_resource_id %>
:onchange => 'computeResourceSelected(this);',
:help_inline => :indicator } if SETTINGS[:unattended] && @host.new_record? || @host.compute_resource_id %>
<% if @host.new_record? && ComputeProfile.visibles.any? %>
<%# only show compute_profile select box for new hosts. It is not relevant for existing hosts as the VM attributes defined could
be different from the defaults, or the defaults could have changed after the vm was created. %>
<div id="compute_profile" <%= display?(!@host.compute_resource_id) %> >
<%= select_f f, :compute_profile_id, ComputeProfile.visibles, :id, :name,
{ :include_blank => true },
{ :label => _("Compute profile"), :'data-url' => compute_resource_selected_hosts_path,
:onchange => 'computeResourceSelected(this);',
:help_inline => :indicator } if SETTINGS[:unattended] %>
</div>
<% end %>
<%= select_f f, :environment_id, Environment.all, :id, :to_label, { :include_blank => true },
{:onchange => 'update_puppetclasses(this)', :'data-url' => hostgroup_or_environment_selected_hosts_path,
config/routes.rb
end
end
resources :compute_profiles do
resources :compute_attributes, :only => [:create, :edit, :update]
resources :compute_resources, :only => [] do
resources :compute_attributes, :only => :new
end
end
resources :hostgroups, :except => [:show] do
member do
get 'nest'
......
constraints(:id => /[^\/]+/) do
resources :compute_resources do
member do
post 'hardware_profile_selected'
post 'template_selected'
post 'cluster_selected'
post 'ping'
put 'associate'
db/migrate/20131224153518_create_compute_profiles.rb
class CreateComputeProfiles < ActiveRecord::Migration
def change
create_table :compute_profiles do |t|
t.string :name
t.timestamps
end
end
end
db/migrate/20131224153743_create_compute_attributes.rb
class CreateComputeAttributes < ActiveRecord::Migration
def change
create_table :compute_attributes do |t|
t.integer :compute_profile_id
t.integer :compute_resource_id
t.string :name
t.text :vm_attrs
t.timestamps
end
add_index :compute_attributes, :compute_profile_id
add_index :compute_attributes, :compute_resource_id
add_foreign_key "compute_attributes", "compute_resources", :name => "compute_attributes_compute_resource_id_fk"
add_foreign_key "compute_attributes", "compute_profiles", :name => "compute_attributes_compute_profile_id_fk"
end
end
db/migrate/20131224154836_add_compute_profile_to_hostgroup.rb
class AddComputeProfileToHostgroup < ActiveRecord::Migration
def change
add_column :hostgroups, :compute_profile_id, :integer
add_column :hosts, :compute_profile_id, :integer
add_index :hostgroups, :compute_profile_id
add_index :hosts, :compute_profile_id
add_foreign_key "hostgroups", "compute_profiles", :name => "hostgroups_compute_profile_id_fk"
add_foreign_key "hosts", "compute_profiles", :name => "hosts_compute_profile_id_fk"
end
end
db/seeds.rb
raise "Unable to create admin user: #{format_errors user}" unless user.save
end
end
# Compute Profiles - only create if there are not any
if ComputeProfile.unconfigured?
ComputeProfile.without_auditing do
[
{ :name => '1-Small' },
{ :name => '2-Medium' },
{ :name => '3-Large' },
].each do |input|
cp = ComputeProfile.create input
raise "Unable to create hardware profile: #{format_errors m}" if cp.nil? || cp.errors.any?
end
end
end
test/fixtures/compute_attributes.yml
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
one:
compute_profile: one
compute_resource: ec2
vm_attrs:
flavor_id: m1.small
availability_zone: eu-west-1a
two:
compute_profile: one
compute_resource: one
vm_attrs:
cpus: 2
memory: 536870912
three:
compute_profile: two
compute_resource: ec2
vm_attrs:
flavor_id: m1.medium
availability_zone: eu-west-1a
four:
compute_profile: two
compute_resource: one
vm_attrs:
cpus: 4
memory: 4294967296
test/fixtures/compute_profiles.yml
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html
one:
name: 1-Small
two:
name: 2-Medium
three:
name: 3-Large
test/fixtures/compute_resources.yml
password: MyString
uuid: 234234234324
type: Foreman::Model::EC2
ec2-another:
name: another-ec2
description: yourcompute
url: eu-west-1
user: MyString
password: MyString
uuid: 234234234324
type: Foreman::Model::EC2
test/fixtures/hostgroups.yml
domain: mydomain
label: Common
root_pass: $1$foreman$NW1XVtbk4/XkJqmKNrFWV0
compute_profile: one
unusual:
name: Unusual
test/functional/compute_attributes_controller_test.rb
require 'test_helper'
class ComputeAttributesControllerTest < ActionController::TestCase
setup do
Fog.mock!
User.current = User.admin
@set = compute_attributes(:one)
@compute_profile = @set.compute_profile #1-Small
@compute_resource = @set.compute_resource #EC2
end
teardown do
Fog.unmock!
end
test "should get new" do
get :new, {:compute_profile_id => @compute_profile.to_param, :compute_resource_id => @compute_resource.to_param}, set_session_user
assert_response :success
end
test "should create compute_attribute" do
assert_difference('ComputeAttribute.count') do
# create 3-Large that doesn't exist in fixtures
post :create, {:compute_profile_id => @compute_profile.to_param,
:compute_attribute => { :compute_resource_id => @compute_resource.to_param, :compute_profile_id => compute_profiles(:three) }}, set_session_user
end
assert_redirected_to compute_profile_path(assigns(:set).compute_profile)
end
test "should get edit" do
get :edit, {:compute_profile_id => @compute_profile.to_param, :id => @set}, set_session_user
assert_response :success
end
test "should update compute_attribute" do
put :update, {:id => @set,
:compute_profile_id => @compute_profile.to_param,
:compute_attribute => { :compute_resource_id => @set.compute_resource_id, :compute_profile_id => @set.compute_profile_id }}, set_session_user
assert_redirected_to compute_profile_path(@set.compute_profile)
end
end
test/functional/compute_profiles_controller_test.rb
require 'test_helper'
class ComputeProfilesControllerTest < ActionController::TestCase
setup do
User.current = User.admin
@compute_profile = compute_profiles(:one)
end
test "should get index" do
get :index, {}, set_session_user
assert_response :success
assert_not_nil assigns(:compute_profiles)
end
test "should get new" do
get :new, {}, set_session_user
assert_response :success
end
test "should create compute_profile" do
assert_difference('ComputeProfile.count') do
post :create, {:compute_profile => { :name => '10-xxlarge' }}, set_session_user
end
assert_redirected_to compute_profile_path(assigns(:compute_profile))
end
test "should show compute_profile" do
get :show, {:id => @compute_profile}, set_session_user
assert_response :success
end
test "should get edit" do
get :edit, {:id => @compute_profile}, set_session_user
assert_response :success
end
test "should update compute_profile" do
put :update, {:id => @compute_profile, :compute_profile => { :name => "new name" }}, set_session_user
assert_redirected_to compute_profiles_path
end
test "should destroy compute_profile" do
assert_difference('ComputeProfile.count', -1) do
delete :destroy, {:id => compute_profiles(:three)}, set_session_user
end
assert_redirected_to compute_profiles_path
end
end
test/integration/compute_profile_test.rb
require 'test_helper'
class ComputeProfileTest < ActionDispatch::IntegrationTest
setup do
Fog.mock!
end
teardown do
Fog.unmock!
end
test "index page" do
assert_index_page(compute_profiles_path,"Compute profiles","New Compute Profile")
end
test "create new page" do
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff