// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. (function($, cloudStack) { //The drag and drop function to order ACL rules does not have access to the whole ACL. //Therefore, we store the "state-hash" of the list being displayed for use in the drag and drop function. var accessControlListConsistentyHashForDragAndDropFunction = ""; var isNumeric = function (n) { return !isNaN(parseFloat(n)); }; var createSafeCsvValue = function(value){ if(value){ return '"' + value + '"'; } return ""; }; var generateCsvForAclRules = function(aclRules){ var csv = createSafeCsvValue('id') + ','; for(var field in aclRuleFields){ var fieldLabel = aclRuleFields[field].label; var fieldLabelTranslated = _l(fieldLabel); csv = csv + createSafeCsvValue(fieldLabelTranslated) + ','; } csv = csv.substr(0, csv.length - 1) + '\n'; if(!aclRules){ return csv; } aclRules.forEach(function(entry){ csv = csv + createSafeCsvValue(entry.id) + ',' + createSafeCsvValue(entry.number) + ',' + createSafeCsvValue(entry.cidrlist) + ',' + createSafeCsvValue(entry.action) + ',' ; if(isNumeric(entry.protocol)){ csv = csv + createSafeCsvValue(_l('label.protocol.number')) + ',' + createSafeCsvValue(entry.protocol) + ','; }else{ csv = csv + createSafeCsvValue(entry.protocol) + ',' + createSafeCsvValue('') + ','; } csv = csv + createSafeCsvValue(entry.startport) + ',' + createSafeCsvValue(entry.endport) + ',' + createSafeCsvValue(entry.icmptype) + ',' + createSafeCsvValue(entry.icmpcode) + ',' + createSafeCsvValue(entry.traffictype) + ',' + createSafeCsvValue(entry.reason) + '\n'; }); return csv; }; var assignVMAction = function() { return { label: 'label.assign.vms', messages: { notification: function(args) { return 'label.assign.vms'; } }, needsRefresh: true, listView: $.extend(true, {}, cloudStack.sections.instances.listView, { type: 'checkbox', filters: false, multiSelect: false, subselect: { isMultiple: true, label: 'label.use.vm.ip', dataProvider: function(args) { var instance = args.context.instances[0]; var network = args.context.networks[0]; $.ajax({ url: createURL('listNics'), data: { virtualmachineid: instance.id, nicId: instance.nic[0].id }, success: function(json) { var nic = json.listnicsresponse.nic[0]; var primaryIp = nic.ipaddress; var secondaryIps = nic.secondaryip ? nic.secondaryip : []; var ipSelection = []; var existingIps = $(args.context.subItemData).map( function(index, item) { return item.itemIp; } ); // Add primary IP as default if ($.inArray(primaryIp, existingIps) == -1) { ipSelection.push({ id: primaryIp, description: primaryIp + ' (Primary)' }); } // Add secondary IPs $(secondaryIps).map(function(index, secondaryIp) { if ($.inArray(secondaryIp.ipaddress, existingIps) == -1) { ipSelection.push({ id: secondaryIp.ipaddress, description: secondaryIp.ipaddress }); } }); args.response.success({ data: ipSelection }); } }); } }, dataProvider: function(args) { var assignedInstances; $.ajax({ url: createURL('listLoadBalancers'), data: { id: args.context.internalLoadBalancers[0].id }, async: false, success: function(json) { assignedInstances = json.listloadbalancersresponse.loadbalancer[0].loadbalancerinstance; if (assignedInstances == null) assignedInstances = []; } }); $.ajax({ url: createURL('listVirtualMachines'), data: { networkid: args.context.networks[0].id, listAll: true }, success: function(json) { var instances = json.listvirtualmachinesresponse.virtualmachine; // Pre-select existing instances in LB rule $(instances).map(function(index, instance) { instance._isSelected = $.grep(assignedInstances, function(assignedInstance) { return assignedInstance.id == instance.id; } ).length ? true : false; }); //remove assigned VMs (i.e. instance._isSelected == true) var items = []; if (instances != null) { for (var i = 0; i < instances.length; i++) { if (instances[i]._isSelected == true) continue; else items.push(instances[i]); } } args.response.success({ data: items }); } }); } }), action: function(args) { /* * path 1: Network > VPC (list) > click "Configure" > pick an internal LB tier > click "Internal LB" (list) > click on a grid row (Details tab) > click "Assign VMs" tab > click Assign VMs" button on top of list * path 2: Network > VPC (list) > click "Configure" > pick an internal LB tier > click "Internal LB" (list) > "QuickView" on a grid row > click "Assign VMs" button in QuickView */ var $rows = $(':ui-dialog .list-view tbody tr'); var vms = args.context.instances; // Assign subselect values $(vms).each(function() { var vm = this; var $vmRow = $rows.filter(function() { return $(this).data('json-obj') === vm; }); $.extend(vm, { _subselect: $vmRow.find('.subselect select').val() }); }); var inputData = { id: args.context.internalLoadBalancers[0].id }; /* * e.g. first VM(xxx) has two IPs(10.1.1.~), second VM(yyy) has three IPs(10.2.2.~): * vmidipmap[0].vmid=xxx vmidipmap[0].vmip=10.1.1.11 * vmidipmap[1].vmid=xxx vmidipmap[1].vmip=10.1.1.12 * vmidipmap[2].vmid=yyy vmidipmap[2].vmip=10.2.2.77 * vmidipmap[3].vmid=yyy vmidipmap[3].vmip=10.2.2.78 * vmidipmap[4].vmid=yyy vmidipmap[4].vmip=10.2.2.79 */ var selectedVMs = vms; if (selectedVMs != null) { var vmidipmapIndex = 0; for (var vmIndex = 0; vmIndex < selectedVMs.length; vmIndex++) { var selectedIPs = selectedVMs[vmIndex]._subselect; for (var ipIndex = 0; ipIndex < selectedIPs.length; ipIndex++) { inputData['vmidipmap[' + vmidipmapIndex + '].vmid'] = selectedVMs[vmIndex].id; inputData['vmidipmap[' + vmidipmapIndex + '].vmip'] = selectedIPs[ipIndex]; vmidipmapIndex++; } } } $.ajax({ url: createURL('assignToLoadBalancerRule'), data: inputData, dataType: 'json', async: true, success: function(data) { var jid = data.assigntoloadbalancerruleresponse.jobid; args.response.success({ _custom: { jobId: jid } }); } }); }, notification: { poll: pollAsyncJobResult } }; }; var aclRuleFields = { 'number': { label: 'label.rule.number.short', desc: 'label.rule.number', edit: true, isEditable: true }, 'cidrlist': { edit: true, label: 'label.cidr', isEditable: true }, action: { label: 'label.action', isEditable: true, select: function(args) { args.response.success({ data: [{ name: 'Allow', description: 'Allow' }, { name: 'Deny', description: 'Deny' }] }); } }, 'protocol': { label: 'label.protocol', isEditable: true, select: function(args) { var isEditDialog = args.type === 'createForm'; args.$select.change(function() { var $inputs, $icmpFields, $otherFields, $portFields, $protocolFields, $protocolinput; // // Editing existing rules in createForm dialog // if (isEditDialog) { $inputs = args.$form.find('.form-item'); $icmpFields = $inputs.filter(function() { var name = $(this).attr('rel'); return $.inArray(name, [ 'icmptype', 'icmpcode' ]) > -1; }); $otherFields = $inputs.filter(function() { var name = $(this).attr('rel'); return name != 'protocolnumber' && name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist' && name != 'number'; }); $portFields = $inputs.filter(function() { var name = $(this).attr('rel'); return $.inArray(name, [ 'startport', 'endport' ]) > -1; }); $protocolFields = $inputs.filter(function() { var name = $(this).attr('rel'); return $.inArray(name, ['protocolnumber']) > -1; }); if ($(this).val() == 'protocolnumber') { $icmpFields.show(); $portFields.show(); $protocolFields.show(); $portFields.show(); } else if ($(this).val() == 'icmp') { $icmpFields.show(); $protocolFields.hide(); $portFields.hide(); } else if ($(this).val() == 'all') { $portFields.hide(); $portFields.attr('disabled', 'disabled'); $icmpFields.hide(); $icmpFields.attr('disabled', 'disabled'); $protocolFields.attr('disabled', 'disabled'); $protocolFields.hide(); } else { $otherFields.show(); $icmpFields.hide(); $protocolFields.hide(); } } else { // // Add new form // $inputs = args.$form.find('input'); $icmpFields = $inputs.filter(function() { var name = $(this).attr('name'); return $.inArray(name, [ 'icmptype', 'icmpcode' ]) > -1; }); $otherFields = $inputs.filter(function() { var name = $(this).attr('name'); return name != 'protocolnumber' && name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist' && name != 'number'; }); $portFields = $inputs.filter(function() { var name = $(this).attr('name'); return $.inArray(name, [ 'startport', 'endport' ]) > -1; }); $protocolinput = args.$form.find('td input'); $protocolFields = $protocolinput.filter(function() { var name = $(this).attr('name'); return $.inArray(name, ['protocolnumber']) > -1; }); if ($(this).val() == 'protocolnumber') { $icmpFields.show(); $otherFields.hide(); $protocolFields.show().addClass('required'); $inputs.filter('[name=startport],[name=endport]').show().attr('disabled', false); } else if ($(this).val() == 'icmp') { $icmpFields.show(); $icmpFields.attr('disabled', false); $protocolFields.hide().removeClass('required'); $otherFields.attr('disabled', 'disabled'); $otherFields.hide(); $otherFields.parent().find('label.error').hide(); } else if ($(this).val() == 'all') { $portFields.hide(); $portFields.attr('disabled', 'disabled'); $icmpFields.hide(); $icmpFields.attr('disabled', 'disabled'); $protocolFields.hide(); $protocolFields.attr('disabled', 'disabled'); } else { $otherFields.show(); $otherFields.parent().find('label.error').hide(); $otherFields.attr('disabled', false); $icmpFields.attr('disabled', 'disabled'); $icmpFields.hide(); $icmpFields.parent().find('label.error').hide(); $protocolFields.hide().removeClass('required'); } } }); args.response.success({ data: [{ name: 'tcp', description: 'TCP' }, { name: 'udp', description: 'UDP' }, { name: 'icmp', description: 'ICMP' }, { name: 'all', description: 'ALL' }, { name: 'protocolnumber', description: 'Protocol Number' } ] }); setTimeout(function() { args.$select.trigger('change'); }, 100); } }, 'protocolnumber': { label: 'label.protocol.number.short', desc: 'label.protocol.number', edit: true, isEditable: true }, 'startport': { edit: true, label: 'label.start.port', isOptional: true, isEditable: true }, 'endport': { edit: true, label: 'label.end.port', isOptional: true, isEditable: true }, 'icmptype': { edit: true, label: 'ICMP.type', desc: 'ICMP.type.desc', defaultValue: '-1', isEditable: true }, 'icmpcode': { edit: true, label: 'ICMP.code', desc: 'ICMP.code.desc', defaultValue: '-1', isEditable: true }, 'traffictype': { label: 'label.traffic.type', isEditable: true, select: function(args) { args.response.success({ data: [{ name: 'Ingress', description: 'Ingress' }, { name: 'Egress', description: 'Egress' }] }); } }, 'reason': { edit: true, label: 'label.acl.reason', desc: 'label.acl.reason.description', isEditable: true, isTextarea: true } }; var aclRuleFieldsForMultiEdit = { 'networkid': { label: 'label.select.tier', select: function(args) { var data = { listAll: true, vpcid: args.context.vpc[0].id }; // Only show selected tier, if viewing from detail view if (args.context.networks && args.context.networks[0] && args.context.networks[0].vpcid) { $.extend(data, { id: args.context.networks[0].id }); } // Ajax Call to display the Tiers $.ajax({ url: createURL('listNetworks'), data: data, success: function(json) { var networks = json.listnetworksresponse.network; args.response.success({ data: $(networks).map(function(index, network) { return { name: network.id, description: network.name }; }) }); } }); } }, }; jQuery.extend(aclRuleFieldsForMultiEdit, aclRuleFields); var aclMultiEdit = { doNotShowInputTable: true, editOptionsFirst: true, noSelect: true, reorder: { moveDrag: { action: function(args) { var rule = args.context.multiRule[0]; var previousRuleId = args.prevItem ? args.prevItem.id : undefined; var nextRuleId = args.nextItem ? args.nextItem.id : undefined; $.ajax({ url: createURL('moveNetworkAclItem'), data: { id: rule.id, previousaclruleid: previousRuleId, nextaclruleid: nextRuleId, aclconsistencyhash: accessControlListConsistentyHashForDragAndDropFunction }, success: function(json) { var pollTimer = setInterval(function() { pollAsyncJobResult({ _custom: { jobId: json.moveNetworkAclItemResponse.jobid }, complete: function() { clearInterval(pollTimer); args.response.success(); }, error: function(errorMsg) { clearInterval(pollTimer); args.response.error(errorMsg); } }); }, 1000); } }); } } }, fields: aclRuleFieldsForMultiEdit, tags: cloudStack.api.tags({ resourceType: 'NetworkACL', contextId: 'multiRule' }), add: { label: 'label.add', action: function(args) { var $multi = args.$multi; //Support for Protocol Number between 0 to 255 if (args.data.protocol === 'protocolnumber') { $.extend(args.data, { protocol: args.data.protocolnumber }); delete args.data.protocolnumber; delete args.data.icmptype; delete args.data.icmpcode; } else { delete args.data.protocolnumber; } if ((args.data.protocol == 'tcp' || args.data.protocol == 'udp') && (args.data.startport == "" || args.data.startport == undefined)) { cloudStack.dialog.notice({ message: _l('Start Port or End Port value should not be blank') }); $(window).trigger('cloudStack.fullRefresh'); } else if ((args.data.protocol == 'tcp' || args.data.protocol == 'udp') && (args.data.endport == "" || args.data.endport == undefined)) { cloudStack.dialog.notice({ message: _l('Start Port or End Port value should not be blank') }); $(window).trigger('cloudStack.fullRefresh'); } else { $.ajax({ url: createURL('createNetworkACL'), data: $.extend(args.data, { aclid: args.context.aclLists[0].id }), dataType: 'json', success: function(data) { args.response.success({ _custom: { jobId: data.createnetworkaclresponse.jobid, getUpdatedItem: function(json) { $(window).trigger('cloudStack.fullRefresh'); return data; } }, notification: { label: 'label.add.ACL', poll: pollAsyncJobResult } }); }, error: function(data) { args.response.error(parseXMLHttpResponse(data)); } }); } } }, actions: { edit: { label: 'label.edit', action: function(args) { var data = { id: args.context.multiRule[0].id, cidrlist: args.data.cidrlist, number: args.data.number, protocol: args.data.protocol, traffictype: args.data.traffictype, action: args.data.action, reason: args.data.reason }; if (data.protocol === 'tcp' || data.protocol === 'udp') { $.extend(data, { startport: args.data.startport, endport: args.data.endport }); } else if (data.protocol === 'icmp') { $.extend(data, { icmptype: args.data.icmptype, icmpcode: args.data.icmpcode }); } else if (data.protocol === 'protocolnumber') { $.extend(data, { protocol: args.data.protocolnumber, startport: args.data.startport, endport: args.data.endport }); delete args.data.protocolnumber; } data.partialupgrade = false; $.ajax({ url: createURL('updateNetworkACLItem'), data: data, type: "POST", success: function(json) { args.response.success({ _custom: { jobId: json.createnetworkaclresponse.jobid }, // API response obj name needs to be fixed notification: { label: 'label.edit.acl.rule', poll: pollAsyncJobResult } }); }, error: function(error) { args.response.error(parseXMLHttpResponse(error)); } }); } }, destroy: { label: 'label.remove.ACL', action: function(args) { $.ajax({ url: createURL('deleteNetworkACL'), data: { id: args.context.multiRule[0].id }, dataType: 'json', async: true, success: function(data) { var jobID = data.deletenetworkaclresponse.jobid; args.response.success({ _custom: { jobId: jobID, getUpdatedItem: function() { $(window).trigger('cloudStack.fullRefresh'); } }, notification: { label: 'label.remove.ACL', poll: pollAsyncJobResult } }); }, error: function(data) { args.response.error(parseXMLHttpResponse(data)); } }); } } }, dataProvider: function(args) { var $multi = args.$multi; var data = { vpcid: args.context.vpc[0].id, listAll: true }; if (!$multi.data('acl-rules')) { $multi.data('acl-rules', []); } if (args.context.networks && args.context.networks[0] && args.context.networks[0].vpcid) { data.networkid = args.context.networks[0].id; $.ajax({ url: createURL('listNetworkACLs'), data: data, dataType: 'json', async: true, success: function(json) { args.response.success({ data: $(json.listnetworkaclsresponse.networkacl).map(function(index, acl) { return $.extend(acl, { networkid: args.context.networks[0].name }); }) }); }, error: function(XMLHttpResponse) { args.response.error(parseXMLHttpResponse(XMLHttpResponse)); } }); } else { args.response.success({ data: $multi.data('acl-rules') }); } } }; cloudStack.vpc = { // nTier sections sections: { tierVMs: function() { var list = $.extend(true, {}, cloudStack.sections.instances); list.listView.actions.add.action.custom = cloudStack.uiCustom.instanceWizard( $.extend(true, {}, cloudStack.instanceWizard, { pluginForm: { name: 'vpcTierInstanceWizard' } }) ); return list; }, tierPortForwarders: function() { return cloudStack.vpc.ipAddresses.listView(); }, tierStaticNATs: function() { return cloudStack.vpc.staticNatIpAddresses.listView(); }, // Internal load balancers internalLoadBalancers: { title: 'label.internal.lb', listView: { id: 'internalLoadBalancers', fields: { name: { label: 'label.name' }, sourceipaddress: { label: 'label.source.ip.address' }, sourceport: { label: 'label.source.port' }, instanceport: { label: 'label.instance.port' }, algorithm: { label: 'label.algorithm' } }, dataProvider: function(args) { var data = { page: args.page, pageSize: pageSize, networkid: args.context.networks[0].id, listAll: true }; var keyword = (((args || {}).filterBy || {}).search || {}).value; if (keyword) { data.keyword = keyword; } $.ajax({ url: createURL('listLoadBalancers'), data: data, success: function(json) { var items = json.listloadbalancersresponse.loadbalancer; if (items != null) { for (var i = 0; i < items.length; i++) { var item = items[i]; //there is only one element in loadbalancerrul array property. item.sourceport = item.loadbalancerrule[0].sourceport; item.instanceport = item.loadbalancerrule[0].instanceport; } } args.response.success({ data: items }); } }); }, actions: { add: { label: 'label.add.internal.lb', createForm: { title: 'label.add.internal.lb', fields: { name: { label: 'label.name', validation: { required: true } }, description: { label: 'label.description', validation: { required: false } }, sourceipaddress: { label: 'label.source.ip.address', validation: { required: false } }, sourceport: { label: 'label.source.port', validation: { required: true } }, instanceport: { label: 'label.instance.port', validation: { required: true } }, algorithm: { label: 'label.algorithm', validation: { required: true }, select: function(args) { args.response.success({ data: [{ id: 'source', description: _l('label.lb.algorithm.source') }, { id: 'roundrobin', description: _l('label.lb.algorithm.roundrobin') }, { id: 'leastconn', description: _l('label.lb.algorithm.leastconn') }] }); } } } }, messages: { notification: function(args) { return 'label.add.internal.lb'; } }, action: function(args) { var data = { name: args.data.name, sourceport: args.data.sourceport, instanceport: args.data.instanceport, algorithm: args.data.algorithm, networkid: args.context.networks[0].id, sourceipaddressnetworkid: args.context.networks[0].id, scheme: 'Internal' }; if (args.data.description != null && args.data.description.length > 0) { $.extend(data, { description: args.data.description }); } if (args.data.sourceipaddress != null && args.data.sourceipaddress.length > 0) { $.extend(data, { sourceipaddress: args.data.sourceipaddress }); } $.ajax({ url: createURL('createLoadBalancer'), data: data, success: function(json) { var jid = json.createloadbalancerresponse.jobid; args.response.success({ _custom: { jobId: jid, getUpdatedItem: function(json) { return json.queryasyncjobresultresponse.jobresult.loadbalancer; } } }); } }); }, notification: { poll: pollAsyncJobResult } } }, detailView: { isMaximized: true, name: 'label.internal.lb.details', actions: { assignVMs: assignVMAction(), remove: { label: 'label.delete.internal.lb', messages: { confirm: function(args) { return 'message.confirm.delete.internal.lb'; }, notification: function(args) { return 'label.delete.internal.lb'; } }, action: function(args) { var data = { id: args.context.internalLoadBalancers[0].id }; $.ajax({ url: createURL('deleteLoadBalancer'), data: data, async: true, success: function(json) { var jid = json.deleteloadbalancerresponse.jobid; args.response.success({ _custom: { jobId: jid } }); }, error: function(data) { args.response.error(parseXMLHttpResponse(data)); } }); }, notification: { poll: pollAsyncJobResult } } }, tabs: { details: { title: 'label.details', fields: [{ name: { label: 'label.name' } }, { id: { label: 'label.id' }, description: { label: 'label.description' }, sourceipaddress: { label: 'label.source.ip.address' }, sourceport: { label: 'label.source.port' }, instanceport: { label: 'label.instance.port' }, algorithm: { label: 'label.algorithm' }, loadbalancerinstance: { label: 'label.assigned.vms', converter: function(objArray) { var s = ''; if (objArray != null) { for (var i = 0; i < objArray.length; i++) { if (i > 0) { s += ', '; } s += objArray[i].name + ' (' + objArray[i].ipaddress + ')'; } } return s; } } }], dataProvider: function(args) { $.ajax({ url: createURL('listLoadBalancers'), data: { id: args.context.internalLoadBalancers[0].id }, success: function(json) { var item = json.listloadbalancersresponse.loadbalancer[0]; //remove Rules tab and add sourceport, instanceport at Details tab because there is only one element in loadbalancerrul array property. item.sourceport = item.loadbalancerrule[0].sourceport; item.instanceport = item.loadbalancerrule[0].instanceport; args.response.success({ data: item }); } }); } }, assignedVms: { title: 'label.assigned.vms', listView: { id: 'assignedVms', fields: { name: { label: 'label.name' }, ipaddress: { label: 'label.ip.address' } }, dataProvider: function(args) { $.ajax({ url: createURL('listLoadBalancers'), data: { id: args.context.internalLoadBalancers[0].id }, success: function(json) { var item = json.listloadbalancersresponse.loadbalancer[0]; args.response.success({ data: item.loadbalancerinstance }); } }); }, actions: { add: assignVMAction() }, detailView: { actions: { remove: { label: 'label.remove.vm.load.balancer', addRow: 'false', messages: { confirm: function(args) { return 'message.confirm.remove.load.balancer'; }, notification: function(args) { return 'label.remove.vm.load.balancer'; } }, action: function(args) { $.ajax({ url: createURL('removeFromLoadBalancerRule'), data: { id: args.context.internalLoadBalancers[0].id, virtualmachineids: args.context.assignedVms[0].id }, success: function(json) { var jid = json.removefromloadbalancerruleresponse.jobid; args.response.success({ _custom: { jobId: jid } }); } }); }, notification: { poll: pollAsyncJobResult } } }, tabs: { details: { title: 'label.details', fields: [{ name: { label: 'label.name' } }, { ipaddress: { label: 'label.ip.address' } }], dataProvider: function(args) { setTimeout(function() { args.response.success({ data: args.context.assignedVms[0] }); }); } } } } } } } } } }, publicLbIps: { title: 'label.public.ip', listView: { id: 'publicLbIps', fields: { ipaddress: { label: 'label.ips', converter: function(text, item) { if (item.issourcenat) { return text + ' [' + _l('label.source.nat') + ']'; } return text; } }, zonename: { label: 'label.zone' }, virtualmachinedisplayname: { label: 'label.vm.name' }, state: { converter: function(str) { // For localization return str; }, label: 'label.state', indicator: { 'Allocated': 'on', 'Released': 'off' } } }, dataProvider: function(args) { $.ajax({ url: createURL('listPublicIpAddresses'), async: false, data: { associatednetworkid: args.context.networks[0].id, forloadbalancing: true, listall: true }, success: function(json) { var items = json.listpublicipaddressesresponse.publicipaddress; args.response.success({ data: items }); } }); } } }, // Private gateways privateGateways: function() { return cloudStack.vpc.gateways.listView() }, // Public IP Addresses publicIPs: function() { return cloudStack.vpc.ipAddresses.listView() }, // Network ACL lists networkACLLists: { listView: { id: 'aclLists', fields: { name: { label: 'label.name' }, description: { label: 'label.description' }, id: { label: 'label.id' } }, dataProvider: function(args) { var data = { vpcid: args.context.vpc[0].id }; listViewDataProvider(args, data); $.ajax({ url: createURL('listNetworkACLLists'), data: data, success: function(json) { var items = json.listnetworkacllistsresponse.networkacllist; args.response.success({ data: items }); } }); }, actions: { add: { label: 'label.add.acl.list', createForm: { label: 'label.add.acl.list', fields: { name: { label: 'label.add.list.name', validation: { required: true } }, description: { label: 'label.description', validation: { required: true } } } }, messages: { notification: function(args) { return 'label.add.network.acl.list'; } }, action: function(args) { var data = { name: args.data.name, description: args.data.description }; $.ajax({ url: createURL('createNetworkACLList&vpcid=' + args.context.vpc[0].id), data: data, success: function(json) { args.response.success({ _custom: { jobId: json.createnetworkacllistresponse.jobid, getUpdatedItem: function(json) { return json.queryasyncjobresultresponse.jobresult.networkacllist; } } }); } }); }, notification: { poll: pollAsyncJobResult } } }, detailView: { isMaximized: true, actions: { remove: { label: 'label.delete.acl.list', messages: { confirm: function(args) { return 'message.confirm.delete.acl.list'; }, notification: function(args) { return 'label.delete.acl.list'; } }, action: function(args) { $.ajax({ url: createURL('deleteNetworkACLList&id=' + args.context.aclLists[0].id), success: function(json) { var jid = json.deletenetworkacllistresponse.jobid; args.response.success({ _custom: { jobId: jid, getUpdatedItem: function() { $(window).trigger('cloudStack.fullRefresh'); } } }); }, error: function(json) { args.response.error(parseXMLHttpResponse(json)); } }); }, notification: { poll: pollAsyncJobResult } }, edit: { label: 'label.edit.acl.list', action: function(args) { var data = args.data; data.id = args.context.aclLists[0].id; $.ajax({ url: createURL('updateNetworkACLList'), type: "POST", data: data, success: function(json) { var jid = json.updatenetworkacllistresponse.jobid; args.response.success({ _custom: { jobId: jid, getUpdatedItem: function() { $(window).trigger('cloudStack.fullRefresh'); jQuery('div[id=breadcrumbs] ul:visible li span').last().html(data.name); } } }); }, error: function(json) { args.response.error(parseXMLHttpResponse(json)); } }); }, notification: { poll: pollAsyncJobResult, desc: 'label.edit.acl.list' } } }, tabs: { details: { title: 'label.details', fields: [{ name: { label: 'label.name', isEditable: true }, description: { label: 'label.description', isEditable: true }, id: { label: 'label.id' } }], dataProvider: function(args) { var items = args.context.aclLists[0]; setTimeout(function() { args.response.success({ data: items, actionFilter: function(args) { var allowedActions = []; if (items.vpcid != null) { allowedActions.push("remove"); allowedActions.push("edit"); } return allowedActions; } }); }); } }, aclRules: { title: 'label.acl.list.rules', custom: function(args) { return $('