| @@ -1,4 +1,3 @@ | ||
| <%= form_for([@set.compute_profile, @set]) do |f| %> | ||
| <%= base_errors_for @set %> | ||
| @@ -1,5 +1,3 @@ | ||
| <% title _('Compute Profiles') %> | ||
| <% title_actions new_link(_('Create Compute Profile')), | ||
| @@ -1,4 +1,3 @@ | ||
| <% title @compute_resource.name %> | ||
| <% title_actions display_link_if_authorized(_("Associate VMs"), | ||
| @@ -1 +1 @@ | ||
| <%= text_f f, :size_gb, :class => "col-md-2", :label => _("Size (GB)"), :label_size => "col-md-2", :onchange => 'tfm.computeResource.capacityEdit(this)' %> |
| @@ -1,5 +1,5 @@ | ||
| <%= 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 => '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" %> |
| @@ -1,4 +1,3 @@ | ||
| <% title _("New Virtual Machine") %> | ||
| <%= form_tag compute_resource_vms_path(@compute_resource) do %> | ||
| @@ -9,7 +9,6 @@ | ||
|
|
||
| # config.assets.precompile += %w() | ||
| javascript = %w(compute_resource | ||
| compute_resources/libvirt/nic_info | ||
| compute_resources/ovirt/nic_info | ||
| compute_resources/vmware/nic_info | ||
| @@ -0,0 +1,18 @@ | ||
| 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'); | ||
| } |
| @@ -0,0 +1,94 @@ | ||
| 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; | ||
| } |
| @@ -0,0 +1,34 @@ | ||
| 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); | ||
| } | ||
| }); | ||
| } | ||
| } |
| @@ -0,0 +1,112 @@ | ||
| 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')); | ||
| } |
| @@ -0,0 +1,27 @@ | ||
| 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(); | ||
| } | ||
| }); | ||
| } |
| @@ -0,0 +1,117 @@ | ||
| 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; | ||
| } |