Revision 9234d6c5
Added by Ohad Levy over 6 years ago
app/assets/javascripts/application.js | ||
---|---|---|
//= require lookup_keys
|
||
//= require editable/bootstrap-editable
|
||
//= require editable/rails
|
||
//= require compute_resource
|
||
|
||
$(document).on("page:fetch", tfm.tools.showSpinner)
|
||
|
app/assets/javascripts/compute_resource.js | ||
---|---|---|
// AJAX load vm listing
|
||
$(function() {
|
||
$('#vms, #images_list, #key_pairs_list').each(function() {
|
||
var url = $(this).attr('data-url');
|
||
$(this).load(url + ' table', function(response, status, xhr) {
|
||
if (status == "error") {
|
||
$(this).html(Jed.sprintf(__("There was an error listing VMs: %(status)s %(statusText)s"), {status: xhr.status, statusText: xhr.statusText}));
|
||
}
|
||
else {
|
||
tfm.tools.activateDatatables();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
function providerSelected(item)
|
||
{
|
||
compute_connection = $('#compute_connection');
|
||
var provider = $(item).val();
|
||
if(provider == "") {
|
||
compute_connection.hide();
|
||
$("[type=submit]").attr("disabled",true);
|
||
return false;
|
||
}
|
||
$("[type=submit]").attr("disabled",false);
|
||
var url = $(item).attr('data-url');
|
||
var data = 'provider=' + provider;
|
||
compute_connection.show();
|
||
compute_connection.load(url + ' div#compute_connection', data, function () {
|
||
password_caps_lock_hint()
|
||
});
|
||
function providerSelected(item) {
|
||
tfm.tools.deprecate('providerSelected', 'tfm.computeResource.providerSelected');
|
||
tfm.computeResource.providerSelected(item);
|
||
}
|
||
|
||
function testConnection(item) {
|
||
var cr_id = $("form").data('id');
|
||
|
||
if(cr_id === undefined || cr_id === null) {
|
||
cr_id = '';
|
||
}
|
||
|
||
var password = $("input#compute_resource_password").val();
|
||
$('.tab-error').removeClass('tab-error');
|
||
$('#test_connection_indicator').show();
|
||
$.ajax({
|
||
type:'put',
|
||
url: $(item).attr('data-url'),
|
||
data: $('form').serialize() + '&cr_id=' + cr_id,
|
||
success:function (result) {
|
||
var res = $('<div>' + result + '</div>');
|
||
$('#compute_connection').html(res.find("#compute_connection"));
|
||
$('#compute_connection').prepend(res.find(".alert"));
|
||
if (!$("#compute_resource_provider").prop('disabled')) {
|
||
$("#compute_resource_password").prop('disabled', false);
|
||
}
|
||
if ( ($('.alert-danger', result).length == 0) &&
|
||
($('#compute_connection .has-error', result).length == 0) ) {
|
||
notify("<p>" + __("Test connection was successful") + "</p>", 'success')
|
||
}
|
||
},
|
||
error:function (xhr) {
|
||
notify("<p>" + __("An error occurred while testing the connection: ") + xhr.statusText + "</p>", 'danger')
|
||
},
|
||
complete:function (result) {
|
||
//we need to restore the password field as it is not sent back from the server.
|
||
$("input#compute_resource_password").val(password);
|
||
$('#test_connection_indicator').hide();
|
||
reloadOnAjaxComplete('#test_connection_indicator');
|
||
}
|
||
});
|
||
}
|
||
|
||
function ovirt_templateSelected(item){
|
||
var template = $(item).val();
|
||
if (!item.disabled) {
|
||
var url = $(item).attr('data-url');
|
||
tfm.tools.showSpinner();
|
||
$.ajax({
|
||
type:'post',
|
||
url: url,
|
||
data:'template_id=' + template,
|
||
success: function(result){
|
||
$('[id$=_memory]').val(result.memory);
|
||
$('[id$=_cores]').val(result.cores);
|
||
$('#network_interfaces').children('.fields').remove();
|
||
$.each(result.interfaces, function() {add_network_interface(this);});
|
||
$('#storage_volumes .children_fields >.fields').remove();
|
||
$.each(result.volumes, function() {add_volume(this);});
|
||
templateSelector = $("#host_compute_attributes_template");
|
||
if (templateSelector.is(':disabled')) {
|
||
templateSelector.val(result.id).trigger("change");
|
||
}
|
||
},
|
||
complete: function(){
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// fill in the template interfaces.
|
||
function add_network_interface(item){
|
||
var nested_fields = $("#network_interfaces .add_nested_fields");
|
||
// no network interfaces update when the network editing is not allowed by the compute resource
|
||
if (nested_fields.length > 0) {
|
||
var new_id = add_child_node(nested_fields);
|
||
$('[id$='+new_id+'_name]').val(item.name);
|
||
$('[id$='+new_id+'_network]').val(item.network);
|
||
}
|
||
}
|
||
|
||
// fill in the template volumes.
|
||
function add_volume(item){
|
||
var new_id = add_child_node($("#storage_volumes .add_nested_fields"));
|
||
disable_element($('[id$='+new_id+'_size_gb]').val(item.size_gb));
|
||
disable_element($('[id$='+new_id+'_storage_domain]').val(item.storage_domain));
|
||
disable_element( $('[id$='+new_id+'_bootable_true]').attr('checked', item.bootable));
|
||
if (item.id) {
|
||
$('[id$=' + new_id + '_id]').val(item.id);
|
||
}
|
||
$('[id$='+new_id+'_storage_domain]').next().hide();
|
||
}
|
||
|
||
function disable_element(element){
|
||
element.clone().attr('type','hidden').appendTo(element);
|
||
element.attr('disabled', 'disabled');
|
||
}
|
||
function bootable_radio(item){
|
||
var $disabled = $('[id$=_bootable_true]:disabled:checked:visible');
|
||
$('[id$=_bootable_true]').prop('checked', false);
|
||
if ($disabled.length > 0){
|
||
$disabled.prop('checked', true);
|
||
} else {
|
||
$(item).prop('checked', true);
|
||
}
|
||
}
|
||
|
||
function ovirt_clusterSelected(item){
|
||
var cluster = $(item).val();
|
||
var url = $(item).attr('data-url');
|
||
tfm.tools.showSpinner();
|
||
$.ajax({
|
||
type:'post',
|
||
url: url,
|
||
data:'cluster_id=' + cluster,
|
||
success: function(result){
|
||
var network_options = $("select[id$=_network]").empty();
|
||
$.each(result, function() {
|
||
network_options.append($("<option />").val(this.id).text(this.name));
|
||
});
|
||
},
|
||
complete: function(){
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
})
|
||
}
|
||
|
||
function ovirt_datacenterSelected(item){
|
||
testConnection($('#test_connection_button'));
|
||
}
|
||
|
||
function libvirt_network_selected(item){
|
||
selected = $(item).val();
|
||
dropdown = $(item).closest('select');
|
||
bridge = $(item).parentsUntil('.fields').parent().find('#bridge');
|
||
nat = $(item).parentsUntil('.fields').parent().find('#nat');
|
||
switch (selected) {
|
||
case '':
|
||
disable_libvirt_dropdown(bridge);
|
||
disable_libvirt_dropdown(nat);
|
||
break;
|
||
case 'network':
|
||
disable_libvirt_dropdown(bridge);
|
||
enable_libvirt_dropdown(nat);
|
||
break;
|
||
case 'bridge':
|
||
disable_libvirt_dropdown(nat);
|
||
enable_libvirt_dropdown(bridge);
|
||
break;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function disable_libvirt_dropdown(item){
|
||
item.hide();
|
||
item.attr("disabled",true);
|
||
}
|
||
|
||
function enable_libvirt_dropdown(item){
|
||
item.attr("disabled",false);
|
||
item.find(':input').attr('disabled',false)
|
||
item.show();
|
||
}
|
||
|
||
function libvirt_image_selected(item){
|
||
var template = $(item).val();
|
||
if (template) {
|
||
var url = $(item).attr('data-url');
|
||
tfm.tools.showSpinner();
|
||
$.ajax({
|
||
type:'post',
|
||
url: url,
|
||
data:'template_id=' + template,
|
||
success: function(result){
|
||
capacity = $('#storage_volumes').children('.fields').find('[id$=capacity]')[0];
|
||
if (parseInt(capacity.value.slice(0, -1), 10) < parseInt(result.capacity, 10))
|
||
capacity.value = result.capacity + 'G';
|
||
$('#storage_volumes').children('.fields').find('[id$=format_type]')[0].value = 'qcow2';
|
||
},
|
||
complete: function(){
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
function ec2_vpcSelected(form){
|
||
sg_select = $('select.security_group_ids')
|
||
sg_select.empty();
|
||
security_groups = jQuery.parseJSON( sg_select.attr('data-security-groups') );
|
||
subnets = jQuery.parseJSON( sg_select.attr('data-subnets') );
|
||
if(form.value != ''){
|
||
vpc=subnets[form.value]
|
||
} else {
|
||
vpc = {'vpc_id': 'ec2', 'subnet_name': 'ec2'};
|
||
}
|
||
for(sg in security_groups[vpc.vpc_id]){
|
||
sg_select.append($('<option />').val(security_groups[vpc.vpc_id][sg].group_id).text(security_groups[vpc.vpc_id][sg].group_name+' - '+vpc.subnet_name));
|
||
}
|
||
sg_select.multiSelect("refresh");
|
||
}
|
||
|
||
function capacity_edit(element) {
|
||
var buttons = $(element).closest('.fields').find('button[name=allocation_radio_btn].btn.active');
|
||
if (buttons.length > 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 previous = $(element).parent().find('.active');
|
||
previous.removeClass('active');
|
||
|
||
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;
|
||
}
|
||
|
||
$(element).button('toggle');
|
||
return false;
|
||
}
|
||
|
||
function vsphereGetResourcePools(item) {
|
||
var data = {cluster_id: $(item).val()};
|
||
var url = $(item).data('url');
|
||
tfm.tools.showSpinner();
|
||
selectbox = $('select[id$="resource_pool"]');
|
||
selectbox.select2('destroy').empty();
|
||
$.ajax({
|
||
type: 'get',
|
||
url: url,
|
||
data: data,
|
||
complete: function() { tfm.tools.hideSpinner();},
|
||
success: function(request) {
|
||
for (var i = 0; i < request.length; i++) {
|
||
var option = request[i].name;
|
||
$('<option>').text(option).val(option).appendTo(selectbox);
|
||
}
|
||
$(selectbox).select2();
|
||
}
|
||
})
|
||
}
|
||
|
||
function vsphereStoragePodSelected(item) {
|
||
selected = $(item).val();
|
||
datastore = $('select[id*=datastore]')
|
||
if(!selected || 0 === selected.length) {
|
||
enable_vsphere_dropdown(datastore);
|
||
} else {
|
||
disable_vsphere_dropdown(datastore);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function vsphereStoragePodLoad() {
|
||
items = $('select[id*=storage_pod]');
|
||
if(items.length < 1) {
|
||
return false;
|
||
}
|
||
items.each(function() {
|
||
selected = $(this).val();
|
||
if(selected || ! (0 === selected.length)) {
|
||
datastore = $('select[id*=datastore]');
|
||
disable_vsphere_dropdown(datastore);
|
||
}
|
||
});
|
||
return false;
|
||
}
|
||
|
||
$(document).on('ContentLoad', function(){vsphereStoragePodLoad()});
|
||
|
||
function disable_vsphere_dropdown(item){
|
||
item.attr("disabled", true);
|
||
tfm.tools.deprecate('testConnection', 'tfm.computeResource.testConnection');
|
||
tfm.computeResource.testConnection(item);
|
||
}
|
||
|
||
function enable_vsphere_dropdown(item){
|
||
item.attr("disabled", false);
|
||
function capacity_edit(item) {
|
||
tfm.tools.deprecate('capacity_edit', 'tfm.computeResource.capacityEdit');
|
||
tfm.computeResource.capacityEdit(item);
|
||
}
|
app/assets/javascripts/compute_resources/openstack/host_edit.js | ||
---|---|---|
function schedulerHintFilterSelected(item){
|
||
var filter = $(item).val();
|
||
if (filter == '') {
|
||
$('#scheduler_hint_wrapper').empty();
|
||
} else {
|
||
var url = $(item).attr('data-url');
|
||
var data = serializeForm().replace('method=patch', 'method=post');
|
||
tfm.tools.showSpinner();
|
||
$.ajax({
|
||
type:'post',
|
||
url: url,
|
||
data: data,
|
||
complete: function(){
|
||
tfm.tools.hideSpinner();
|
||
},
|
||
error: function(jqXHR, status, error){
|
||
$('#scheduler_hint_wrapper').html(Jed.sprintf(__("Error loading scheduler hint filters information: %s"), error));
|
||
$('#compute_resource_tab a').addClass('tab-error');
|
||
},
|
||
success: function(result){
|
||
$('#scheduler_hint_wrapper').html(result);
|
||
}
|
||
})
|
||
}
|
||
}
|
app/assets/javascripts/host_edit.js | ||
---|---|---|
if (image_options.find('option').length > 0) {
|
||
if ($('#host_provision_method_image')[0].checked) {
|
||
if ($('#provider').val() == 'Libvirt') {
|
||
libvirt_image_selected(image_options);
|
||
tfm.computeResource.libvirt.imageSelected(image_options);
|
||
} else if ($('#provider').val() == 'Ovirt') {
|
||
var template_select = $('#host_compute_attributes_template');
|
||
if (template_select.length > 0) {
|
||
template_select.val(image_options.val());
|
||
ovirt_templateSelected(image_options);
|
||
tfm.computeResource.ovirt.templateSelected(image_options);
|
||
}
|
||
}
|
||
}
|
||
... | ... | |
var image_options = $('#image_selection select');
|
||
image_options.attr('disabled', false);
|
||
if ($('#provider').val() == 'Libvirt') {
|
||
libvirt_image_selected(image_options);
|
||
tfm.computeResource.libvirt.imageSelected(image_options);
|
||
} else if ($('#provider').val() == 'Ovirt') {
|
||
var template_options = $('#host_compute_attributes_template');
|
||
if (template_options.length > 0) {
|
||
template_options.attr('disabled', true);
|
||
template_options.val(image_options.val());
|
||
ovirt_templateSelected(image_options);
|
||
tfm.computeResource.ovirt.templateSelected(image_options);
|
||
}
|
||
}
|
||
}
|
app/helpers/compute_resources_helper.rb | ||
---|---|---|
caption ||= _("Test Connection")
|
||
btn_class = success ? 'btn-success' : 'btn-default'
|
||
spinner_class = success ? 'spinner-inverse' : nil
|
||
spinner_button_f(f, caption, "testConnection(this)",
|
||
spinner_button_f(f, caption, "tfm.computeResource.testConnection(this)",
|
||
:id => 'test_connection_button',
|
||
:spinner_id => 'test_connection_indicator',
|
||
:class => btn_class,
|
app/helpers/hosts_helper.rb | ||
---|---|---|
content_tag :button, _(label), :type => 'button', :href => '#',
|
||
:name => 'allocation_radio_btn',
|
||
:class => (label == active) ? 'btn btn-default active' : 'btn btn-default',
|
||
:onclick => "allocation_switcher(this, '#{label}');",
|
||
:onclick => "tfm.computeResource.libvirt.allocationSwitcher(this, '#{label}');",
|
||
:data => { :toggle => 'button' }
|
||
end.join(' ').html_safe
|
||
end)
|
app/views/compute_attributes/_form.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
<%= form_for([@set.compute_profile, @set]) do |f| %>
|
||
<%= base_errors_for @set %>
|
||
|
app/views/compute_profiles/index.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
|
||
<% title _('Compute Profiles') %>
|
||
|
||
<% title_actions new_link(_('Create Compute Profile')),
|
app/views/compute_profiles/show.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
<% title(_("Edit Compute profile: %s") % @compute_profile.name) %>
|
||
|
||
<% title_actions display_link_if_authorized(_("Back"), hash_for_compute_profiles_path, :class => 'btn btn-default') %>
|
app/views/compute_resources/_form.html.erb | ||
---|---|---|
<%= javascript "compute_resource" %>
|
||
<%= form_for @compute_resource, :html => {:data => {:id => @compute_resource.try(:id)}} do |f| %>
|
||
<%= base_errors_for @compute_resource %>
|
||
<ul class="nav nav-tabs" data-tabs="tabs">
|
||
... | ... | |
<%= text_f f, :name %>
|
||
<%= f.hidden_field(:provider, :id => '') if f.object.uuid.present? %>
|
||
<%= selectable_f f, :provider, list_providers, { :include_blank => _("Choose a provider")},
|
||
{:label => _("Provider"), :disabled=> !f.object.new_record?, :'data-url'=> provider_selected_compute_resources_path, :onchange => 'providerSelected(this);'} %>
|
||
{:label => _("Provider"), :disabled=> !f.object.new_record?, :'data-url'=> provider_selected_compute_resources_path, :onchange => 'tfm.computeResource.providerSelected(this);'} %>
|
||
<%= textarea_f f, :description, :rows => 3 %>
|
||
<div id='compute_connection'>
|
||
<%= render "compute_resources/form/#{@compute_resource.provider.downcase}", :f => f unless @compute_resource.provider.empty? %>
|
app/views/compute_resources/form/_ovirt.html.erb | ||
---|---|---|
<%= password_f f, :password, :keep_value => true, :unset => unset_password? %>
|
||
<% datacenters = (f.object.uuid.nil? && controller.action_name != 'test_connection') ? [] : f.object.datacenters rescue []%>
|
||
<%= selectable_f(f, :uuid, datacenters, {}, {:label => _('Datacenter'),
|
||
:onchange => 'ovirt_datacenterSelected();',
|
||
:onchange => 'tfm.computeResource.ovirt.datacenterSelected();',
|
||
:help_inline_permanent => load_datacenters_button_f(f, !datacenters.empty?) }) %>
|
||
<% quotas = (f.object.uuid.nil? && controller.action_name != 'test_connection') ? [] : f.object.quotas.all rescue []%>
|
||
<%= select_f f, :ovirt_quota, quotas, :id, :name, {}, :label => _("Quota ID") %>
|
app/views/compute_resources/show.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
<% title @compute_resource.name %>
|
||
|
||
<% title_actions display_link_if_authorized(_("Associate VMs"),
|
app/views/compute_resources_vms/form/ec2/_base.html.erb | ||
---|---|---|
<% if compute_resource.subnets.any? %>
|
||
<%= select_f f, :subnet_id, compute_resource.subnets, :subnet_id, :cidr_block,
|
||
{:include_blank => _("EC2")},
|
||
{:label => _("Subnet"), :label_size => "col-md-2", :onchange => "ec2_vpcSelected(this);"} %>
|
||
{:label => _("Subnet"), :label_size => "col-md-2", :onchange => "tfm.computeResource.ec2.vpcSelected(this);"} %>
|
||
<% end %>
|
||
|
||
<% groups, vpc_sg_hash, subnet_vpc_hash = security_groups_selectable(compute_resource, f) %>
|
app/views/compute_resources_vms/form/gce/_volume.html.erb | ||
---|---|---|
<%= text_f f, :size_gb, :class => "col-md-2", :label => _("Size (GB)"), :label_size => "col-md-2", :onchange => 'capacity_edit(this)' %>
|
||
<%= text_f f, :size_gb, :class => "col-md-2", :label => _("Size (GB)"), :label_size => "col-md-2", :onchange => 'tfm.computeResource.capacityEdit(this)' %>
|
app/views/compute_resources_vms/form/libvirt/_base.html.erb | ||
---|---|---|
<%= select_f f, :image_id, images, :uuid, :name,{:include_blank => (images.empty? || images.size == 1) ? false : _('Please select an image')},
|
||
{ :disabled => images.empty? || (params[:host] && params[:host][:provision_method] == 'build'),
|
||
:'data-url' => template_selected_compute_resource_path(compute_resource),
|
||
:onchange => 'libvirt_image_selected(this);',
|
||
:onchange => 'tfm.computeResource.libvirt.imageSelected(this);',
|
||
:help_inline => :indicator,
|
||
:help_block => _("Image to use"),
|
||
:label => _('Image'), :label_size => "col-md-2"} %>
|
app/views/compute_resources_vms/form/libvirt/_network.html.erb | ||
---|---|---|
<%= selectable_f f, :type, libvirt_networks(compute_resource), {},
|
||
{ :label => _('Network type'),
|
||
:disabled => !new_vm,
|
||
:onchange => 'libvirt_network_selected(this)',
|
||
:onchange => 'tfm.computeResource.libvirt.networkSelected(this)',
|
||
:class => 'libvirt_network',
|
||
:label_size => "col-md-3"
|
||
} %>
|
app/views/compute_resources_vms/form/libvirt/_volume.html.erb | ||
---|---|---|
|
||
<%= selectable_f f, :pool_name, compute_resource.storage_pools.map(&:name), { }, :label => _("Storage pool"), :label_size => "col-md-2" %>
|
||
<%= text_f f, :capacity, :label => _("Size (GB)"), :onchange => 'capacity_edit(this)', :label_size => "col-md-2" %>
|
||
<%= text_f f, :capacity, :label => _("Size (GB)"), :onchange => 'tfm.computeResource.capacityEdit(this)', :label_size => "col-md-2" %>
|
||
<%= allocation_text_f f %>
|
||
<%= select_f f, :format_type, %w[RAW QCOW2],:downcase, :to_s, { }, :label => _("Type"), :label_size => "col-md-2" %>
|
app/views/compute_resources_vms/form/openstack/_base.html.erb | ||
---|---|---|
<%= checkbox_f f, :boot_from_volume, {:label => _("Boot from volume"), :label_size => "col-md-2", :help_inline => _("Create new boot volume from image")}, "true", "false" %>
|
||
<%= text_f f, :size_gb, { :label => _("New boot volume size (GB)"), :label_size => "col-md-2", :help_inline => _("Defaults to image size if left blank") } %>
|
||
<%= selectable_f f, :scheduler_hint_filter, compute_resource.possible_scheduler_hints, { include_blank: 'None' }, { :label => _("Scheduler hint filter"), :label_size => "col-md-2", :'data-url' => scheduler_hint_selected_hosts_path,
|
||
:onchange => 'schedulerHintFilterSelected(this);', :disabled => !new_vm } %>
|
||
:onchange => 'tfm.computeResource.openstack.schedulerHintFilterSelected(this);', :disabled => !new_vm } %>
|
||
<div id="scheduler_hint_wrapper">
|
||
<%= if @host && @host.compute_attributes && @host.compute_attributes[:scheduler_hint_filter].present?
|
||
render :partial => "compute_resources_vms/form/scheduler_hint_filters", :locals => { :compute_resource => compute_resource, :host => @host, :new_vm => new_vm }
|
app/views/compute_resources_vms/form/ovirt/_base.html.erb | ||
---|---|---|
<%= javascript_tag("$(document).on('ContentLoad', tfm.numFields.initAll)"); %>
|
||
|
||
<% javascript 'compute_resource' %>
|
||
<%= text_f f, :name, :label => _('Name'), :label_size => "col-md-3" if show_vm_name? %>
|
||
<% clusters = compute_resource.clusters %>
|
||
<%= select_f f, :cluster, clusters, :id, :name, { },
|
||
{ :disabled => !new_vm, :'data-url' => cluster_selected_compute_resource_path(compute_resource),
|
||
:onchange => 'ovirt_clusterSelected(this);',
|
||
:onchange => 'tfm.computeResource.ovirt.clusterSelected(this);',
|
||
:help_inline => :indicator,
|
||
:label => _('Cluster'), :label_size => "col-md-2" } %>
|
||
<%= f.hidden_field :cluster if !new_vm %>
|
||
<%= select_f f, :template, compute_resource.templates, :id, :full_name, {:include_blank => _("Select template")},
|
||
{ :disabled => !new_vm, :'data-url' => template_selected_compute_resource_path(compute_resource),
|
||
:onchange => 'ovirt_templateSelected(this);',
|
||
:onchange => 'tfm.computeResource.ovirt.templateSelected(this);',
|
||
:help_inline => :indicator,
|
||
:help_block => _("oVirt/RHEV template to use"),
|
||
:label => _('Template'), :label_size => "col-md-2" } %>
|
||
... | ... | |
<div id='image_selection'>
|
||
<%= select_f f, :image_id, images, :uuid, :name,{:include_blank => (images.empty? || images.size == 1) ? false : _('Please select an image')},
|
||
{ :disabled => true, :'data-url' => template_selected_compute_resource_path(compute_resource),
|
||
:onchange => 'ovirt_templateSelected(this);',
|
||
:onchange => 'tfm.computeResource.ovirt.templateSelected(this);',
|
||
:help_inline => :indicator,
|
||
:help_block => _("Image to use"),
|
||
:label => _('Image'), :label_size => "col-md-2"} %>
|
app/views/compute_resources_vms/form/ovirt/_volume.html.erb | ||
---|---|---|
<%= checkbox_f f, :preallocate, { :checked => f.object.sparse == 'false', :help_inline => _('Uses thin provisioning if unchecked'), :label => _('Preallocate disk'), :label_size => "col-md-2" } %>
|
||
|
||
<%= field(f, :bootable, :label => _('Bootable'), :label_size => "col-md-2") do
|
||
radio_button_f f, :bootable, {:disabled => !new_vm, :value=>'true', :checked => (f.object.bootable == 'true'), :onclick => 'bootable_radio(this)',
|
||
radio_button_f f, :bootable, {:disabled => !new_vm, :value=>'true', :checked => (f.object.bootable == 'true'), :onclick => 'tfm.computeResource.ovirt.bootableRadio(this)',
|
||
:text => _('Only one volume can be bootable')}
|
||
end %>
|
app/views/compute_resources_vms/form/vmware/_base.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
<%= javascript_tag("$(document).on('ContentLoad', tfm.numFields.initCounter)"); %>
|
||
<%= text_f f, :name, :label => _('Name'), :disabled => !new_vm if show_vm_name? %>
|
||
<%= counter_f f, :cpus, :label => _('CPUs'), :label_size => 'col-md-2', :'data-soft-max' => compute_resource.max_cpu_count %>
|
||
... | ... | |
end %>
|
||
<%= selectable_f f, :cluster, compute_resource.clusters, { :include_blank => _('Please select a cluster') },
|
||
:class => "col-md-2", :disabled => !new_vm,
|
||
:label => _('Cluster'), :onchange => 'vsphereGetResourcePools(this)',
|
||
:label => _('Cluster'), :onchange => 'tfm.computeResource.vmware.getResourcePools(this)',
|
||
:help_inline => :indicator,
|
||
:data => {:url => resource_pools_compute_resource_path(compute_resource)} %>
|
||
<%= vsphere_resource_pools(f, compute_resource, !new_vm) %>
|
app/views/compute_resources_vms/new.html.erb | ||
---|---|---|
<%= javascript 'compute_resource' %>
|
||
<% title _("New Virtual Machine") %>
|
||
|
||
<%= form_tag compute_resource_vms_path(@compute_resource) do %>
|
app/views/hosts/_form.html.erb | ||
---|---|---|
<%= javascript 'hosts', 'host_edit', 'host_edit_interfaces', 'class_edit', 'compute_resource', 'charts' %>
|
||
<%= javascript 'hosts', 'host_edit', 'host_edit_interfaces', 'class_edit', 'charts' %>
|
||
<%= render "hosts/dhcp_lease_errors" if has_dhcp_lease_errors?(@host.errors) %>
|
||
<%= render "hosts/conflicts" if (!has_dhcp_lease_errors?(@host.errors) && has_conflicts?(@host.errors)) %>
|
||
<%= render "hosts/progress" %>
|
config/initializers/assets.rb | ||
---|---|---|
|
||
# config.assets.precompile += %w()
|
||
javascript = %w(compute_resource
|
||
compute_resources/openstack/host_edit
|
||
compute_resources/libvirt/nic_info
|
||
compute_resources/ovirt/nic_info
|
||
compute_resources/vmware/nic_info
|
webpack/assets/javascripts/bundle.js | ||
---|---|---|
require('./bundle_multiselect');
|
||
require('./bundle_select2');
|
||
require('./bundle_datatables');
|
||
import compute from './foreman_compute_resource';
|
||
|
||
window.tfm = Object.assign(
|
||
window.tfm || {},
|
||
{
|
||
tools: require('./foreman_tools'),
|
||
users: require('./foreman_users'),
|
||
computeResource: compute,
|
||
sshKeys: require('./foreman_ssh_keys'),
|
||
trends: require('./foreman_trends'),
|
||
hostgroups: require('./foreman_hostgroups'),
|
webpack/assets/javascripts/compute_resource/ec2.js | ||
---|---|---|
import $ from 'jquery';
|
||
|
||
export function vpcSelected({ value }) {
|
||
const sgSelect = $('select.security_group_ids');
|
||
const securityGroups = JSON.parse(sgSelect.attr('data-security-groups'));
|
||
const subnets = JSON.parse(sgSelect.attr('data-subnets'));
|
||
// eslint-disable-next-line camelcase
|
||
const vpc = value !== '' ? subnets[value] : { vpc_id: 'ec2', subnet_name: 'ec2' };
|
||
|
||
sgSelect.empty();
|
||
|
||
// eslint-disable-next-line camelcase
|
||
securityGroups[vpc.vpc_id].forEach(({ group_id, group_name }) => {
|
||
// eslint-disable-next-line camelcase
|
||
sgSelect.append($('<option />').val(group_id).text(`${group_name} - ${vpc.subnet_name}`));
|
||
});
|
||
sgSelect.multiSelect('refresh');
|
||
}
|
webpack/assets/javascripts/compute_resource/libvirt.js | ||
---|---|---|
import $ from 'jquery';
|
||
import { showSpinner } from '../foreman_tools';
|
||
|
||
export function networkSelected(item) {
|
||
const selected = $(item).val();
|
||
const bridge = $(item).parentsUntil('.fields').parent().find('#bridge');
|
||
const nat = $(item).parentsUntil('.fields').parent().find('#nat');
|
||
|
||
switch (selected) {
|
||
case '':
|
||
disableDropdown(bridge);
|
||
disableDropdown(nat);
|
||
break;
|
||
case 'network':
|
||
disableDropdown(bridge);
|
||
enableDropdown(nat);
|
||
break;
|
||
case 'bridge':
|
||
disableDropdown(nat);
|
||
enableDropdown(bridge);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function disableDropdown(item) {
|
||
item.hide();
|
||
item.attr('disabled', true);
|
||
}
|
||
|
||
function enableDropdown(item) {
|
||
item.attr('disabled', false);
|
||
item.find(':input').attr('disabled', false);
|
||
item.show();
|
||
}
|
||
|
||
export function imageSelected(item) {
|
||
const template = $(item).val();
|
||
|
||
if (template) {
|
||
const url = $(item).attr('data-url');
|
||
|
||
showSpinner();
|
||
$.ajax({
|
||
type: 'post',
|
||
url,
|
||
data: `template_id=${template}`,
|
||
success(result) {
|
||
let capacity = $('#storage_volumes').children('.fields').find('[id$=capacity]')[0];
|
||
|
||
if (parseInt(capacity.value.slice(0, -1), 10) < parseInt(result.capacity, 10)) {
|
||
capacity.value = `${result.capacity}G`;
|
||
}
|
||
$('#storage_volumes').children('.fields').find('[id$=format_type]')[0].value = 'qcow2';
|
||
},
|
||
complete() {
|
||
// eslint-disable-next-line no-undef
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
export function allocationSwitcher(element, action) {
|
||
const previous = $(element).parent().find('.active');
|
||
|
||
previous.removeClass('active');
|
||
|
||
const capacity = $(element).closest('.fields').find('[id$=capacity]')[0];
|
||
let allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
|
||
|
||
switch (action) {
|
||
case 'None':
|
||
$(allocation).attr('readonly', 'readonly');
|
||
allocation.value = '0G';
|
||
break;
|
||
case 'Size':
|
||
$(allocation).removeAttr('readonly');
|
||
allocation.value = '';
|
||
$(allocation).focus();
|
||
break;
|
||
case 'Full':
|
||
$(allocation).attr('readonly', 'readonly');
|
||
allocation.value = capacity.value;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
$(element).button('toggle');
|
||
return false;
|
||
}
|
webpack/assets/javascripts/compute_resource/openstack.js | ||
---|---|---|
import $ from 'jquery';
|
||
import { showSpinner, hideSpinner } from '../foreman_tools';
|
||
|
||
export function schedulerHintFilterSelected(item) {
|
||
let filter = $(item).val();
|
||
|
||
if (filter === '') {
|
||
$('#scheduler_hint_wrapper').empty();
|
||
} else {
|
||
let url = $(item).attr('data-url');
|
||
// eslint-disable-next-line no-undef
|
||
let data = serializeForm().replace('method=patch', 'method=post');
|
||
|
||
showSpinner();
|
||
$.ajax({
|
||
type: 'post',
|
||
url,
|
||
data,
|
||
complete() {
|
||
hideSpinner();
|
||
},
|
||
error(jqXHR, status, error) {
|
||
$('#scheduler_hint_wrapper').html(
|
||
// eslint-disable-next-line no-undef
|
||
Jed.sprintf(__('Error loading scheduler hint filters information: %s'), error)
|
||
);
|
||
$('#compute_resource_tab a').addClass('tab-error');
|
||
},
|
||
success(result) {
|
||
$('#scheduler_hint_wrapper').html(result);
|
||
}
|
||
});
|
||
}
|
||
}
|
webpack/assets/javascripts/compute_resource/ovirt.js | ||
---|---|---|
import $ from 'jquery';
|
||
import { showSpinner } from '../foreman_tools';
|
||
import { testConnection } from '../foreman_compute_resource';
|
||
|
||
export function templateSelected(item) {
|
||
const template = $(item).val();
|
||
|
||
if (!item.disabled) {
|
||
const url = $(item).attr('data-url');
|
||
|
||
showSpinner();
|
||
$.ajax({
|
||
type: 'post',
|
||
url,
|
||
data: `template_id=${template}`,
|
||
success(result) {
|
||
$('[id$=_memory]').val(result.memory);
|
||
$('[id$=_cores]').val(result.cores);
|
||
$('#network_interfaces').children('.fields').remove();
|
||
$.each(result.interfaces, function () {
|
||
addNetworkInterface(this);
|
||
});
|
||
$('#storage_volumes .children_fields >.fields').remove();
|
||
$.each(result.volumes, function () {
|
||
addVolume(this);
|
||
});
|
||
const templateSelector = $('#host_compute_attributes_template');
|
||
|
||
if (templateSelector.is(':disabled')) {
|
||
templateSelector.val(result.id).trigger('change');
|
||
}
|
||
},
|
||
complete() {
|
||
// eslint-disable-next-line no-undef
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// fill in the template interfaces.
|
||
function addNetworkInterface({ name, network }) {
|
||
const nestedFields = $('#network_interfaces .add_nested_fields');
|
||
// no network interfaces update when the network editing is not allowed by the compute resource
|
||
|
||
if (nestedFields.length > -1) {
|
||
// eslint-disable-next-line no-undef
|
||
const newId = add_child_node(nestedFields);
|
||
|
||
$(`[id$=${newId}_name]`).val(name);
|
||
$(`[id$=${newId}_network]`).val(network);
|
||
}
|
||
}
|
||
|
||
// fill in the template volumes.
|
||
// eslint-disable-next-line camelcase
|
||
function addVolume({ size_gb, storage_domain, bootable, id }) {
|
||
// eslint-disable-next-line no-undef
|
||
const newId = add_child_node($('#storage_volumes .add_nested_fields'));
|
||
|
||
disableElement($(`[id$=${newId}_size_gb]`).val(size_gb));
|
||
disableElement($(`[id$=${newId}_storage_domain]`).val(storage_domain));
|
||
disableElement($(`[id$=${newId}_bootable_true]`).attr('checked', bootable));
|
||
if (id) {
|
||
$(`[id$=${newId}_id]`).val(id);
|
||
}
|
||
$(`[id$=${newId}_storage_domain]`).next().hide();
|
||
}
|
||
|
||
function disableElement(element) {
|
||
element.clone().attr('type', 'hidden').appendTo(element);
|
||
element.attr('disabled', 'disabled');
|
||
}
|
||
|
||
export function bootableRadio(item) {
|
||
let disabled = $('[id$=_bootable_true]:disabled:checked:visible');
|
||
|
||
$('[id$=_bootable_true]').prop('checked', false);
|
||
if (disabled.length > 0) {
|
||
disabled.prop('checked', true);
|
||
} else {
|
||
$(item).prop('checked', true);
|
||
}
|
||
}
|
||
export function clusterSelected(item) {
|
||
const cluster = $(item).val();
|
||
const url = $(item).attr('data-url');
|
||
|
||
showSpinner();
|
||
$.ajax({
|
||
type: 'post',
|
||
url,
|
||
data: `cluster_id=${cluster}`,
|
||
success(result) {
|
||
let networkOptions = $('select[id$=_network]').empty();
|
||
|
||
$.each(result, function () {
|
||
networkOptions.append($('<option />').val(this.id).text(this.name));
|
||
});
|
||
},
|
||
complete() {
|
||
// eslint-disable-next-line no-undef
|
||
reloadOnAjaxComplete(item);
|
||
}
|
||
});
|
||
}
|
||
|
||
// used by test connection
|
||
export function datacenterSelected(item) {
|
||
// eslint-disable-next-line no-undef
|
||
testConnection($('#test_connection_button'));
|
||
}
|
webpack/assets/javascripts/compute_resource/vmware.js | ||
---|---|---|
import $ from 'jquery';
|
||
import { showSpinner, hideSpinner } from '../foreman_tools';
|
||
|
||
export function getResourcePools(item) {
|
||
// eslint-disable-next-line camelcase
|
||
const data = { cluster_id: $(item).val() };
|
||
let url = $(item).data('url');
|
||
|
||
showSpinner();
|
||
const selectbox = $('select[id$="resource_pool"]');
|
||
|
||
selectbox.select2('destroy').empty();
|
||
$.ajax({
|
||
type: 'get',
|
||
url,
|
||
data,
|
||
complete() {
|
||
hideSpinner();
|
||
},
|
||
success(request) {
|
||
request.forEach(({ name }) => {
|
||
$('<option>').text(name).val(name).appendTo(selectbox);
|
||
});
|
||
$(selectbox).select2();
|
||
}
|
||
});
|
||
}
|
webpack/assets/javascripts/foreman_compute_resource.js | ||
---|---|---|
import $ from 'jquery';
|
||
import { activateDatatables } from './foreman_tools';
|
||
import { notify } from './foreman_toast_notifications';
|
||
|
||
export default {
|
||
ec2: require('./compute_resource/ec2'),
|
||
libvirt: require('./compute_resource/libvirt'),
|
||
openstack: require('./compute_resource/openstack'),
|
||
ovirt: require('./compute_resource/ovirt'),
|
||
vmware: require('./compute_resource/vmware'),
|
||
capacityEdit,
|
||
providerSelected,
|
||
testConnection
|
||
};
|
||
|
||
// Common functions used by one or more Compute Resource
|
||
|
||
// AJAX load vm listing
|
||
$(() => {
|
||
$('#vms, #images_list, #key_pairs_list').filter('[data-url]').each(function () {
|
||
const url = $(this).attr('data-url');
|
||
|
||
$(this).load(`${url} table`, function (response, status, xhr) {
|
||
if (status === 'error') {
|
||
$(this).html(
|
||
// eslint-disable-next-line no-undef
|
||
Jed.sprintf(__('There was an error listing VMs: %(status)s %(statusText)s'), {
|
||
status: xhr.status,
|
||
statusText: xhr.statusText
|
||
})
|
||
);
|
||
} else {
|
||
activateDatatables();
|
||
}
|
||
});
|
||
});
|
||
});
|
||
|
||
// eslint-disable-next-line max-statements
|
||
export function providerSelected(item) {
|
||
const computeConnection = $('#compute_connection');
|
||
const provider = $(item).val();
|
||
|
||
if (provider === '') {
|
||
computeConnection.hide();
|
||
$('[type=submit]').attr('disabled', true);
|
||
return false;
|
||
}
|
||
$('[type=submit]').attr('disabled', false);
|
||
const url = $(item).attr('data-url');
|
||
const data = `provider=${provider}`;
|
||
|
||
computeConnection.show();
|
||
computeConnection.load(`${url} div#compute_connection`, data, () => {
|
||
// eslint-disable-next-line no-undef
|
||
password_caps_lock_hint();
|
||
});
|
||
|
||
return false;
|
||
}
|
||
|
||
export function testConnection(item) {
|
||
let crId = $('form').data('id');
|
||
|
||
if (crId === undefined || crId === null) {
|
||
crId = '';
|
||
}
|
||
|
||
let password = $('input#compute_resource_password').val();
|
||
|
||
$('.tab-error').removeClass('tab-error');
|
||
$('#test_connection_indicator').show();
|
||
$.ajax({
|
||
type: 'put',
|
||
url: $(item).attr('data-url'),
|
||
data: `${$('form').serialize()}&cr_id=${crId}`,
|
||
success(result) {
|
||
let res = $(`<div>${result}</div>`);
|
||
|
||
$('#compute_connection').html(res.find('#compute_connection'));
|
||
$('#compute_connection').prepend(res.find('.alert'));
|
||
if (!$('#compute_resource_provider').prop('disabled')) {
|
||
$('#compute_resource_password').prop('disabled', false);
|
||
}
|
||
if (
|
||
$('.alert-danger', result).length === 0 &&
|
||
$('#compute_connection .has-error', result).length === 0
|
||
) {
|
||
notify({ message: `<p>${__('Test connection was successful')}</p>`, type: 'success' });
|
||
}
|
||
},
|
||
error({ statusText }) {
|
||
notify({
|
||
message: `<p>${__('An error occurred while testing the connection: ')}${statusText}</p>`,
|
||
type: 'danger'
|
||
});
|
||
},
|
||
complete(result) {
|
||
// we need to restore the password field as it is not sent back from the server.
|
||
$('input#compute_resource_password').val(password);
|
||
$('#test_connection_indicator').hide();
|
||
// eslint-disable-next-line no-undef
|
||
reloadOnAjaxComplete('#test_connection_indicator');
|
||
}
|
||
});
|
||
}
|
||
|
||
export function capacityEdit(element) {
|
||
let buttons = $(element).closest('.fields').find('button[name=allocation_radio_btn].btn.active');
|
||
|
||
if (buttons.length > 0 && $(buttons[0]).text() === 'Full') {
|
||
let allocation = $(element).closest('.fields').find('[id$=allocation]')[0];
|
||
|
||
allocation.value = element.value;
|
||
}
|
||
return false;
|
||
}
|
Also available in: Unified diff
fixes #20652 - moved compute_resource js code to webpack
this creates a new namespace under tfm, tfm.computeResource
where relevant functions are expoed under the compute resource
namespace, for example:
tfm.computeResource.ovirt.termplateSelected function
Additional common functions are also exposed under the same namespace:
tfm.computeResource.providerSelected
I left the host form NIC code out of this PR as it actually requires
code changes, changes in this PR are comsetic (mostly linting) and
convertion to ES6.