Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconfigure VM: Add / Remove Network Adapters #3121

Merged
merged 4 commits into from Apr 6, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -14,14 +14,18 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
hdUnit: 'MB',
new_controller_type: 'VirtualLsiLogicController',
cb_dependent: true,
nicsEnabled: false,
addEnabled: false,
enableAddDiskButton: true,
enableAddNetworkAdapterButton: true,
cb_bootable: false,
vmAddDisks: [],
vmRemoveDisks: [],
vmResizeDisks: [],
vLan_requested: '',
};
vm.cb_disks = false;
vm.cb_networkAdapters = false;
vm.hdpattern = '^[1-9][0-9]*$';
vm.reconfigureFormId = reconfigureFormId;
vm.afterGet = false;
Expand Down Expand Up @@ -61,6 +65,11 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
vm.reconfigureModel.enableAddDiskButton = (nrDisksAfterReconfigure < 4);
};

vm.setEnableAddNetworkAdapterButton = function() {
var nrNetworksAfterReconfigure = _.reject(vm.reconfigureModel.vmNetworkAdapters, { add_remove: 'remove' }).length;
vm.reconfigureModel.enableAddNetworkAdapterButton = (nrNetworksAfterReconfigure < 4);
};

vm.canValidateBasicInfo = function() {
if (vm.isBasicInfoValid()) {
return true;
Expand Down Expand Up @@ -187,6 +196,22 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
vm.setEnableAddDiskButton();
};

vm.updateNetworkAdaptersAddRemove = function() {
vm.reconfigureModel.vmAddNetworkAdapters = [];
vm.reconfigureModel.vmRemoveNetworkAdapters = [];
angular.forEach(vm.reconfigureModel.vmNetworkAdapters, function(networkAdapter) {
if (networkAdapter.add_remove === 'add') {
vm.reconfigureModel.vmAddNetworkAdapters.push({network: networkAdapter.vlan});
}
if (networkAdapter.add_remove === 'remove') {
vm.reconfigureModel.vmRemoveNetworkAdapters.push({network: networkAdapter});
}
});
vm.setEnableAddNetworkAdapterButton();
vm.cb_networkAdapters = vm.reconfigureModel.vmAddNetworkAdapters.length > 0 ||
vm.reconfigureModel.vmRemoveNetworkAdapters.length > 0;
};

vm.resetAddValues = function() {
vm.reconfigureModel.hdType = 'thin';
vm.reconfigureModel.hdMode = 'persistent';
Expand All @@ -198,6 +223,52 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
vm.reconfigureModel.cb_bootable = false;
};

vm.processAddSelectedNetwork = function() {
vm.reconfigureModel.vmNetworkAdapters.push(
{
name: __('to be determined'),
vlan: vm.reconfigureModel.vLan_requested,
mac: __('not available yet'),
add_remove: 'add',
});
vm.resetAddNetworkAdapterValues();
vm.updateNetworkAdaptersAddRemove();
};

vm.removeExistingNetworkAdapter = function(thisNetworkAdapter) {
thisNetworkAdapter.add_remove = 'remove';
vm.updateNetworkAdaptersAddRemove();
};

vm.enableAddNetworkAdapter = function() {
vm.reconfigureModel.nicsEnabled = true;
vm.reconfigureModel.enableAddNetworkAdapterButton = false;
vm.reconfigureModel.showDropDownNetwork = true;
vm.reconfigureModel.vLan_requested = '';
};

vm.hideAddNetworkAdapter = function() {
vm.resetAddNetworkAdapterValues();
};

vm.resetAddNetworkAdapterValues = function() {
vm.reconfigureModel.nicsEnabled = false;
vm.reconfigureModel.addNetworkAdapterEnabled = false;
vm.reconfigureModel.showDropDownNetwork = false;
vm.setEnableAddNetworkAdapterButton();
vm.reconfigureModel.vLan_requested = '';
};

vm.cancelAddRemoveNetworkAdapter = function(vmNetworkAdapter) {
if (vmNetworkAdapter.add_remove === "remove") {
vmNetworkAdapter.add_remove = "";
} else if (vmNetworkAdapter.add_remove === "add") {
var index = vm.reconfigureModel.vmNetworkAdapters.indexOf(vmNetworkAdapter);
vm.reconfigureModel.vmNetworkAdapters.splice(index, 1);
}
vm.updateNetworkAdaptersAddRemove();
};

vm.addDisk = function() {
vm.reconfigureModel.vmdisks.push({
hdFilename: '',
Expand Down Expand Up @@ -289,6 +360,8 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
vmAddDisks: vm.reconfigureModel.vmAddDisks,
vmRemoveDisks: vm.reconfigureModel.vmRemoveDisks,
vmResizeDisks: vm.reconfigureModel.vmResizeDisks,
vmAddNetworkAdapters: vm.reconfigureModel.vmAddNetworkAdapters,
vmRemoveNetworkAdapters: vm.reconfigureModel.vmRemoveNetworkAdapters,
});
}
};
Expand Down Expand Up @@ -334,7 +407,10 @@ ManageIQ.angular.app.controller('reconfigureFormController', ['$http', '$scope',
vm.cb_memory = data.cb_memory;
vm.cb_cpu = data.cb_cpu;
vm.reconfigureModel.vmdisks = angular.copy(data.disks);
vm.reconfigureModel.vmNetworkAdapters = angular.copy(data.network_adapters);
vm.updateDisksAddRemove();
vm.updateNetworkAdaptersAddRemove();

angular.forEach(vm.reconfigureModel.vmdisks, function(disk) {
if (typeof disk !== 'undefined') {
disk.orgHdSize = disk.hdSize;
Expand Down
1 change: 1 addition & 0 deletions app/controllers/application_controller/ci_processing.rb
Expand Up @@ -15,6 +15,7 @@ module ApplicationController::CiProcessing
include Mixins::Actions::VmActions::Reconfigure
helper_method(:supports_reconfigure_disks?)
helper_method(:supports_reconfigure_disksize?)
helper_method(:supports_reconfigure_network_adapters?)
include Mixins::Actions::VmActions::PolicySimulation
include Mixins::Actions::VmActions::Transform

Expand Down
53 changes: 52 additions & 1 deletion app/controllers/mixins/actions/vm_actions/reconfigure.rb
Expand Up @@ -16,6 +16,12 @@ def reconfigure(reconfigure_ids = [])
@force_no_grid_xml = true
@view, @pages = get_view(Vm, :view_suffix => "VmReconfigureRequest", :selected_ids => reconfigure_ids) # Get the records (into a view) and the paginator
get_reconfig_limits(reconfigure_ids)

if @reconfigitems.size == 1
vm = Vm.find(@reconfigitems)
@vlan_options = get_vlan_options(vm.host_id)
end

unless @explorer
render :action => "show"
end
Expand Down Expand Up @@ -181,6 +187,21 @@ def reconfigure_calculations(mbsize)
return humansize.to_s, fmt
end

def get_vlan_options(host_id)
vlan_options = []

# determine available switches for this host...
switch_ids = []
Rbac.filtered(HostSwitch.where("host_id = ?", host_id)).each do |host_switch|
switch_ids << host_switch.switch_id
end

Rbac.filtered(Lan.where("switch_id IN (?)", switch_ids)).each do |lan|
vlan_options << lan.name
end
vlan_options
end

def get_reconfig_info(reconfigure_ids)
@reconfigureitems = Vm.find(reconfigure_ids).sort_by(&:name)
# set memory to nil if multiple items were selected with different mem_cpu values
Expand Down Expand Up @@ -208,12 +229,24 @@ def get_reconfig_info(reconfigure_ids)
:cb_bootable => disk.bootable}
end

# reconfiguring network adapters is only supported when one vm was selected
network_adapters = []
if @reconfigureitems.size == 1
vm = @reconfigureitems.first

vm.hardware.guest_devices.order(:device_name => 'asc').each do |guest_device|
lan = Lan.find_by(:id => guest_device.lan_id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rbac?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@himdel Is rbac necessary for lans that are already connected to the vm? Should the vm owner be blocked removing a non accessible lan from his vm?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're right, here it makes less sense, never mind :).

(But if you wanted to, it would be spelled find_record_with_rbac(Lan, guest_device.lan_id).)

network_adapters << {:name => guest_device.device_name, :vlan => lan.name, :mac => guest_device.address, :add_remove => ''} unless lan.nil?
end
end

{:objectIds => reconfigure_ids,
:memory => memory,
:memory_type => memory_type,
:socket_count => socket_count.to_s,
:cores_per_socket_count => cores_per_socket.to_s,
:disks => vmdisks}
:disks => vmdisks,
:network_adapters => network_adapters}
end

def supports_reconfigure_disks?
Expand All @@ -224,6 +257,10 @@ def supports_reconfigure_disksize?
@reconfigitems && @reconfigitems.size == 1 && @reconfigitems.first.supports_reconfigure_disksize? && @reconfigitems.first.supports_reconfigure_disks?
end

def supports_reconfigure_network_adapters?
@reconfigitems && @reconfigitems.size == 1 && @reconfigitems.first.supports_reconfigure_network_adapters?
end

private

# 'true' => true
Expand Down Expand Up @@ -288,6 +325,20 @@ def reconfigure_handle_submit_button
options[:disk_remove] = params[:vmRemoveDisks].values
end

if params[:vmAddNetworkAdapters]
params[:vmAddNetworkAdapters].each_value do |p|
p.transform_values! { |v| eval_if_bool_string(v) }
end
options[:network_adapter_add] = params[:vmAddNetworkAdapters].values
end

if params[:vmRemoveNetworkAdapters]
params[:vmRemoveNetworkAdapters].each_value do |p|
p.transform_values! { |v| eval_if_bool_string(v) }
end
options[:network_adapter_remove] = params[:vmRemoveNetworkAdapters].values
end

if params[:id] && params[:id] != 'new'
@request_id = params[:id]
end
Expand Down
14 changes: 14 additions & 0 deletions app/views/miq_request/_reconfigure_show.html.haml
Expand Up @@ -46,6 +46,20 @@
= _("Resize Disks")
.col-md-8
= h(@options[:disk_resize].size)
- if @options[:network_adapter_add]
.form-group
%label.control-label.col-md-2
= _("Add Network Adapters")
.col-md-8
= h(@options[:network_adapter_add].size)
&nbsp;
- if @options[:network_adapter_remove]
.form-group
%label.control-label.col-md-2
= _("Remove Network Adapters")
.col-md-8
= h(@options[:network_adapter_remove].size)
&nbsp;
- if @options[:instance_type]
.form-group
%label.control-label.col-md-2
Expand Down
66 changes: 65 additions & 1 deletion app/views/vm_common/_reconfigure.html.haml
Expand Up @@ -295,6 +295,70 @@
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-if" => "disk.add_remove == 'resize'",
"ng-click" => "vm.cancelAddRemoveDisk(disk)"}= _('Cancel Resize')
- if supports_reconfigure_network_adapters?
%hr
%div
%h3
= _('Network Adapters')
%table{:width => "100%", :align => "bottom"}
%tr
%td#buttons_on_nics{:align => "right"}
%button.btn.btn-primary{:type => "button",
"ng-click" => "vm.enableAddNetworkAdapter()",
:align => "left",
"ng-show" => "!vm.reconfigureModel.nicsEnabled",
"ng-disabled" => "!vm.reconfigureModel.enableAddNetworkAdapterButton"}= _('Add Network')
%button.btn.btn-default.btn-sm{:type => "button",
"ng-click" => "vm.hideAddNetworkAdapter()",
"ng-show" => "vm.reconfigureModel.nicsEnabled"}= _('Cancel Add')
%table.table.table-striped.table-condensed.table-bordered
%thead
%th= _('Name')
%th= _('vLan')
%th= _('MAC Address')
%th{:colspan => 2}= _('Actions')
%tr{"ng-repeat" => "networkAdapter in vm.reconfigureModel.vmNetworkAdapters",
"ng-class" => "{'danger': networkAdapter.add_remove == 'remove', 'active': networkAdapter.add_remove == 'add'}"}
%td
{{networkAdapter.name}}
%td
{{networkAdapter.vlan}}
%td.narrow
{{networkAdapter.mac}}
%td.action-cell
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
:style => "visibility:hidden"}= _('Intentionally left empty')
%td.action-cell
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-if" => "networkAdapter.add_remove == ''",
"ng-click" => "vm.removeExistingNetworkAdapter(networkAdapter)"}= _('Delete')
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-if" => "networkAdapter.add_remove == 'remove'",
"ng-disabled" => "!vm.reconfigureModel.enableAddNetworkAdapterButton",
"ng-click" => "vm.cancelAddRemoveNetworkAdapter(networkAdapter)"}= _('Cancel Delete')
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-if" => "networkAdapter.add_remove == 'add'",
"ng-click" => "vm.cancelAddRemoveNetworkAdapter(networkAdapter)"}= _('Cancel Add')
%tr{"ng-if" => "vm.reconfigureModel.showDropDownNetwork",
"ng-form" => "rowForm"}
%td
%td
= select_tag('vLan',
options_for_select([["<#{_('Choose')}>", '']] + @vlan_options, :disabled => ["<#{_('Choose')}>", nil]),
"ng-model" => "vm.reconfigureModel.vLan_requested",
"ng-change" => "",
"data-width" => "auto",
"required" => "",
"selectpicker-for-select-tag" => "")
%td
%td.action-cell
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-click" => "vm.processAddSelectedNetwork();rowForm.vLan.selectionpicker('refresh')",
"ng-disabled" => "rowForm.vLan.$invalid || !vm.reconfigureModel.vmNetworkAdapters.length >= 4"}= _('Confirm Add')
%td.action-cell
%button.btn.btn-default.btn-block.btn-sm{:type => "button",
"ng-click" => "vm.hideAddNetworkAdapter()"}= _('Cancel Add')

%hr

%table{:width => "100%", :align => "bottom"}
Expand All @@ -303,7 +367,7 @@
%miq-button{:name => t = _('Submit'),
:title => t,
:alt => t,
:enabled => "!((angularForm.$pristine && !vm.cb_disks) || angularForm.$invalid || (!vm.cb_memory && !vm.cb_cpu && !vm.cb_disks))",
:enabled => "!((angularForm.$pristine && !vm.cb_disks && !vm.cb_networkAdapters) || angularForm.$invalid || (!vm.cb_memory && !vm.cb_cpu && !vm.cb_disks && !vm.cb_networkAdapters))",
'on-click' => "vm.submitClicked()",
:primary => 'true'}
%miq-button{:name => t = _('Reset'),
Expand Down
Expand Up @@ -16,7 +16,8 @@ describe('reconfigureFormController', function() {
cb_cpu: 'on',
socket_count: '2',
cores_per_socket_count: '3',
disks: [{hdFilename: "test_disk.vmdk", hdType: "thick", hdMode: "persistent", new_controller_type: "VirtualLsiLogicController", hdSize: "0", hdUnit: "MB", add_remove: ""}]};
disks: [{hdFilename: "test_disk.vmdk", hdType: "thick", hdMode: "persistent", new_controller_type: "VirtualLsiLogicController", hdSize: "0", hdUnit: "MB", add_remove: ""}],
network_adapters: [{name: "Network adapter 1", vlan: "test_network", mac: "00:00:00:00:00:00", add_remove: ""}]};

$httpBackend = _$httpBackend_;
$httpBackend.whenGET('reconfigure_form_fields/1000000000003,1000000000001,1000000000002').respond(reconfigureFormResponse);
Expand Down Expand Up @@ -56,6 +57,9 @@ describe('reconfigureFormController', function() {
it('initializes the delete_backing flag to false if not retrived', function() {
expect(vm.reconfigureModel.vmdisks[0].delete_backing).toEqual(false);
});
it('sets the network adapter data to the network adapter data returned with the http request', function() {
expect(vm.reconfigureModel.vmNetworkAdapters).toEqual([{name: "Network adapter 1", vlan: "test_network", mac: "00:00:00:00:00:00", add_remove: ""}]);
});
});

describe('#cancelClicked', function() {
Expand Down Expand Up @@ -95,7 +99,8 @@ describe('reconfigureFormController', function() {
memory_type: vm.reconfigureModel.memory_type,
socket_count: vm.reconfigureModel.socket_count,
cores_per_socket_count: vm.reconfigureModel.cores_per_socket_count,
vmAddDisks: [ ], vmRemoveDisks: [ ], vmResizeDisks: [ ] };
vmAddDisks: [ ], vmRemoveDisks: [ ], vmResizeDisks: [ ],
vmAddNetworkAdapters: [ ], vmRemoveNetworkAdapters: [ ]};

expect(miqService.miqAjaxButton).toHaveBeenCalledWith('reconfigure_update/1000000000003?button=submit', submitContent);
});
Expand Down